]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/flock.rs
Rollup merge of #31295 - steveklabnik:gh31266, r=alexcrichton
[rust.git] / src / librustdoc / 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
19 pub use self::imp::Lock;
20
21 #[cfg(unix)]
22 mod imp {
23     use std::ffi::{CString, OsStr};
24     use std::os::unix::prelude::*;
25     use std::path::Path;
26     use std::io;
27     use libc;
28
29     #[cfg(target_os = "linux")]
30     mod os {
31         use libc;
32
33         pub struct flock {
34             pub l_type: libc::c_short,
35             pub l_whence: libc::c_short,
36             pub l_start: libc::off_t,
37             pub l_len: libc::off_t,
38             pub l_pid: libc::pid_t,
39
40             // not actually here, but brings in line with freebsd
41             pub l_sysid: libc::c_int,
42         }
43
44         pub const F_WRLCK: libc::c_short = 1;
45         pub const F_UNLCK: libc::c_short = 2;
46         pub const F_SETLK: libc::c_int = 6;
47         pub const F_SETLKW: libc::c_int = 7;
48     }
49
50     #[cfg(target_os = "freebsd")]
51     mod os {
52         use libc;
53
54         pub struct flock {
55             pub l_start: libc::off_t,
56             pub l_len: libc::off_t,
57             pub l_pid: libc::pid_t,
58             pub l_type: libc::c_short,
59             pub l_whence: libc::c_short,
60             pub l_sysid: libc::c_int,
61         }
62
63         pub const F_UNLCK: libc::c_short = 2;
64         pub const F_WRLCK: libc::c_short = 3;
65         pub const F_SETLK: libc::c_int = 12;
66         pub const F_SETLKW: libc::c_int = 13;
67     }
68
69     #[cfg(any(target_os = "dragonfly",
70               target_os = "bitrig",
71               target_os = "netbsd",
72               target_os = "openbsd"))]
73     mod os {
74         use libc;
75
76         pub struct flock {
77             pub l_start: libc::off_t,
78             pub l_len: libc::off_t,
79             pub l_pid: libc::pid_t,
80             pub l_type: libc::c_short,
81             pub l_whence: libc::c_short,
82
83             // not actually here, but brings in line with freebsd
84             pub l_sysid: libc::c_int,
85         }
86
87         pub const F_UNLCK: libc::c_short = 2;
88         pub const F_WRLCK: libc::c_short = 3;
89         pub const F_SETLK: libc::c_int = 8;
90         pub const F_SETLKW: libc::c_int = 9;
91     }
92
93     #[cfg(any(target_os = "macos", target_os = "ios"))]
94     mod os {
95         use libc;
96
97         pub struct flock {
98             pub l_start: libc::off_t,
99             pub l_len: libc::off_t,
100             pub l_pid: libc::pid_t,
101             pub l_type: libc::c_short,
102             pub l_whence: libc::c_short,
103
104             // not actually here, but brings in line with freebsd
105             pub l_sysid: libc::c_int,
106         }
107
108         pub const F_UNLCK: libc::c_short = 2;
109         pub const F_WRLCK: libc::c_short = 3;
110         pub const F_SETLK: libc::c_int = 8;
111         pub const F_SETLKW: libc::c_int = 9;
112     }
113
114     pub struct Lock {
115         fd: libc::c_int,
116     }
117
118     impl Lock {
119         pub fn new(p: &Path) -> Lock {
120             let os: &OsStr = p.as_ref();
121             let buf = CString::new(os.as_bytes()).unwrap();
122             let fd = unsafe {
123                 libc::open(buf.as_ptr(), libc::O_RDWR | libc::O_CREAT,
124                            libc::S_IRWXU as libc::c_int)
125             };
126             assert!(fd > 0, "failed to open lockfile: {}",
127                     io::Error::last_os_error());
128             let flock = os::flock {
129                 l_start: 0,
130                 l_len: 0,
131                 l_pid: 0,
132                 l_whence: libc::SEEK_SET as libc::c_short,
133                 l_type: os::F_WRLCK,
134                 l_sysid: 0,
135             };
136             let ret = unsafe {
137                 libc::fcntl(fd, os::F_SETLKW, &flock)
138             };
139             if ret == -1 {
140                 let err = io::Error::last_os_error();
141                 unsafe { libc::close(fd); }
142                 panic!("could not lock `{}`: {}", p.display(), err);
143             }
144             Lock { fd: fd }
145         }
146     }
147
148     impl Drop for Lock {
149         fn drop(&mut self) {
150             let flock = os::flock {
151                 l_start: 0,
152                 l_len: 0,
153                 l_pid: 0,
154                 l_whence: libc::SEEK_SET as libc::c_short,
155                 l_type: os::F_UNLCK,
156                 l_sysid: 0,
157             };
158             unsafe {
159                 libc::fcntl(self.fd, os::F_SETLK, &flock);
160                 libc::close(self.fd);
161             }
162         }
163     }
164 }
165
166 #[cfg(windows)]
167 #[allow(bad_style)]
168 mod imp {
169     use std::io;
170     use std::mem;
171     use std::os::windows::prelude::*;
172     use std::os::windows::raw::HANDLE;
173     use std::path::Path;
174     use std::fs::{File, OpenOptions};
175
176     type DWORD = u32;
177     type LPOVERLAPPED = *mut OVERLAPPED;
178     type BOOL = i32;
179     const LOCKFILE_EXCLUSIVE_LOCK: DWORD = 0x00000002;
180
181     #[repr(C)]
182     struct OVERLAPPED {
183         Internal: usize,
184         InternalHigh: usize,
185         Pointer: *mut u8,
186         hEvent: *mut u8,
187     }
188
189     extern "system" {
190         fn LockFileEx(hFile: HANDLE,
191                       dwFlags: DWORD,
192                       dwReserved: DWORD,
193                       nNumberOfBytesToLockLow: DWORD,
194                       nNumberOfBytesToLockHigh: DWORD,
195                       lpOverlapped: LPOVERLAPPED) -> BOOL;
196     }
197
198     pub struct Lock {
199         _file: File,
200     }
201
202     impl Lock {
203         pub fn new(p: &Path) -> Lock {
204             let f = OpenOptions::new().read(true).write(true).create(true)
205                                       .open(p).unwrap();
206             let ret = unsafe {
207                 let mut overlapped: OVERLAPPED = mem::zeroed();
208                 LockFileEx(f.as_raw_handle(), LOCKFILE_EXCLUSIVE_LOCK, 0, 100, 0,
209                            &mut overlapped)
210             };
211             if ret == 0 {
212                 let err = io::Error::last_os_error();
213                 panic!("could not lock `{}`: {}", p.display(), err);
214             }
215             Lock { _file: f }
216         }
217     }
218 }