]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/flock.rs
Auto merge of #31715 - mitaa:rdoc-index-crate, 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     #[cfg(target_os = "solaris")]
115     mod os {
116         use libc;
117
118         pub struct flock {
119             pub l_type: libc::c_short,
120             pub l_whence: libc::c_short,
121             pub l_start: libc::off_t,
122             pub l_len: libc::off_t,
123             pub l_sysid: libc::c_int,
124             pub l_pid: libc::pid_t,
125         }
126
127         pub const F_WRLCK: libc::c_short = 2;
128         pub const F_UNLCK: libc::c_short = 3;
129         pub const F_SETLK: libc::c_int = 6;
130         pub const F_SETLKW: libc::c_int = 7;
131     }
132
133     pub struct Lock {
134         fd: libc::c_int,
135     }
136
137     impl Lock {
138         pub fn new(p: &Path) -> Lock {
139             let os: &OsStr = p.as_ref();
140             let buf = CString::new(os.as_bytes()).unwrap();
141             let fd = unsafe {
142                 libc::open(buf.as_ptr(), libc::O_RDWR | libc::O_CREAT,
143                            libc::S_IRWXU as libc::c_int)
144             };
145             assert!(fd > 0, "failed to open lockfile: {}",
146                     io::Error::last_os_error());
147             let flock = os::flock {
148                 l_start: 0,
149                 l_len: 0,
150                 l_pid: 0,
151                 l_whence: libc::SEEK_SET as libc::c_short,
152                 l_type: os::F_WRLCK,
153                 l_sysid: 0,
154             };
155             let ret = unsafe {
156                 libc::fcntl(fd, os::F_SETLKW, &flock)
157             };
158             if ret == -1 {
159                 let err = io::Error::last_os_error();
160                 unsafe { libc::close(fd); }
161                 panic!("could not lock `{}`: {}", p.display(), err);
162             }
163             Lock { fd: fd }
164         }
165     }
166
167     impl Drop for Lock {
168         fn drop(&mut self) {
169             let flock = os::flock {
170                 l_start: 0,
171                 l_len: 0,
172                 l_pid: 0,
173                 l_whence: libc::SEEK_SET as libc::c_short,
174                 l_type: os::F_UNLCK,
175                 l_sysid: 0,
176             };
177             unsafe {
178                 libc::fcntl(self.fd, os::F_SETLK, &flock);
179                 libc::close(self.fd);
180             }
181         }
182     }
183 }
184
185 #[cfg(windows)]
186 #[allow(bad_style)]
187 mod imp {
188     use std::io;
189     use std::mem;
190     use std::os::windows::prelude::*;
191     use std::os::windows::raw::HANDLE;
192     use std::path::Path;
193     use std::fs::{File, OpenOptions};
194
195     type DWORD = u32;
196     type LPOVERLAPPED = *mut OVERLAPPED;
197     type BOOL = i32;
198     const LOCKFILE_EXCLUSIVE_LOCK: DWORD = 0x00000002;
199
200     #[repr(C)]
201     struct OVERLAPPED {
202         Internal: usize,
203         InternalHigh: usize,
204         Pointer: *mut u8,
205         hEvent: *mut u8,
206     }
207
208     extern "system" {
209         fn LockFileEx(hFile: HANDLE,
210                       dwFlags: DWORD,
211                       dwReserved: DWORD,
212                       nNumberOfBytesToLockLow: DWORD,
213                       nNumberOfBytesToLockHigh: DWORD,
214                       lpOverlapped: LPOVERLAPPED) -> BOOL;
215     }
216
217     pub struct Lock {
218         _file: File,
219     }
220
221     impl Lock {
222         pub fn new(p: &Path) -> Lock {
223             let f = OpenOptions::new().read(true).write(true).create(true)
224                                       .open(p).unwrap();
225             let ret = unsafe {
226                 let mut overlapped: OVERLAPPED = mem::zeroed();
227                 LockFileEx(f.as_raw_handle(), LOCKFILE_EXCLUSIVE_LOCK, 0, 100, 0,
228                            &mut overlapped)
229             };
230             if ret == 0 {
231                 let err = io::Error::last_os_error();
232                 panic!("could not lock `{}`: {}", p.display(), err);
233             }
234             Lock { _file: f }
235         }
236     }
237 }