]> git.lizzy.rs Git - rust.git/blob - src/librustc_data_structures/flock.rs
Rollup merge of #39039 - michaelwoerister:ignore-gdb-version, r=nrc
[rust.git] / src / librustc_data_structures / flock.rs
1 // Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! Simple file-locking apis for each OS.
12 //!
13 //! This is not meant to be in the standard library, it does nothing with
14 //! green/native threading. This is just a bare-bones enough solution for
15 //! librustdoc, it is not production quality at all.
16
17 #![allow(non_camel_case_types)]
18 use std::path::Path;
19
20 pub use self::imp::Lock;
21
22 #[cfg(unix)]
23 mod imp {
24     use std::ffi::{CString, OsStr};
25     use std::os::unix::prelude::*;
26     use std::path::Path;
27     use std::io;
28     use libc;
29
30     #[cfg(target_os = "linux")]
31     mod os {
32         use libc;
33
34         #[repr(C)]
35         pub struct flock {
36             pub l_type: libc::c_short,
37             pub l_whence: libc::c_short,
38             pub l_start: libc::off_t,
39             pub l_len: libc::off_t,
40             pub l_pid: libc::pid_t,
41
42             // not actually here, but brings in line with freebsd
43             pub l_sysid: libc::c_int,
44         }
45
46         pub const F_RDLCK: libc::c_short = 0;
47         pub const F_WRLCK: libc::c_short = 1;
48         pub const F_UNLCK: libc::c_short = 2;
49         pub const F_SETLK: libc::c_int = 6;
50         pub const F_SETLKW: libc::c_int = 7;
51     }
52
53     #[cfg(target_os = "freebsd")]
54     mod os {
55         use libc;
56
57         #[repr(C)]
58         pub struct flock {
59             pub l_start: libc::off_t,
60             pub l_len: libc::off_t,
61             pub l_pid: libc::pid_t,
62             pub l_type: libc::c_short,
63             pub l_whence: libc::c_short,
64             pub l_sysid: libc::c_int,
65         }
66
67         pub const F_RDLCK: libc::c_short = 1;
68         pub const F_UNLCK: libc::c_short = 2;
69         pub const F_WRLCK: libc::c_short = 3;
70         pub const F_SETLK: libc::c_int = 12;
71         pub const F_SETLKW: libc::c_int = 13;
72     }
73
74     #[cfg(any(target_os = "dragonfly",
75               target_os = "bitrig",
76               target_os = "netbsd",
77               target_os = "openbsd"))]
78     mod os {
79         use libc;
80
81         #[repr(C)]
82         pub struct flock {
83             pub l_start: libc::off_t,
84             pub l_len: libc::off_t,
85             pub l_pid: libc::pid_t,
86             pub l_type: libc::c_short,
87             pub l_whence: libc::c_short,
88
89             // not actually here, but brings in line with freebsd
90             pub l_sysid: libc::c_int,
91         }
92
93         pub const F_RDLCK: libc::c_short = 1;
94         pub const F_UNLCK: libc::c_short = 2;
95         pub const F_WRLCK: libc::c_short = 3;
96         pub const F_SETLK: libc::c_int = 8;
97         pub const F_SETLKW: libc::c_int = 9;
98     }
99
100     #[cfg(target_os = "haiku")]
101     mod os {
102         use libc;
103
104         #[repr(C)]
105         pub struct flock {
106             pub l_type: libc::c_short,
107             pub l_whence: libc::c_short,
108             pub l_start: libc::off_t,
109             pub l_len: libc::off_t,
110             pub l_pid: libc::pid_t,
111
112             // not actually here, but brings in line with freebsd
113             pub l_sysid: libc::c_int,
114         }
115
116         pub const F_UNLCK: libc::c_short = 0x0200;
117         pub const F_WRLCK: libc::c_short = 0x0400;
118         pub const F_SETLK: libc::c_int = 0x0080;
119         pub const F_SETLKW: libc::c_int = 0x0100;
120     }
121
122     #[cfg(any(target_os = "macos", target_os = "ios"))]
123     mod os {
124         use libc;
125
126         #[repr(C)]
127         pub struct flock {
128             pub l_start: libc::off_t,
129             pub l_len: libc::off_t,
130             pub l_pid: libc::pid_t,
131             pub l_type: libc::c_short,
132             pub l_whence: libc::c_short,
133
134             // not actually here, but brings in line with freebsd
135             pub l_sysid: libc::c_int,
136         }
137
138         pub const F_RDLCK: libc::c_short = 1;
139         pub const F_UNLCK: libc::c_short = 2;
140         pub const F_WRLCK: libc::c_short = 3;
141         pub const F_SETLK: libc::c_int = 8;
142         pub const F_SETLKW: libc::c_int = 9;
143     }
144
145     #[cfg(target_os = "solaris")]
146     mod os {
147         use libc;
148
149         #[repr(C)]
150         pub struct flock {
151             pub l_type: libc::c_short,
152             pub l_whence: libc::c_short,
153             pub l_start: libc::off_t,
154             pub l_len: libc::off_t,
155             pub l_sysid: libc::c_int,
156             pub l_pid: libc::pid_t,
157         }
158
159         pub const F_RDLCK: libc::c_short = 1;
160         pub const F_WRLCK: libc::c_short = 2;
161         pub const F_UNLCK: libc::c_short = 3;
162         pub const F_SETLK: libc::c_int = 6;
163         pub const F_SETLKW: libc::c_int = 7;
164     }
165
166     #[derive(Debug)]
167     pub struct Lock {
168         fd: libc::c_int,
169     }
170
171     impl Lock {
172         pub fn new(p: &Path,
173                    wait: bool,
174                    create: bool,
175                    exclusive: bool)
176                    -> io::Result<Lock> {
177             let os: &OsStr = p.as_ref();
178             let buf = CString::new(os.as_bytes()).unwrap();
179             let open_flags = if create {
180                 libc::O_RDWR | libc::O_CREAT
181             } else {
182                 libc::O_RDWR
183             };
184
185             let fd = unsafe {
186                 libc::open(buf.as_ptr(), open_flags,
187                            libc::S_IRWXU as libc::c_int)
188             };
189
190             if fd < 0 {
191                 return Err(io::Error::last_os_error());
192             }
193
194             let lock_type = if exclusive {
195                 os::F_WRLCK
196             } else {
197                 os::F_RDLCK
198             };
199
200             let flock = os::flock {
201                 l_start: 0,
202                 l_len: 0,
203                 l_pid: 0,
204                 l_whence: libc::SEEK_SET as libc::c_short,
205                 l_type: lock_type,
206                 l_sysid: 0,
207             };
208             let cmd = if wait { os::F_SETLKW } else { os::F_SETLK };
209             let ret = unsafe {
210                 libc::fcntl(fd, cmd, &flock)
211             };
212             if ret == -1 {
213                 let err = io::Error::last_os_error();
214                 unsafe { libc::close(fd); }
215                 Err(err)
216             } else {
217                 Ok(Lock { fd: fd })
218             }
219         }
220     }
221
222     impl Drop for Lock {
223         fn drop(&mut self) {
224             let flock = os::flock {
225                 l_start: 0,
226                 l_len: 0,
227                 l_pid: 0,
228                 l_whence: libc::SEEK_SET as libc::c_short,
229                 l_type: os::F_UNLCK,
230                 l_sysid: 0,
231             };
232             unsafe {
233                 libc::fcntl(self.fd, os::F_SETLK, &flock);
234                 libc::close(self.fd);
235             }
236         }
237     }
238 }
239
240 #[cfg(windows)]
241 #[allow(bad_style)]
242 mod imp {
243     use std::io;
244     use std::mem;
245     use std::os::windows::prelude::*;
246     use std::os::windows::raw::HANDLE;
247     use std::path::Path;
248     use std::fs::{File, OpenOptions};
249     use std::os::raw::{c_ulong, c_ulonglong, c_int};
250
251     type DWORD = c_ulong;
252     type BOOL = c_int;
253     type ULONG_PTR = c_ulonglong;
254
255     type LPOVERLAPPED = *mut OVERLAPPED;
256     const LOCKFILE_EXCLUSIVE_LOCK: DWORD = 0x00000002;
257     const LOCKFILE_FAIL_IMMEDIATELY: DWORD = 0x00000001;
258
259     const FILE_SHARE_DELETE: DWORD = 0x4;
260     const FILE_SHARE_READ: DWORD = 0x1;
261     const FILE_SHARE_WRITE: DWORD = 0x2;
262
263     #[repr(C)]
264     struct OVERLAPPED {
265         Internal: ULONG_PTR,
266         InternalHigh: ULONG_PTR,
267         Offset: DWORD,
268         OffsetHigh: DWORD,
269         hEvent: HANDLE,
270     }
271
272     extern "system" {
273         fn LockFileEx(hFile: HANDLE,
274                       dwFlags: DWORD,
275                       dwReserved: DWORD,
276                       nNumberOfBytesToLockLow: DWORD,
277                       nNumberOfBytesToLockHigh: DWORD,
278                       lpOverlapped: LPOVERLAPPED) -> BOOL;
279     }
280
281     #[derive(Debug)]
282     pub struct Lock {
283         _file: File,
284     }
285
286     impl Lock {
287         pub fn new(p: &Path,
288                    wait: bool,
289                    create: bool,
290                    exclusive: bool)
291                    -> io::Result<Lock> {
292             assert!(p.parent().unwrap().exists(),
293                 "Parent directory of lock-file must exist: {}",
294                 p.display());
295
296             let share_mode = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE;
297
298             let mut open_options = OpenOptions::new();
299             open_options.read(true)
300                         .share_mode(share_mode);
301
302             if create {
303                 open_options.create(true)
304                             .write(true);
305             }
306
307             debug!("Attempting to open lock file `{}`", p.display());
308             let file = match open_options.open(p) {
309                 Ok(file) => {
310                     debug!("Lock file opened successfully");
311                     file
312                 }
313                 Err(err) => {
314                     debug!("Error opening lock file: {}", err);
315                     return Err(err)
316                 }
317             };
318
319             let ret = unsafe {
320                 let mut overlapped: OVERLAPPED = mem::zeroed();
321
322                 let mut dwFlags = 0;
323                 if !wait {
324                     dwFlags |= LOCKFILE_FAIL_IMMEDIATELY;
325                 }
326
327                 if exclusive {
328                     dwFlags |= LOCKFILE_EXCLUSIVE_LOCK;
329                 }
330
331                 debug!("Attempting to acquire lock on lock file `{}`",
332                        p.display());
333                 LockFileEx(file.as_raw_handle(),
334                            dwFlags,
335                            0,
336                            0xFFFF_FFFF,
337                            0xFFFF_FFFF,
338                            &mut overlapped)
339             };
340             if ret == 0 {
341                 let err = io::Error::last_os_error();
342                 debug!("Failed acquiring file lock: {}", err);
343                 Err(err)
344             } else {
345                 debug!("Successfully acquired lock.");
346                 Ok(Lock { _file: file })
347             }
348         }
349     }
350
351     // Note that we don't need a Drop impl on the Windows: The file is unlocked
352     // automatically when it's closed.
353 }
354
355 impl imp::Lock {
356     pub fn panicking_new(p: &Path,
357                          wait: bool,
358                          create: bool,
359                          exclusive: bool)
360                          -> Lock {
361         Lock::new(p, wait, create, exclusive).unwrap_or_else(|err| {
362             panic!("could not lock `{}`: {}", p.display(), err);
363         })
364     }
365 }