]> git.lizzy.rs Git - rust.git/blob - src/librustdoc/flock.rs
Basic iOS support
[rust.git] / src / librustdoc / flock.rs
1 // Copyright 2014 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
22 #[cfg(unix)]
23 mod imp {
24     use libc;
25
26     #[cfg(target_os = "linux")]
27     mod os {
28         use libc;
29
30         pub struct flock {
31             pub l_type: libc::c_short,
32             pub l_whence: libc::c_short,
33             pub l_start: libc::off_t,
34             pub l_len: libc::off_t,
35             pub l_pid: libc::pid_t,
36
37             // not actually here, but brings in line with freebsd
38             pub l_sysid: libc::c_int,
39         }
40
41         pub static F_WRLCK: libc::c_short = 1;
42         pub static F_UNLCK: libc::c_short = 2;
43         pub static F_SETLK: libc::c_int = 6;
44         pub static F_SETLKW: libc::c_int = 7;
45     }
46
47     #[cfg(target_os = "freebsd")]
48     mod os {
49         use libc;
50
51         pub struct flock {
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,
57             pub l_sysid: libc::c_int,
58         }
59
60         pub static F_UNLCK: libc::c_short = 2;
61         pub static F_WRLCK: libc::c_short = 3;
62         pub static F_SETLK: libc::c_int = 12;
63         pub static F_SETLKW: libc::c_int = 13;
64     }
65
66     #[cfg(target_os = "macos")]
67     #[cfg(target_os = "ios")]
68     mod os {
69         use libc;
70
71         pub struct flock {
72             pub l_start: libc::off_t,
73             pub l_len: libc::off_t,
74             pub l_pid: libc::pid_t,
75             pub l_type: libc::c_short,
76             pub l_whence: libc::c_short,
77
78             // not actually here, but brings in line with freebsd
79             pub l_sysid: libc::c_int,
80         }
81
82         pub static F_UNLCK: libc::c_short = 2;
83         pub static F_WRLCK: libc::c_short = 3;
84         pub static F_SETLK: libc::c_int = 8;
85         pub static F_SETLKW: libc::c_int = 9;
86     }
87
88     pub struct Lock {
89         fd: libc::c_int,
90     }
91
92     impl Lock {
93         pub fn new(p: &Path) -> Lock {
94             let fd = p.with_c_str(|s| unsafe {
95                 libc::open(s, libc::O_RDWR | libc::O_CREAT, libc::S_IRWXU)
96             });
97             assert!(fd > 0);
98             let flock = os::flock {
99                 l_start: 0,
100                 l_len: 0,
101                 l_pid: 0,
102                 l_whence: libc::SEEK_SET as libc::c_short,
103                 l_type: os::F_WRLCK,
104                 l_sysid: 0,
105             };
106             let ret = unsafe {
107                 libc::fcntl(fd, os::F_SETLKW, &flock as *os::flock)
108             };
109             if ret == -1 {
110                 unsafe { libc::close(fd); }
111                 fail!("could not lock `{}`", p.display())
112             }
113             Lock { fd: fd }
114         }
115     }
116
117     impl Drop for Lock {
118         fn drop(&mut self) {
119             let flock = os::flock {
120                 l_start: 0,
121                 l_len: 0,
122                 l_pid: 0,
123                 l_whence: libc::SEEK_SET as libc::c_short,
124                 l_type: os::F_UNLCK,
125                 l_sysid: 0,
126             };
127             unsafe {
128                 libc::fcntl(self.fd, os::F_SETLK, &flock as *os::flock);
129                 libc::close(self.fd);
130             }
131         }
132     }
133 }
134
135 #[cfg(windows)]
136 mod imp {
137     use libc;
138     use std::mem;
139     use std::os;
140     use std::ptr;
141
142     static LOCKFILE_EXCLUSIVE_LOCK: libc::DWORD = 0x00000002;
143
144     #[allow(non_snake_case_functions)]
145     extern "system" {
146         fn LockFileEx(hFile: libc::HANDLE,
147                       dwFlags: libc::DWORD,
148                       dwReserved: libc::DWORD,
149                       nNumberOfBytesToLockLow: libc::DWORD,
150                       nNumberOfBytesToLockHigh: libc::DWORD,
151                       lpOverlapped: libc::LPOVERLAPPED) -> libc::BOOL;
152         fn UnlockFileEx(hFile: libc::HANDLE,
153                         dwReserved: libc::DWORD,
154                         nNumberOfBytesToLockLow: libc::DWORD,
155                         nNumberOfBytesToLockHigh: libc::DWORD,
156                         lpOverlapped: libc::LPOVERLAPPED) -> libc::BOOL;
157     }
158
159     pub struct Lock {
160         handle: libc::HANDLE,
161     }
162
163     impl Lock {
164         pub fn new(p: &Path) -> Lock {
165             let p_16 = p.as_str().unwrap().to_utf16().append_one(0);
166             let handle = unsafe {
167                 libc::CreateFileW(p_16.as_ptr(),
168                                   libc::FILE_GENERIC_READ |
169                                     libc::FILE_GENERIC_WRITE,
170                                   libc::FILE_SHARE_READ |
171                                     libc::FILE_SHARE_DELETE |
172                                     libc::FILE_SHARE_WRITE,
173                                   ptr::mut_null(),
174                                   libc::CREATE_ALWAYS,
175                                   libc::FILE_ATTRIBUTE_NORMAL,
176                                   ptr::mut_null())
177             };
178             if handle as uint == libc::INVALID_HANDLE_VALUE as uint {
179                 fail!("create file error: {}", os::last_os_error());
180             }
181             let mut overlapped: libc::OVERLAPPED = unsafe { mem::zeroed() };
182             let ret = unsafe {
183                 LockFileEx(handle, LOCKFILE_EXCLUSIVE_LOCK, 0, 100, 0,
184                            &mut overlapped)
185             };
186             if ret == 0 {
187                 unsafe { libc::CloseHandle(handle); }
188                 fail!("could not lock `{}`: {}", p.display(),
189                       os::last_os_error())
190             }
191             Lock { handle: handle }
192         }
193     }
194
195     impl Drop for Lock {
196         fn drop(&mut self) {
197             let mut overlapped: libc::OVERLAPPED = unsafe { mem::zeroed() };
198             unsafe {
199                 UnlockFileEx(self.handle, 0, 100, 0, &mut overlapped);
200                 libc::CloseHandle(self.handle);
201             }
202         }
203     }
204 }