]>
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 | ||
7453a54e | 11 | #![allow(missing_docs, bad_style)] |
1a4d82fc | 12 | |
c34b1796 | 13 | use ffi::{OsStr, OsString}; |
85aaf69f | 14 | use io::{self, ErrorKind}; |
c34b1796 AL |
15 | use os::windows::ffi::{OsStrExt, OsStringExt}; |
16 | use path::PathBuf; | |
d9579d0f | 17 | use time::Duration; |
1a4d82fc | 18 | |
c1a9b12d SL |
19 | #[macro_use] pub mod compat; |
20 | ||
1a4d82fc JJ |
21 | pub mod backtrace; |
22 | pub mod c; | |
1a4d82fc | 23 | pub mod condvar; |
54a0048b | 24 | pub mod dynamic_lib; |
85aaf69f | 25 | pub mod ext; |
d9579d0f | 26 | pub mod fs; |
85aaf69f | 27 | pub mod handle; |
1a4d82fc | 28 | pub mod mutex; |
85aaf69f | 29 | pub mod net; |
1a4d82fc | 30 | pub mod os; |
85aaf69f | 31 | pub mod os_str; |
d9579d0f AL |
32 | pub mod pipe; |
33 | pub mod process; | |
7453a54e | 34 | pub mod rand; |
1a4d82fc | 35 | pub mod rwlock; |
1a4d82fc | 36 | pub mod stack_overflow; |
1a4d82fc JJ |
37 | pub mod thread; |
38 | pub mod thread_local; | |
85aaf69f | 39 | pub mod time; |
c34b1796 | 40 | pub mod stdio; |
1a4d82fc | 41 | |
7453a54e | 42 | #[cfg(not(test))] |
9cc50fc6 | 43 | pub fn init() { |
7453a54e SL |
44 | ::alloc::oom::set_oom_handler(oom_handler); |
45 | ||
46 | // See comment in sys/unix/mod.rs | |
47 | fn oom_handler() -> ! { | |
48 | use intrinsics; | |
49 | use ptr; | |
50 | let msg = "fatal runtime error: out of memory\n"; | |
51 | unsafe { | |
52 | // WriteFile silently fails if it is passed an invalid handle, so | |
53 | // there is no need to check the result of GetStdHandle. | |
54 | c::WriteFile(c::GetStdHandle(c::STD_ERROR_HANDLE), | |
55 | msg.as_ptr() as c::LPVOID, | |
56 | msg.len() as c::DWORD, | |
57 | ptr::null_mut(), | |
58 | ptr::null_mut()); | |
59 | intrinsics::abort(); | |
60 | } | |
61 | } | |
9cc50fc6 | 62 | } |
e9174d1e | 63 | |
85aaf69f | 64 | pub fn decode_error_kind(errno: i32) -> ErrorKind { |
92a42be0 SL |
65 | match errno as c::DWORD { |
66 | c::ERROR_ACCESS_DENIED => return ErrorKind::PermissionDenied, | |
67 | c::ERROR_ALREADY_EXISTS => return ErrorKind::AlreadyExists, | |
3157f602 | 68 | c::ERROR_FILE_EXISTS => return ErrorKind::AlreadyExists, |
92a42be0 SL |
69 | c::ERROR_BROKEN_PIPE => return ErrorKind::BrokenPipe, |
70 | c::ERROR_FILE_NOT_FOUND => return ErrorKind::NotFound, | |
71 | c::ERROR_PATH_NOT_FOUND => return ErrorKind::NotFound, | |
72 | c::ERROR_NO_DATA => return ErrorKind::BrokenPipe, | |
73 | c::ERROR_OPERATION_ABORTED => return ErrorKind::TimedOut, | |
74 | _ => {} | |
75 | } | |
76 | ||
77 | match errno { | |
78 | c::WSAEACCES => ErrorKind::PermissionDenied, | |
79 | c::WSAEADDRINUSE => ErrorKind::AddrInUse, | |
80 | c::WSAEADDRNOTAVAIL => ErrorKind::AddrNotAvailable, | |
81 | c::WSAECONNABORTED => ErrorKind::ConnectionAborted, | |
82 | c::WSAECONNREFUSED => ErrorKind::ConnectionRefused, | |
83 | c::WSAECONNRESET => ErrorKind::ConnectionReset, | |
84 | c::WSAEINVAL => ErrorKind::InvalidInput, | |
85 | c::WSAENOTCONN => ErrorKind::NotConnected, | |
86 | c::WSAEWOULDBLOCK => ErrorKind::WouldBlock, | |
87 | c::WSAETIMEDOUT => ErrorKind::TimedOut, | |
85aaf69f SL |
88 | |
89 | _ => ErrorKind::Other, | |
90 | } | |
91 | } | |
92 | ||
92a42be0 SL |
93 | pub fn to_u16s<S: AsRef<OsStr>>(s: S) -> io::Result<Vec<u16>> { |
94 | fn inner(s: &OsStr) -> io::Result<Vec<u16>> { | |
95 | let mut maybe_result: Vec<u16> = s.encode_wide().collect(); | |
96 | if maybe_result.iter().any(|&u| u == 0) { | |
97 | return Err(io::Error::new(io::ErrorKind::InvalidInput, | |
98 | "strings passed to WinAPI cannot contain NULs")); | |
99 | } | |
100 | maybe_result.push(0); | |
101 | Ok(maybe_result) | |
102 | } | |
103 | inner(s.as_ref()) | |
85aaf69f SL |
104 | } |
105 | ||
b039eaaf SL |
106 | // Many Windows APIs follow a pattern of where we hand a buffer and then they |
107 | // will report back to us how large the buffer should be or how many bytes | |
85aaf69f SL |
108 | // currently reside in the buffer. This function is an abstraction over these |
109 | // functions by making them easier to call. | |
110 | // | |
111 | // The first callback, `f1`, is yielded a (pointer, len) pair which can be | |
112 | // passed to a syscall. The `ptr` is valid for `len` items (u16 in this case). | |
113 | // The closure is expected to return what the syscall returns which will be | |
114 | // interpreted by this function to determine if the syscall needs to be invoked | |
115 | // again (with more buffer space). | |
116 | // | |
117 | // Once the syscall has completed (errors bail out early) the second closure is | |
118 | // yielded the data which has been read from the syscall. The return value | |
119 | // from this closure is then the return value of the function. | |
9346a6ac | 120 | fn fill_utf16_buf<F1, F2, T>(mut f1: F1, f2: F2) -> io::Result<T> |
92a42be0 | 121 | where F1: FnMut(*mut u16, c::DWORD) -> c::DWORD, |
85aaf69f SL |
122 | F2: FnOnce(&[u16]) -> T |
123 | { | |
124 | // Start off with a stack buf but then spill over to the heap if we end up | |
125 | // needing more space. | |
126 | let mut stack_buf = [0u16; 512]; | |
127 | let mut heap_buf = Vec::new(); | |
128 | unsafe { | |
129 | let mut n = stack_buf.len(); | |
130 | loop { | |
131 | let buf = if n <= stack_buf.len() { | |
132 | &mut stack_buf[..] | |
133 | } else { | |
134 | let extra = n - heap_buf.len(); | |
135 | heap_buf.reserve(extra); | |
136 | heap_buf.set_len(n); | |
137 | &mut heap_buf[..] | |
138 | }; | |
139 | ||
140 | // This function is typically called on windows API functions which | |
141 | // will return the correct length of the string, but these functions | |
142 | // also return the `0` on error. In some cases, however, the | |
143 | // returned "correct length" may actually be 0! | |
144 | // | |
145 | // To handle this case we call `SetLastError` to reset it to 0 and | |
146 | // then check it again if we get the "0 error value". If the "last | |
147 | // error" is still 0 then we interpret it as a 0 length buffer and | |
148 | // not an actual error. | |
149 | c::SetLastError(0); | |
92a42be0 SL |
150 | let k = match f1(buf.as_mut_ptr(), n as c::DWORD) { |
151 | 0 if c::GetLastError() == 0 => 0, | |
9346a6ac | 152 | 0 => return Err(io::Error::last_os_error()), |
85aaf69f SL |
153 | n => n, |
154 | } as usize; | |
92a42be0 | 155 | if k == n && c::GetLastError() == c::ERROR_INSUFFICIENT_BUFFER { |
85aaf69f SL |
156 | n *= 2; |
157 | } else if k >= n { | |
158 | n = k; | |
159 | } else { | |
160 | return Ok(f2(&buf[..k])) | |
161 | } | |
162 | } | |
163 | } | |
164 | } | |
165 | ||
c34b1796 AL |
166 | fn os2path(s: &[u16]) -> PathBuf { |
167 | PathBuf::from(OsString::from_wide(s)) | |
85aaf69f SL |
168 | } |
169 | ||
170 | pub fn truncate_utf16_at_nul<'a>(v: &'a [u16]) -> &'a [u16] { | |
171 | match v.iter().position(|c| *c == 0) { | |
172 | // don't include the 0 | |
173 | Some(i) => &v[..i], | |
174 | None => v | |
175 | } | |
176 | } | |
177 | ||
3157f602 XL |
178 | trait IsZero { |
179 | fn is_zero(&self) -> bool; | |
180 | } | |
181 | ||
182 | macro_rules! impl_is_zero { | |
183 | ($($t:ident)*) => ($(impl IsZero for $t { | |
184 | fn is_zero(&self) -> bool { | |
185 | *self == 0 | |
186 | } | |
187 | })*) | |
188 | } | |
189 | ||
190 | impl_is_zero! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize } | |
191 | ||
192 | fn cvt<I: IsZero>(i: I) -> io::Result<I> { | |
193 | if i.is_zero() { | |
85aaf69f SL |
194 | Err(io::Error::last_os_error()) |
195 | } else { | |
196 | Ok(i) | |
197 | } | |
198 | } | |
199 | ||
92a42be0 | 200 | fn dur2timeout(dur: Duration) -> c::DWORD { |
d9579d0f AL |
201 | // Note that a duration is a (u64, u32) (seconds, nanoseconds) pair, and the |
202 | // timeouts in windows APIs are typically u32 milliseconds. To translate, we | |
203 | // have two pieces to take care of: | |
204 | // | |
205 | // * Nanosecond precision is rounded up | |
206 | // * Greater than u32::MAX milliseconds (50 days) is rounded up to INFINITE | |
207 | // (never time out). | |
c1a9b12d SL |
208 | dur.as_secs().checked_mul(1000).and_then(|ms| { |
209 | ms.checked_add((dur.subsec_nanos() as u64) / 1_000_000) | |
d9579d0f | 210 | }).and_then(|ms| { |
c1a9b12d | 211 | ms.checked_add(if dur.subsec_nanos() % 1_000_000 > 0 {1} else {0}) |
d9579d0f | 212 | }).map(|ms| { |
92a42be0 SL |
213 | if ms > <c::DWORD>::max_value() as u64 { |
214 | c::INFINITE | |
d9579d0f | 215 | } else { |
92a42be0 | 216 | ms as c::DWORD |
d9579d0f | 217 | } |
92a42be0 | 218 | }).unwrap_or(c::INFINITE) |
d9579d0f | 219 | } |