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