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