]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
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 | #![allow(missing_docs)] | |
12 | #![allow(non_camel_case_types)] | |
13 | #![allow(non_snake_case)] | |
1a4d82fc JJ |
14 | |
15 | use prelude::v1::*; | |
16 | ||
c34b1796 | 17 | use ffi::{OsStr, OsString}; |
85aaf69f SL |
18 | use io::{self, ErrorKind}; |
19 | use libc; | |
9346a6ac | 20 | use num::Zero; |
c34b1796 AL |
21 | use os::windows::ffi::{OsStrExt, OsStringExt}; |
22 | use path::PathBuf; | |
d9579d0f | 23 | use time::Duration; |
1a4d82fc | 24 | |
1a4d82fc JJ |
25 | pub mod backtrace; |
26 | pub mod c; | |
1a4d82fc | 27 | pub mod condvar; |
85aaf69f | 28 | pub mod ext; |
d9579d0f | 29 | pub mod fs; |
85aaf69f | 30 | pub mod handle; |
1a4d82fc | 31 | pub mod mutex; |
85aaf69f | 32 | pub mod net; |
1a4d82fc | 33 | pub mod os; |
85aaf69f | 34 | pub mod os_str; |
d9579d0f AL |
35 | pub mod pipe; |
36 | pub mod process; | |
1a4d82fc | 37 | pub mod rwlock; |
1a4d82fc | 38 | pub mod stack_overflow; |
85aaf69f | 39 | pub mod sync; |
1a4d82fc JJ |
40 | pub mod thread; |
41 | pub mod thread_local; | |
85aaf69f | 42 | pub mod time; |
c34b1796 | 43 | pub mod stdio; |
1a4d82fc | 44 | |
85aaf69f SL |
45 | pub fn decode_error_kind(errno: i32) -> ErrorKind { |
46 | match errno as libc::c_int { | |
47 | libc::ERROR_ACCESS_DENIED => ErrorKind::PermissionDenied, | |
c34b1796 | 48 | libc::ERROR_ALREADY_EXISTS => ErrorKind::AlreadyExists, |
85aaf69f | 49 | libc::ERROR_BROKEN_PIPE => ErrorKind::BrokenPipe, |
c34b1796 | 50 | libc::ERROR_FILE_NOT_FOUND => ErrorKind::NotFound, |
85aaf69f SL |
51 | libc::ERROR_NO_DATA => ErrorKind::BrokenPipe, |
52 | libc::ERROR_OPERATION_ABORTED => ErrorKind::TimedOut, | |
53 | ||
54 | libc::WSAEACCES => ErrorKind::PermissionDenied, | |
c34b1796 AL |
55 | libc::WSAEADDRINUSE => ErrorKind::AddrInUse, |
56 | libc::WSAEADDRNOTAVAIL => ErrorKind::AddrNotAvailable, | |
85aaf69f SL |
57 | libc::WSAECONNABORTED => ErrorKind::ConnectionAborted, |
58 | libc::WSAECONNREFUSED => ErrorKind::ConnectionRefused, | |
59 | libc::WSAECONNRESET => ErrorKind::ConnectionReset, | |
60 | libc::WSAEINVAL => ErrorKind::InvalidInput, | |
61 | libc::WSAENOTCONN => ErrorKind::NotConnected, | |
c34b1796 | 62 | libc::WSAEWOULDBLOCK => ErrorKind::WouldBlock, |
85aaf69f SL |
63 | |
64 | _ => ErrorKind::Other, | |
65 | } | |
66 | } | |
67 | ||
85aaf69f SL |
68 | fn to_utf16_os(s: &OsStr) -> Vec<u16> { |
69 | let mut v: Vec<_> = s.encode_wide().collect(); | |
70 | v.push(0); | |
71 | v | |
72 | } | |
73 | ||
74 | // Many Windows APIs follow a pattern of where we hand the a buffer and then | |
75 | // they will report back to us how large the buffer should be or how many bytes | |
76 | // currently reside in the buffer. This function is an abstraction over these | |
77 | // functions by making them easier to call. | |
78 | // | |
79 | // The first callback, `f1`, is yielded a (pointer, len) pair which can be | |
80 | // passed to a syscall. The `ptr` is valid for `len` items (u16 in this case). | |
81 | // The closure is expected to return what the syscall returns which will be | |
82 | // interpreted by this function to determine if the syscall needs to be invoked | |
83 | // again (with more buffer space). | |
84 | // | |
85 | // Once the syscall has completed (errors bail out early) the second closure is | |
86 | // yielded the data which has been read from the syscall. The return value | |
87 | // from this closure is then the return value of the function. | |
9346a6ac | 88 | fn fill_utf16_buf<F1, F2, T>(mut f1: F1, f2: F2) -> io::Result<T> |
85aaf69f SL |
89 | where F1: FnMut(*mut u16, libc::DWORD) -> libc::DWORD, |
90 | F2: FnOnce(&[u16]) -> T | |
91 | { | |
92 | // Start off with a stack buf but then spill over to the heap if we end up | |
93 | // needing more space. | |
94 | let mut stack_buf = [0u16; 512]; | |
95 | let mut heap_buf = Vec::new(); | |
96 | unsafe { | |
97 | let mut n = stack_buf.len(); | |
98 | loop { | |
99 | let buf = if n <= stack_buf.len() { | |
100 | &mut stack_buf[..] | |
101 | } else { | |
102 | let extra = n - heap_buf.len(); | |
103 | heap_buf.reserve(extra); | |
104 | heap_buf.set_len(n); | |
105 | &mut heap_buf[..] | |
106 | }; | |
107 | ||
108 | // This function is typically called on windows API functions which | |
109 | // will return the correct length of the string, but these functions | |
110 | // also return the `0` on error. In some cases, however, the | |
111 | // returned "correct length" may actually be 0! | |
112 | // | |
113 | // To handle this case we call `SetLastError` to reset it to 0 and | |
114 | // then check it again if we get the "0 error value". If the "last | |
115 | // error" is still 0 then we interpret it as a 0 length buffer and | |
116 | // not an actual error. | |
117 | c::SetLastError(0); | |
118 | let k = match f1(buf.as_mut_ptr(), n as libc::DWORD) { | |
119 | 0 if libc::GetLastError() == 0 => 0, | |
9346a6ac | 120 | 0 => return Err(io::Error::last_os_error()), |
85aaf69f SL |
121 | n => n, |
122 | } as usize; | |
123 | if k == n && libc::GetLastError() == | |
124 | libc::ERROR_INSUFFICIENT_BUFFER as libc::DWORD { | |
125 | n *= 2; | |
126 | } else if k >= n { | |
127 | n = k; | |
128 | } else { | |
129 | return Ok(f2(&buf[..k])) | |
130 | } | |
131 | } | |
132 | } | |
133 | } | |
134 | ||
c34b1796 AL |
135 | fn os2path(s: &[u16]) -> PathBuf { |
136 | PathBuf::from(OsString::from_wide(s)) | |
85aaf69f SL |
137 | } |
138 | ||
139 | pub fn truncate_utf16_at_nul<'a>(v: &'a [u16]) -> &'a [u16] { | |
140 | match v.iter().position(|c| *c == 0) { | |
141 | // don't include the 0 | |
142 | Some(i) => &v[..i], | |
143 | None => v | |
144 | } | |
145 | } | |
146 | ||
9346a6ac AL |
147 | fn cvt<I: PartialEq + Zero>(i: I) -> io::Result<I> { |
148 | if i == I::zero() { | |
85aaf69f SL |
149 | Err(io::Error::last_os_error()) |
150 | } else { | |
151 | Ok(i) | |
152 | } | |
153 | } | |
154 | ||
d9579d0f AL |
155 | fn dur2timeout(dur: Duration) -> libc::DWORD { |
156 | // Note that a duration is a (u64, u32) (seconds, nanoseconds) pair, and the | |
157 | // timeouts in windows APIs are typically u32 milliseconds. To translate, we | |
158 | // have two pieces to take care of: | |
159 | // | |
160 | // * Nanosecond precision is rounded up | |
161 | // * Greater than u32::MAX milliseconds (50 days) is rounded up to INFINITE | |
162 | // (never time out). | |
163 | dur.secs().checked_mul(1000).and_then(|ms| { | |
164 | ms.checked_add((dur.extra_nanos() as u64) / 1_000_000) | |
165 | }).and_then(|ms| { | |
166 | ms.checked_add(if dur.extra_nanos() % 1_000_000 > 0 {1} else {0}) | |
167 | }).map(|ms| { | |
168 | if ms > <libc::DWORD>::max_value() as u64 { | |
169 | libc::INFINITE | |
170 | } else { | |
171 | ms as libc::DWORD | |
172 | } | |
173 | }).unwrap_or(libc::INFINITE) | |
174 | } | |
175 | ||
85aaf69f SL |
176 | fn ms_to_filetime(ms: u64) -> libc::FILETIME { |
177 | // A FILETIME is a count of 100 nanosecond intervals, so we multiply by | |
178 | // 10000 b/c there are 10000 intervals in 1 ms | |
179 | let ms = ms * 10000; | |
180 | libc::FILETIME { | |
181 | dwLowDateTime: ms as u32, | |
182 | dwHighDateTime: (ms >> 32) as u32, | |
1a4d82fc JJ |
183 | } |
184 | } |