]> git.lizzy.rs Git - rust.git/blob - src/libnative/io/mod.rs
auto merge of #15999 : Kimundi/rust/fix_folder, r=nikomatsakis
[rust.git] / src / libnative / io / mod.rs
1 // Copyright 2013-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 //! Native thread-blocking I/O implementation
12 //!
13 //! This module contains the implementation of native thread-blocking
14 //! implementations of I/O on all platforms. This module is not intended to be
15 //! used directly, but rather the rust runtime will fall back to using it if
16 //! necessary.
17 //!
18 //! Rust code normally runs inside of green tasks with a local scheduler using
19 //! asynchronous I/O to cooperate among tasks. This model is not always
20 //! available, however, and that's where these native implementations come into
21 //! play. The only dependencies of these modules are the normal system libraries
22 //! that you would find on the respective platform.
23
24 #![allow(non_snake_case_functions)]
25
26 use libc::c_int;
27 use libc;
28 use std::c_str::CString;
29 use std::os;
30 use std::rt::rtio;
31 use std::rt::rtio::{IoResult, IoError};
32
33 // Local re-exports
34 pub use self::file::FileDesc;
35 pub use self::process::Process;
36
37 mod helper_thread;
38
39 // Native I/O implementations
40 pub mod addrinfo;
41 pub mod net;
42 pub mod process;
43 mod util;
44
45 #[cfg(unix)]
46 #[path = "file_unix.rs"]
47 pub mod file;
48 #[cfg(windows)]
49 #[path = "file_win32.rs"]
50 pub mod file;
51
52 #[cfg(target_os = "macos")]
53 #[cfg(target_os = "ios")]
54 #[cfg(target_os = "freebsd")]
55 #[cfg(target_os = "dragonfly")]
56 #[cfg(target_os = "android")]
57 #[cfg(target_os = "linux")]
58 #[path = "timer_unix.rs"]
59 pub mod timer;
60
61 #[cfg(target_os = "win32")]
62 #[path = "timer_win32.rs"]
63 pub mod timer;
64
65 #[cfg(unix)]
66 #[path = "pipe_unix.rs"]
67 pub mod pipe;
68
69 #[cfg(windows)]
70 #[path = "pipe_win32.rs"]
71 pub mod pipe;
72
73 #[cfg(windows)]
74 #[path = "tty_win32.rs"]
75 mod tty;
76
77 #[cfg(unix)]    #[path = "c_unix.rs"]  mod c;
78 #[cfg(windows)] #[path = "c_win32.rs"] mod c;
79
80 fn unimpl() -> IoError {
81     #[cfg(unix)] use ERROR = libc::ENOSYS;
82     #[cfg(windows)] use ERROR = libc::ERROR_CALL_NOT_IMPLEMENTED;
83     IoError {
84         code: ERROR as uint,
85         extra: 0,
86         detail: Some("not yet supported by the `native` runtime, maybe try `green`.".to_string()),
87     }
88 }
89
90 fn last_error() -> IoError {
91     let errno = os::errno() as uint;
92     IoError {
93         code: os::errno() as uint,
94         extra: 0,
95         detail: Some(os::error_string(errno)),
96     }
97 }
98
99 // unix has nonzero values as errors
100 fn mkerr_libc(ret: libc::c_int) -> IoResult<()> {
101     if ret != 0 {
102         Err(last_error())
103     } else {
104         Ok(())
105     }
106 }
107
108 // windows has zero values as errors
109 #[cfg(windows)]
110 fn mkerr_winbool(ret: libc::c_int) -> IoResult<()> {
111     if ret == 0 {
112         Err(last_error())
113     } else {
114         Ok(())
115     }
116 }
117
118 #[cfg(windows)]
119 #[inline]
120 fn retry(f: || -> libc::c_int) -> libc::c_int {
121     loop {
122         match f() {
123             -1 if os::errno() as int == libc::WSAEINTR as int => {}
124             n => return n,
125         }
126     }
127 }
128
129 #[cfg(unix)]
130 #[inline]
131 fn retry(f: || -> libc::c_int) -> libc::c_int {
132     loop {
133         match f() {
134             -1 if os::errno() as int == libc::EINTR as int => {}
135             n => return n,
136         }
137     }
138 }
139
140 fn keep_going(data: &[u8], f: |*const u8, uint| -> i64) -> i64 {
141     let origamt = data.len();
142     let mut data = data.as_ptr();
143     let mut amt = origamt;
144     while amt > 0 {
145         let ret = retry(|| f(data, amt) as libc::c_int);
146         if ret == 0 {
147             break
148         } else if ret != -1 {
149             amt -= ret as uint;
150             data = unsafe { data.offset(ret as int) };
151         } else {
152             return ret as i64;
153         }
154     }
155     return (origamt - amt) as i64;
156 }
157
158 /// Implementation of rt::rtio's IoFactory trait to generate handles to the
159 /// native I/O functionality.
160 pub struct IoFactory {
161     _cannot_construct_outside_of_this_module: ()
162 }
163
164 impl IoFactory {
165     pub fn new() -> IoFactory {
166         net::init();
167         IoFactory { _cannot_construct_outside_of_this_module: () }
168     }
169 }
170
171 impl rtio::IoFactory for IoFactory {
172     // networking
173     fn tcp_connect(&mut self, addr: rtio::SocketAddr,
174                    timeout: Option<u64>)
175         -> IoResult<Box<rtio::RtioTcpStream + Send>>
176     {
177         net::TcpStream::connect(addr, timeout).map(|s| {
178             box s as Box<rtio::RtioTcpStream + Send>
179         })
180     }
181     fn tcp_bind(&mut self, addr: rtio::SocketAddr)
182                 -> IoResult<Box<rtio::RtioTcpListener + Send>> {
183         net::TcpListener::bind(addr).map(|s| {
184             box s as Box<rtio::RtioTcpListener + Send>
185         })
186     }
187     fn udp_bind(&mut self, addr: rtio::SocketAddr)
188                 -> IoResult<Box<rtio::RtioUdpSocket + Send>> {
189         net::UdpSocket::bind(addr).map(|u| {
190             box u as Box<rtio::RtioUdpSocket + Send>
191         })
192     }
193     fn unix_bind(&mut self, path: &CString)
194                  -> IoResult<Box<rtio::RtioUnixListener + Send>> {
195         pipe::UnixListener::bind(path).map(|s| {
196             box s as Box<rtio::RtioUnixListener + Send>
197         })
198     }
199     fn unix_connect(&mut self, path: &CString,
200                     timeout: Option<u64>) -> IoResult<Box<rtio::RtioPipe + Send>> {
201         pipe::UnixStream::connect(path, timeout).map(|s| {
202             box s as Box<rtio::RtioPipe + Send>
203         })
204     }
205     fn get_host_addresses(&mut self, host: Option<&str>, servname: Option<&str>,
206                           hint: Option<rtio::AddrinfoHint>)
207         -> IoResult<Vec<rtio::AddrinfoInfo>>
208     {
209         addrinfo::GetAddrInfoRequest::run(host, servname, hint)
210     }
211
212     // filesystem operations
213     fn fs_from_raw_fd(&mut self, fd: c_int, close: rtio::CloseBehavior)
214                       -> Box<rtio::RtioFileStream + Send> {
215         let close = match close {
216             rtio::CloseSynchronously | rtio::CloseAsynchronously => true,
217             rtio::DontClose => false
218         };
219         box file::FileDesc::new(fd, close) as Box<rtio::RtioFileStream + Send>
220     }
221     fn fs_open(&mut self, path: &CString, fm: rtio::FileMode,
222                fa: rtio::FileAccess)
223         -> IoResult<Box<rtio::RtioFileStream + Send>>
224     {
225         file::open(path, fm, fa).map(|fd| box fd as Box<rtio::RtioFileStream + Send>)
226     }
227     fn fs_unlink(&mut self, path: &CString) -> IoResult<()> {
228         file::unlink(path)
229     }
230     fn fs_stat(&mut self, path: &CString) -> IoResult<rtio::FileStat> {
231         file::stat(path)
232     }
233     fn fs_mkdir(&mut self, path: &CString, mode: uint) -> IoResult<()> {
234         file::mkdir(path, mode)
235     }
236     fn fs_chmod(&mut self, path: &CString, mode: uint) -> IoResult<()> {
237         file::chmod(path, mode)
238     }
239     fn fs_rmdir(&mut self, path: &CString) -> IoResult<()> {
240         file::rmdir(path)
241     }
242     fn fs_rename(&mut self, path: &CString, to: &CString) -> IoResult<()> {
243         file::rename(path, to)
244     }
245     fn fs_readdir(&mut self, path: &CString, _flags: c_int) -> IoResult<Vec<CString>> {
246         file::readdir(path)
247     }
248     fn fs_lstat(&mut self, path: &CString) -> IoResult<rtio::FileStat> {
249         file::lstat(path)
250     }
251     fn fs_chown(&mut self, path: &CString, uid: int, gid: int) -> IoResult<()> {
252         file::chown(path, uid, gid)
253     }
254     fn fs_readlink(&mut self, path: &CString) -> IoResult<CString> {
255         file::readlink(path)
256     }
257     fn fs_symlink(&mut self, src: &CString, dst: &CString) -> IoResult<()> {
258         file::symlink(src, dst)
259     }
260     fn fs_link(&mut self, src: &CString, dst: &CString) -> IoResult<()> {
261         file::link(src, dst)
262     }
263     fn fs_utime(&mut self, src: &CString, atime: u64,
264                 mtime: u64) -> IoResult<()> {
265         file::utime(src, atime, mtime)
266     }
267
268     // misc
269     fn timer_init(&mut self) -> IoResult<Box<rtio::RtioTimer + Send>> {
270         timer::Timer::new().map(|t| box t as Box<rtio::RtioTimer + Send>)
271     }
272     fn spawn(&mut self, cfg: rtio::ProcessConfig)
273             -> IoResult<(Box<rtio::RtioProcess + Send>,
274                          Vec<Option<Box<rtio::RtioPipe + Send>>>)> {
275         process::Process::spawn(cfg).map(|(p, io)| {
276             (box p as Box<rtio::RtioProcess + Send>,
277              io.move_iter().map(|p| p.map(|p| {
278                  box p as Box<rtio::RtioPipe + Send>
279              })).collect())
280         })
281     }
282     fn kill(&mut self, pid: libc::pid_t, signum: int) -> IoResult<()> {
283         process::Process::kill(pid, signum)
284     }
285     fn pipe_open(&mut self, fd: c_int) -> IoResult<Box<rtio::RtioPipe + Send>> {
286         Ok(box file::FileDesc::new(fd, true) as Box<rtio::RtioPipe + Send>)
287     }
288     #[cfg(unix)]
289     fn tty_open(&mut self, fd: c_int, _readable: bool)
290                 -> IoResult<Box<rtio::RtioTTY + Send>> {
291         if unsafe { libc::isatty(fd) } != 0 {
292             Ok(box file::FileDesc::new(fd, true) as Box<rtio::RtioTTY + Send>)
293         } else {
294             Err(IoError {
295                 code: libc::ENOTTY as uint,
296                 extra: 0,
297                 detail: None,
298             })
299         }
300     }
301     #[cfg(windows)]
302     fn tty_open(&mut self, fd: c_int, _readable: bool)
303                 -> IoResult<Box<rtio::RtioTTY + Send>> {
304         if tty::is_tty(fd) {
305             Ok(box tty::WindowsTTY::new(fd) as Box<rtio::RtioTTY + Send>)
306         } else {
307             Err(IoError {
308                 code: libc::ERROR_INVALID_HANDLE as uint,
309                 extra: 0,
310                 detail: None,
311             })
312         }
313     }
314     fn signal(&mut self, _signal: int, _cb: Box<rtio::Callback>)
315               -> IoResult<Box<rtio::RtioSignal + Send>> {
316         Err(unimpl())
317     }
318 }