Runtime removal: add private sys, sys_common modules
These modules will house the code that used to be part of the runtime system in libnative. The `sys_common` module contains a few low-level but cross-platform details. The `sys` module is set up using `#[cfg()]` to include either a unix or windows implementation of a common API surface. This API surface is *not* exported directly in `libstd`, but is instead used to bulid `std::os` and `std::io`. Ultimately, the low-level details in `sys` will be exposed in a controlled way through a separate platform-specific surface, but that setup is not part of this patch.
This commit is contained in:
parent
93c85eb8bd
commit
3a527f2b33
@ -73,9 +73,6 @@ pub mod pipe;
|
||||
#[path = "tty_windows.rs"]
|
||||
mod tty;
|
||||
|
||||
#[cfg(unix)] #[path = "c_unix.rs"] mod c;
|
||||
#[cfg(windows)] #[path = "c_windows.rs"] mod c;
|
||||
|
||||
fn unimpl() -> IoError {
|
||||
#[cfg(unix)] use libc::ENOSYS as ERROR;
|
||||
#[cfg(windows)] use libc::ERROR_CALL_NOT_IMPLEMENTED as ERROR;
|
||||
|
@ -1,209 +0,0 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use libc;
|
||||
use std::cmp;
|
||||
use std::mem;
|
||||
use std::os;
|
||||
use std::ptr;
|
||||
use std::rt::rtio::{IoResult, IoError};
|
||||
|
||||
use super::c;
|
||||
use super::net;
|
||||
use super::{retry, last_error};
|
||||
|
||||
#[deriving(Show)]
|
||||
pub enum SocketStatus {
|
||||
Readable,
|
||||
Writable,
|
||||
}
|
||||
|
||||
pub fn timeout(desc: &'static str) -> IoError {
|
||||
#[cfg(unix)] use libc::ETIMEDOUT as ERROR;
|
||||
#[cfg(windows)] use libc::ERROR_OPERATION_ABORTED as ERROR;
|
||||
IoError {
|
||||
code: ERROR as uint,
|
||||
extra: 0,
|
||||
detail: Some(desc.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn short_write(n: uint, desc: &'static str) -> IoError {
|
||||
#[cfg(unix)] use libc::EAGAIN as ERROR;
|
||||
#[cfg(windows)] use libc::ERROR_OPERATION_ABORTED as ERROR;
|
||||
IoError {
|
||||
code: ERROR as uint,
|
||||
extra: n,
|
||||
detail: Some(desc.to_string()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn eof() -> IoError {
|
||||
IoError {
|
||||
code: libc::EOF as uint,
|
||||
extra: 0,
|
||||
detail: None,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn ms_to_timeval(ms: u64) -> libc::timeval {
|
||||
libc::timeval {
|
||||
tv_sec: (ms / 1000) as libc::c_long,
|
||||
tv_usec: ((ms % 1000) * 1000) as libc::c_long,
|
||||
}
|
||||
}
|
||||
#[cfg(not(windows))]
|
||||
pub fn ms_to_timeval(ms: u64) -> libc::timeval {
|
||||
libc::timeval {
|
||||
tv_sec: (ms / 1000) as libc::time_t,
|
||||
tv_usec: ((ms % 1000) * 1000) as libc::suseconds_t,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub fn wouldblock() -> bool {
|
||||
let err = os::errno();
|
||||
err == libc::EWOULDBLOCK as int || err == libc::EAGAIN as int
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn wouldblock() -> bool {
|
||||
let err = os::errno();
|
||||
err == libc::WSAEWOULDBLOCK as uint
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
pub fn set_nonblocking(fd: net::sock_t, nb: bool) -> IoResult<()> {
|
||||
let set = nb as libc::c_int;
|
||||
super::mkerr_libc(retry(|| unsafe { c::ioctl(fd, c::FIONBIO, &set) }))
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn set_nonblocking(fd: net::sock_t, nb: bool) -> IoResult<()> {
|
||||
let mut set = nb as libc::c_ulong;
|
||||
if unsafe { c::ioctlsocket(fd, c::FIONBIO, &mut set) != 0 } {
|
||||
Err(last_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// See http://developerweb.net/viewtopic.php?id=3196 for where this is
|
||||
// derived from.
|
||||
pub fn connect_timeout(fd: net::sock_t,
|
||||
addrp: *const libc::sockaddr,
|
||||
len: libc::socklen_t,
|
||||
timeout_ms: u64) -> IoResult<()> {
|
||||
use std::os;
|
||||
#[cfg(unix)] use libc::EINPROGRESS as INPROGRESS;
|
||||
#[cfg(windows)] use libc::WSAEINPROGRESS as INPROGRESS;
|
||||
#[cfg(unix)] use libc::EWOULDBLOCK as WOULDBLOCK;
|
||||
#[cfg(windows)] use libc::WSAEWOULDBLOCK as WOULDBLOCK;
|
||||
|
||||
// Make sure the call to connect() doesn't block
|
||||
try!(set_nonblocking(fd, true));
|
||||
|
||||
let ret = match unsafe { libc::connect(fd, addrp, len) } {
|
||||
// If the connection is in progress, then we need to wait for it to
|
||||
// finish (with a timeout). The current strategy for doing this is
|
||||
// to use select() with a timeout.
|
||||
-1 if os::errno() as int == INPROGRESS as int ||
|
||||
os::errno() as int == WOULDBLOCK as int => {
|
||||
let mut set: c::fd_set = unsafe { mem::zeroed() };
|
||||
c::fd_set(&mut set, fd);
|
||||
match await(fd, &mut set, timeout_ms) {
|
||||
0 => Err(timeout("connection timed out")),
|
||||
-1 => Err(last_error()),
|
||||
_ => {
|
||||
let err: libc::c_int = try!(
|
||||
net::getsockopt(fd, libc::SOL_SOCKET, libc::SO_ERROR));
|
||||
if err == 0 {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(IoError {
|
||||
code: err as uint,
|
||||
extra: 0,
|
||||
detail: Some(os::error_string(err as uint)),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-1 => Err(last_error()),
|
||||
_ => Ok(()),
|
||||
};
|
||||
|
||||
// be sure to turn blocking I/O back on
|
||||
try!(set_nonblocking(fd, false));
|
||||
return ret;
|
||||
|
||||
#[cfg(unix)]
|
||||
fn await(fd: net::sock_t, set: &mut c::fd_set,
|
||||
timeout: u64) -> libc::c_int {
|
||||
let start = ::io::timer::now();
|
||||
retry(|| unsafe {
|
||||
// Recalculate the timeout each iteration (it is generally
|
||||
// undefined what the value of the 'tv' is after select
|
||||
// returns EINTR).
|
||||
let mut tv = ms_to_timeval(timeout - (::io::timer::now() - start));
|
||||
c::select(fd + 1, ptr::null_mut(), set as *mut _,
|
||||
ptr::null_mut(), &mut tv)
|
||||
})
|
||||
}
|
||||
#[cfg(windows)]
|
||||
fn await(_fd: net::sock_t, set: &mut c::fd_set,
|
||||
timeout: u64) -> libc::c_int {
|
||||
let mut tv = ms_to_timeval(timeout);
|
||||
unsafe { c::select(1, ptr::null_mut(), set, ptr::null_mut(), &mut tv) }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn await(fds: &[net::sock_t], deadline: Option<u64>,
|
||||
status: SocketStatus) -> IoResult<()> {
|
||||
let mut set: c::fd_set = unsafe { mem::zeroed() };
|
||||
let mut max = 0;
|
||||
for &fd in fds.iter() {
|
||||
c::fd_set(&mut set, fd);
|
||||
max = cmp::max(max, fd + 1);
|
||||
}
|
||||
if cfg!(windows) {
|
||||
max = fds.len() as net::sock_t;
|
||||
}
|
||||
|
||||
let (read, write) = match status {
|
||||
Readable => (&mut set as *mut _, ptr::null_mut()),
|
||||
Writable => (ptr::null_mut(), &mut set as *mut _),
|
||||
};
|
||||
let mut tv: libc::timeval = unsafe { mem::zeroed() };
|
||||
|
||||
match retry(|| {
|
||||
let now = ::io::timer::now();
|
||||
let tvp = match deadline {
|
||||
None => ptr::null_mut(),
|
||||
Some(deadline) => {
|
||||
// If we're past the deadline, then pass a 0 timeout to
|
||||
// select() so we can poll the status
|
||||
let ms = if deadline < now {0} else {deadline - now};
|
||||
tv = ms_to_timeval(ms);
|
||||
&mut tv as *mut _
|
||||
}
|
||||
};
|
||||
let r = unsafe {
|
||||
c::select(max as libc::c_int, read, write, ptr::null_mut(), tvp)
|
||||
};
|
||||
r
|
||||
}) {
|
||||
-1 => Err(last_error()),
|
||||
0 => Err(timeout("timed out")),
|
||||
_ => Ok(()),
|
||||
}
|
||||
}
|
@ -236,8 +236,7 @@ use os;
|
||||
use boxed::Box;
|
||||
use result::{Ok, Err, Result};
|
||||
use rt::rtio;
|
||||
use slice::{AsSlice, SlicePrelude};
|
||||
use str::{Str, StrPrelude};
|
||||
use sys;
|
||||
use str;
|
||||
use string::String;
|
||||
use uint;
|
||||
@ -312,91 +311,10 @@ impl IoError {
|
||||
/// struct is filled with an allocated string describing the error
|
||||
/// in more detail, retrieved from the operating system.
|
||||
pub fn from_errno(errno: uint, detail: bool) -> IoError {
|
||||
|
||||
#[cfg(windows)]
|
||||
fn get_err(errno: i32) -> (IoErrorKind, &'static str) {
|
||||
match errno {
|
||||
libc::EOF => (EndOfFile, "end of file"),
|
||||
libc::ERROR_NO_DATA => (BrokenPipe, "the pipe is being closed"),
|
||||
libc::ERROR_FILE_NOT_FOUND => (FileNotFound, "file not found"),
|
||||
libc::ERROR_INVALID_NAME => (InvalidInput, "invalid file name"),
|
||||
libc::WSAECONNREFUSED => (ConnectionRefused, "connection refused"),
|
||||
libc::WSAECONNRESET => (ConnectionReset, "connection reset"),
|
||||
libc::ERROR_ACCESS_DENIED | libc::WSAEACCES =>
|
||||
(PermissionDenied, "permission denied"),
|
||||
libc::WSAEWOULDBLOCK => {
|
||||
(ResourceUnavailable, "resource temporarily unavailable")
|
||||
}
|
||||
libc::WSAENOTCONN => (NotConnected, "not connected"),
|
||||
libc::WSAECONNABORTED => (ConnectionAborted, "connection aborted"),
|
||||
libc::WSAEADDRNOTAVAIL => (ConnectionRefused, "address not available"),
|
||||
libc::WSAEADDRINUSE => (ConnectionRefused, "address in use"),
|
||||
libc::ERROR_BROKEN_PIPE => (EndOfFile, "the pipe has ended"),
|
||||
libc::ERROR_OPERATION_ABORTED =>
|
||||
(TimedOut, "operation timed out"),
|
||||
libc::WSAEINVAL => (InvalidInput, "invalid argument"),
|
||||
libc::ERROR_CALL_NOT_IMPLEMENTED =>
|
||||
(IoUnavailable, "function not implemented"),
|
||||
libc::ERROR_INVALID_HANDLE =>
|
||||
(MismatchedFileTypeForOperation,
|
||||
"invalid handle provided to function"),
|
||||
libc::ERROR_NOTHING_TO_TERMINATE =>
|
||||
(InvalidInput, "no process to kill"),
|
||||
|
||||
// libuv maps this error code to EISDIR. we do too. if it is found
|
||||
// to be incorrect, we can add in some more machinery to only
|
||||
// return this message when ERROR_INVALID_FUNCTION after certain
|
||||
// Windows calls.
|
||||
libc::ERROR_INVALID_FUNCTION => (InvalidInput,
|
||||
"illegal operation on a directory"),
|
||||
|
||||
_ => (OtherIoError, "unknown error")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
fn get_err(errno: i32) -> (IoErrorKind, &'static str) {
|
||||
// FIXME: this should probably be a bit more descriptive...
|
||||
match errno {
|
||||
libc::EOF => (EndOfFile, "end of file"),
|
||||
libc::ECONNREFUSED => (ConnectionRefused, "connection refused"),
|
||||
libc::ECONNRESET => (ConnectionReset, "connection reset"),
|
||||
libc::EPERM | libc::EACCES =>
|
||||
(PermissionDenied, "permission denied"),
|
||||
libc::EPIPE => (BrokenPipe, "broken pipe"),
|
||||
libc::ENOTCONN => (NotConnected, "not connected"),
|
||||
libc::ECONNABORTED => (ConnectionAborted, "connection aborted"),
|
||||
libc::EADDRNOTAVAIL => (ConnectionRefused, "address not available"),
|
||||
libc::EADDRINUSE => (ConnectionRefused, "address in use"),
|
||||
libc::ENOENT => (FileNotFound, "no such file or directory"),
|
||||
libc::EISDIR => (InvalidInput, "illegal operation on a directory"),
|
||||
libc::ENOSYS => (IoUnavailable, "function not implemented"),
|
||||
libc::EINVAL => (InvalidInput, "invalid argument"),
|
||||
libc::ENOTTY =>
|
||||
(MismatchedFileTypeForOperation,
|
||||
"file descriptor is not a TTY"),
|
||||
libc::ETIMEDOUT => (TimedOut, "operation timed out"),
|
||||
libc::ECANCELED => (TimedOut, "operation aborted"),
|
||||
|
||||
// These two constants can have the same value on some systems,
|
||||
// but different values on others, so we can't use a match
|
||||
// clause
|
||||
x if x == libc::EAGAIN || x == libc::EWOULDBLOCK =>
|
||||
(ResourceUnavailable, "resource temporarily unavailable"),
|
||||
|
||||
_ => (OtherIoError, "unknown error")
|
||||
}
|
||||
}
|
||||
|
||||
let (kind, desc) = get_err(errno as i32);
|
||||
IoError {
|
||||
kind: kind,
|
||||
desc: desc,
|
||||
detail: if detail && kind == OtherIoError {
|
||||
Some(os::error_string(errno).as_slice().chars().map(|c| c.to_lowercase()).collect())
|
||||
} else {
|
||||
None
|
||||
},
|
||||
let mut err = sys::decode_error(errno as i32);
|
||||
if detail && err.kind == OtherIoError {
|
||||
err.detail = Some(os::error_string(errno).as_slice().chars()
|
||||
.map(|c| c.to_lowercase()).collect())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -242,6 +242,13 @@ pub mod io;
|
||||
pub mod path;
|
||||
pub mod fmt;
|
||||
|
||||
#[cfg(unix)]
|
||||
#[path = "sys/unix/mod.rs"] mod sys;
|
||||
#[cfg(windows)]
|
||||
#[path = "sys/windows/mod.rs"] mod sys;
|
||||
|
||||
#[path = "sys/common/mod.rs"] mod sys_common;
|
||||
|
||||
// FIXME #7809: This shouldn't be pub, and it should be reexported under 'unstable'
|
||||
// but name resolution doesn't work without it being pub.
|
||||
pub mod rt;
|
||||
|
155
src/libstd/os.rs
155
src/libstd/os.rs
@ -34,7 +34,7 @@
|
||||
use clone::Clone;
|
||||
use error::{FromError, Error};
|
||||
use fmt;
|
||||
use io::{IoResult, IoError};
|
||||
use io::IoResult;
|
||||
use iter::Iterator;
|
||||
use libc::{c_void, c_int};
|
||||
use libc;
|
||||
@ -43,6 +43,7 @@ use ops::Drop;
|
||||
use option::{Some, None, Option};
|
||||
use os;
|
||||
use path::{Path, GenericPath, BytesContainer};
|
||||
use sys::os as os_imp;
|
||||
use ptr::RawPtr;
|
||||
use ptr;
|
||||
use result::{Err, Ok, Result};
|
||||
@ -905,59 +906,9 @@ pub fn change_dir(p: &Path) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
/// Returns the platform-specific value of errno
|
||||
pub fn errno() -> int {
|
||||
#[cfg(any(target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "freebsd"))]
|
||||
fn errno_location() -> *const c_int {
|
||||
extern {
|
||||
fn __error() -> *const c_int;
|
||||
}
|
||||
unsafe {
|
||||
__error()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "dragonfly")]
|
||||
fn errno_location() -> *const c_int {
|
||||
extern {
|
||||
fn __dfly_error() -> *const c_int;
|
||||
}
|
||||
unsafe {
|
||||
__dfly_error()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
fn errno_location() -> *const c_int {
|
||||
extern {
|
||||
fn __errno_location() -> *const c_int;
|
||||
}
|
||||
unsafe {
|
||||
__errno_location()
|
||||
}
|
||||
}
|
||||
|
||||
unsafe {
|
||||
(*errno_location()) as int
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
/// Returns the platform-specific value of errno
|
||||
pub fn errno() -> uint {
|
||||
use libc::types::os::arch::extra::DWORD;
|
||||
|
||||
#[link_name = "kernel32"]
|
||||
extern "system" {
|
||||
fn GetLastError() -> DWORD;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
GetLastError() as uint
|
||||
}
|
||||
os_imp::errno() as uint
|
||||
}
|
||||
|
||||
/// Return the string corresponding to an `errno()` value of `errnum`.
|
||||
@ -969,105 +920,7 @@ pub fn errno() -> uint {
|
||||
/// println!("{}", os::error_string(os::errno() as uint));
|
||||
/// ```
|
||||
pub fn error_string(errnum: uint) -> String {
|
||||
return strerror(errnum);
|
||||
|
||||
#[cfg(unix)]
|
||||
fn strerror(errnum: uint) -> String {
|
||||
#[cfg(any(target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "android",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly"))]
|
||||
fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: libc::size_t)
|
||||
-> c_int {
|
||||
extern {
|
||||
fn strerror_r(errnum: c_int, buf: *mut c_char,
|
||||
buflen: libc::size_t) -> c_int;
|
||||
}
|
||||
unsafe {
|
||||
strerror_r(errnum, buf, buflen)
|
||||
}
|
||||
}
|
||||
|
||||
// GNU libc provides a non-compliant version of strerror_r by default
|
||||
// and requires macros to instead use the POSIX compliant variant.
|
||||
// So we just use __xpg_strerror_r which is always POSIX compliant
|
||||
#[cfg(target_os = "linux")]
|
||||
fn strerror_r(errnum: c_int, buf: *mut c_char,
|
||||
buflen: libc::size_t) -> c_int {
|
||||
extern {
|
||||
fn __xpg_strerror_r(errnum: c_int,
|
||||
buf: *mut c_char,
|
||||
buflen: libc::size_t)
|
||||
-> c_int;
|
||||
}
|
||||
unsafe {
|
||||
__xpg_strerror_r(errnum, buf, buflen)
|
||||
}
|
||||
}
|
||||
|
||||
let mut buf = [0 as c_char, ..TMPBUF_SZ];
|
||||
|
||||
let p = buf.as_mut_ptr();
|
||||
unsafe {
|
||||
if strerror_r(errnum as c_int, p, buf.len() as libc::size_t) < 0 {
|
||||
panic!("strerror_r failure");
|
||||
}
|
||||
|
||||
::string::raw::from_buf(p as *const u8)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn strerror(errnum: uint) -> String {
|
||||
use libc::types::os::arch::extra::DWORD;
|
||||
use libc::types::os::arch::extra::LPWSTR;
|
||||
use libc::types::os::arch::extra::LPVOID;
|
||||
use libc::types::os::arch::extra::WCHAR;
|
||||
|
||||
#[link_name = "kernel32"]
|
||||
extern "system" {
|
||||
fn FormatMessageW(flags: DWORD,
|
||||
lpSrc: LPVOID,
|
||||
msgId: DWORD,
|
||||
langId: DWORD,
|
||||
buf: LPWSTR,
|
||||
nsize: DWORD,
|
||||
args: *const c_void)
|
||||
-> DWORD;
|
||||
}
|
||||
|
||||
static FORMAT_MESSAGE_FROM_SYSTEM: DWORD = 0x00001000;
|
||||
static FORMAT_MESSAGE_IGNORE_INSERTS: DWORD = 0x00000200;
|
||||
|
||||
// This value is calculated from the macro
|
||||
// MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT)
|
||||
let langId = 0x0800 as DWORD;
|
||||
|
||||
let mut buf = [0 as WCHAR, ..TMPBUF_SZ];
|
||||
|
||||
unsafe {
|
||||
let res = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
ptr::null_mut(),
|
||||
errnum as DWORD,
|
||||
langId,
|
||||
buf.as_mut_ptr(),
|
||||
buf.len() as DWORD,
|
||||
ptr::null());
|
||||
if res == 0 {
|
||||
// Sometimes FormatMessageW can fail e.g. system doesn't like langId,
|
||||
let fm_err = errno();
|
||||
return format!("OS Error {} (FormatMessageW() returned error {})", errnum, fm_err);
|
||||
}
|
||||
|
||||
let msg = String::from_utf16(::str::truncate_utf16_at_nul(buf));
|
||||
match msg {
|
||||
Some(msg) => format!("OS Error {}: {}", errnum, msg),
|
||||
None => format!("OS Error {} (FormatMessageW() returned invalid UTF-16)", errnum),
|
||||
}
|
||||
}
|
||||
}
|
||||
return os_imp::error_string(errnum as i32);
|
||||
}
|
||||
|
||||
/// Get a string representing the platform-dependent last error
|
||||
|
91
src/libstd/sys/common/mod.rs
Normal file
91
src/libstd/sys/common/mod.rs
Normal file
@ -0,0 +1,91 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![allow(missing_doc)]
|
||||
#![allow(dead_code)]
|
||||
|
||||
use io::{mod, IoError, IoResult};
|
||||
use prelude::*;
|
||||
use num;
|
||||
use sys::{last_error, retry, fs};
|
||||
use c_str::CString;
|
||||
use path::BytesContainer;
|
||||
use collections;
|
||||
|
||||
pub mod net;
|
||||
|
||||
// common error constructors
|
||||
|
||||
pub fn eof() -> IoError {
|
||||
IoError {
|
||||
kind: io::EndOfFile,
|
||||
desc: "end of file",
|
||||
detail: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn timeout(desc: &'static str) -> IoError {
|
||||
IoError {
|
||||
kind: io::TimedOut,
|
||||
desc: desc,
|
||||
detail: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn short_write(n: uint, desc: &'static str) -> IoError {
|
||||
IoError {
|
||||
kind: if n == 0 { io::TimedOut } else { io::ShortWrite(n) },
|
||||
desc: desc,
|
||||
detail: None,
|
||||
}
|
||||
}
|
||||
|
||||
// unix has nonzero values as errors
|
||||
pub fn mkerr_libc<Int: num::Zero>(ret: Int) -> IoResult<()> {
|
||||
if !ret.is_zero() {
|
||||
Err(last_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn keep_going(data: &[u8], f: |*const u8, uint| -> i64) -> i64 {
|
||||
let origamt = data.len();
|
||||
let mut data = data.as_ptr();
|
||||
let mut amt = origamt;
|
||||
while amt > 0 {
|
||||
let ret = retry(|| f(data, amt));
|
||||
if ret == 0 {
|
||||
break
|
||||
} else if ret != -1 {
|
||||
amt -= ret as uint;
|
||||
data = unsafe { data.offset(ret as int) };
|
||||
} else {
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
return (origamt - amt) as i64;
|
||||
}
|
||||
|
||||
// traits for extracting representations from
|
||||
|
||||
pub trait AsFileDesc {
|
||||
fn as_fd(&self) -> &fs::FileDesc;
|
||||
}
|
||||
|
||||
pub trait ProcessConfig<K: BytesContainer, V: BytesContainer> {
|
||||
fn program(&self) -> &CString;
|
||||
fn args(&self) -> &[CString];
|
||||
fn env(&self) -> Option<&collections::HashMap<K, V>>;
|
||||
fn cwd(&self) -> Option<&CString>;
|
||||
fn uid(&self) -> Option<uint>;
|
||||
fn gid(&self) -> Option<uint>;
|
||||
fn detach(&self) -> bool;
|
||||
}
|
@ -11,6 +11,7 @@
|
||||
//! C definitions used by libnative that don't belong in liblibc
|
||||
|
||||
#![allow(dead_code)]
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
pub use self::select::fd_set;
|
||||
pub use self::signal::{sigaction, siginfo, sigset_t};
|
||||
@ -106,7 +107,7 @@ mod select {
|
||||
target_os = "dragonfly",
|
||||
target_os = "linux"))]
|
||||
mod select {
|
||||
use std::uint;
|
||||
use uint;
|
||||
use libc;
|
||||
|
||||
pub const FD_SETSIZE: uint = 1024;
|
92
src/libstd/sys/unix/mod.rs
Normal file
92
src/libstd/sys/unix/mod.rs
Normal file
@ -0,0 +1,92 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
extern crate libc;
|
||||
|
||||
use num;
|
||||
use prelude::*;
|
||||
use io::{mod, IoResult, IoError};
|
||||
|
||||
pub mod fs;
|
||||
pub mod os;
|
||||
pub mod c;
|
||||
|
||||
pub type sock_t = io::file::fd_t;
|
||||
pub type wrlen = libc::size_t;
|
||||
pub unsafe fn close_sock(sock: sock_t) { let _ = libc::close(sock); }
|
||||
|
||||
pub fn last_error() -> IoError {
|
||||
let errno = os::errno() as i32;
|
||||
let mut err = decode_error(errno);
|
||||
err.detail = Some(os::error_string(errno));
|
||||
err
|
||||
}
|
||||
|
||||
/// Convert an `errno` value into a high-level error variant and description.
|
||||
pub fn decode_error(errno: i32) -> IoError {
|
||||
// FIXME: this should probably be a bit more descriptive...
|
||||
let (kind, desc) = match errno {
|
||||
libc::EOF => (io::EndOfFile, "end of file"),
|
||||
libc::ECONNREFUSED => (io::ConnectionRefused, "connection refused"),
|
||||
libc::ECONNRESET => (io::ConnectionReset, "connection reset"),
|
||||
libc::EPERM | libc::EACCES =>
|
||||
(io::PermissionDenied, "permission denied"),
|
||||
libc::EPIPE => (io::BrokenPipe, "broken pipe"),
|
||||
libc::ENOTCONN => (io::NotConnected, "not connected"),
|
||||
libc::ECONNABORTED => (io::ConnectionAborted, "connection aborted"),
|
||||
libc::EADDRNOTAVAIL => (io::ConnectionRefused, "address not available"),
|
||||
libc::EADDRINUSE => (io::ConnectionRefused, "address in use"),
|
||||
libc::ENOENT => (io::FileNotFound, "no such file or directory"),
|
||||
libc::EISDIR => (io::InvalidInput, "illegal operation on a directory"),
|
||||
libc::ENOSYS => (io::IoUnavailable, "function not implemented"),
|
||||
libc::EINVAL => (io::InvalidInput, "invalid argument"),
|
||||
libc::ENOTTY =>
|
||||
(io::MismatchedFileTypeForOperation,
|
||||
"file descriptor is not a TTY"),
|
||||
libc::ETIMEDOUT => (io::TimedOut, "operation timed out"),
|
||||
libc::ECANCELED => (io::TimedOut, "operation aborted"),
|
||||
|
||||
// These two constants can have the same value on some systems,
|
||||
// but different values on others, so we can't use a match
|
||||
// clause
|
||||
x if x == libc::EAGAIN || x == libc::EWOULDBLOCK =>
|
||||
(io::ResourceUnavailable, "resource temporarily unavailable"),
|
||||
|
||||
_ => (io::OtherIoError, "unknown error")
|
||||
};
|
||||
IoError { kind: kind, desc: desc, detail: None }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn retry<I: PartialEq + num::One + Neg<I>> (f: || -> I) -> I {
|
||||
let minus_one = -num::one::<I>();
|
||||
loop {
|
||||
let n = f();
|
||||
if n == minus_one && os::errno() == libc::EINTR as int { }
|
||||
else { return n }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ms_to_timeval(ms: u64) -> libc::timeval {
|
||||
libc::timeval {
|
||||
tv_sec: (ms / 1000) as libc::time_t,
|
||||
tv_usec: ((ms % 1000) * 1000) as libc::suseconds_t,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wouldblock() -> bool {
|
||||
let err = os::errno();
|
||||
err == libc::EWOULDBLOCK as int || err == libc::EAGAIN as int
|
||||
}
|
||||
|
||||
pub fn set_nonblocking(fd: net::sock_t, nb: bool) -> IoResult<()> {
|
||||
let set = nb as libc::c_int;
|
||||
super::mkerr_libc(retry(|| unsafe { c::ioctl(fd, c::FIONBIO, &set) }))
|
||||
}
|
101
src/libstd/sys/unix/os.rs
Normal file
101
src/libstd/sys/unix/os.rs
Normal file
@ -0,0 +1,101 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use libc;
|
||||
use libc::{c_int, c_char};
|
||||
use prelude::*;
|
||||
|
||||
use os::TMPBUF_SZ;
|
||||
|
||||
/// Returns the platform-specific value of errno
|
||||
pub fn errno() -> int {
|
||||
#[cfg(any(target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "freebsd"))]
|
||||
fn errno_location() -> *const c_int {
|
||||
extern {
|
||||
fn __error() -> *const c_int;
|
||||
}
|
||||
unsafe {
|
||||
__error()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "dragonfly")]
|
||||
fn errno_location() -> *const c_int {
|
||||
extern {
|
||||
fn __dfly_error() -> *const c_int;
|
||||
}
|
||||
unsafe {
|
||||
__dfly_error()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
fn errno_location() -> *const c_int {
|
||||
extern {
|
||||
fn __errno_location() -> *const c_int;
|
||||
}
|
||||
unsafe {
|
||||
__errno_location()
|
||||
}
|
||||
}
|
||||
|
||||
unsafe {
|
||||
(*errno_location()) as int
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a detailed string description for the given error number
|
||||
pub fn error_string(errno: i32) -> String {
|
||||
#[cfg(any(target_os = "macos",
|
||||
target_os = "ios",
|
||||
target_os = "android",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly"))]
|
||||
fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: libc::size_t)
|
||||
-> c_int {
|
||||
extern {
|
||||
fn strerror_r(errnum: c_int, buf: *mut c_char,
|
||||
buflen: libc::size_t) -> c_int;
|
||||
}
|
||||
unsafe {
|
||||
strerror_r(errnum, buf, buflen)
|
||||
}
|
||||
}
|
||||
|
||||
// GNU libc provides a non-compliant version of strerror_r by default
|
||||
// and requires macros to instead use the POSIX compliant variant.
|
||||
// So we just use __xpg_strerror_r which is always POSIX compliant
|
||||
#[cfg(target_os = "linux")]
|
||||
fn strerror_r(errnum: c_int, buf: *mut c_char,
|
||||
buflen: libc::size_t) -> c_int {
|
||||
extern {
|
||||
fn __xpg_strerror_r(errnum: c_int,
|
||||
buf: *mut c_char,
|
||||
buflen: libc::size_t)
|
||||
-> c_int;
|
||||
}
|
||||
unsafe {
|
||||
__xpg_strerror_r(errnum, buf, buflen)
|
||||
}
|
||||
}
|
||||
|
||||
let mut buf = [0 as c_char, ..TMPBUF_SZ];
|
||||
|
||||
let p = buf.as_mut_ptr();
|
||||
unsafe {
|
||||
if strerror_r(errno as c_int, p, buf.len() as libc::size_t) < 0 {
|
||||
panic!("strerror_r failure");
|
||||
}
|
||||
|
||||
::string::raw::from_buf(p as *const u8)
|
||||
}
|
||||
}
|
@ -11,8 +11,11 @@
|
||||
//! C definitions used by libnative that don't belong in liblibc
|
||||
|
||||
#![allow(overflowing_literals)]
|
||||
#![allow(dead_code)]
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
use libc;
|
||||
use prelude::*;
|
||||
|
||||
pub const WSADESCRIPTION_LEN: uint = 256;
|
||||
pub const WSASYS_STATUS_LEN: uint = 128;
|
||||
@ -127,9 +130,10 @@ extern "system" {
|
||||
}
|
||||
|
||||
pub mod compat {
|
||||
use std::intrinsics::{atomic_store_relaxed, transmute};
|
||||
use std::iter::Iterator;
|
||||
use intrinsics::{atomic_store_relaxed, transmute};
|
||||
use iter::Iterator;
|
||||
use libc::types::os::arch::extra::{LPCWSTR, HMODULE, LPCSTR, LPVOID};
|
||||
use prelude::*;
|
||||
|
||||
extern "system" {
|
||||
fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE;
|
||||
@ -174,17 +178,17 @@ pub mod compat {
|
||||
|
||||
extern "system" fn thunk($($argname: $argtype),*) -> $rettype {
|
||||
unsafe {
|
||||
::io::c::compat::store_func(&mut ptr as *mut _ as *mut uint,
|
||||
::sys::c::compat::store_func(&mut ptr as *mut _ as *mut uint,
|
||||
stringify!($module),
|
||||
stringify!($symbol),
|
||||
fallback as uint);
|
||||
::std::intrinsics::atomic_load_relaxed(&ptr)($($argname),*)
|
||||
::intrinsics::atomic_load_relaxed(&ptr)($($argname),*)
|
||||
}
|
||||
}
|
||||
|
||||
extern "system" fn fallback($($argname: $argtype),*) -> $rettype $fallback
|
||||
|
||||
::std::intrinsics::atomic_load_relaxed(&ptr)($($argname),*)
|
||||
::intrinsics::atomic_load_relaxed(&ptr)($($argname),*)
|
||||
}
|
||||
);
|
||||
|
178
src/libstd/sys/windows/mod.rs
Normal file
178
src/libstd/sys/windows/mod.rs
Normal file
@ -0,0 +1,178 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
#![allow(missing_doc)]
|
||||
#![allow(non_camel_case_types)]
|
||||
#![allow(non_snake_case)]
|
||||
#![allow(unused_imports)]
|
||||
#![allow(dead_code)]
|
||||
#![allow(unused_unsafe)]
|
||||
#![allow(unused_mut)]
|
||||
|
||||
extern crate libc;
|
||||
|
||||
use num;
|
||||
use mem;
|
||||
use prelude::*;
|
||||
use io::{mod, IoResult, IoError};
|
||||
use sync::{Once, ONCE_INIT};
|
||||
|
||||
macro_rules! helper_init( (static $name:ident: Helper<$m:ty>) => (
|
||||
static $name: Helper<$m> = Helper {
|
||||
lock: ::rt::mutex::NATIVE_MUTEX_INIT,
|
||||
chan: ::cell::UnsafeCell { value: 0 as *mut Sender<$m> },
|
||||
signal: ::cell::UnsafeCell { value: 0 },
|
||||
initialized: ::cell::UnsafeCell { value: false },
|
||||
};
|
||||
) )
|
||||
|
||||
pub mod fs;
|
||||
pub mod os;
|
||||
pub mod c;
|
||||
|
||||
pub type sock_t = libc::SOCKET;
|
||||
pub type wrlen = libc::c_int;
|
||||
pub unsafe fn close_sock(sock: sock_t) { let _ = libc::closesocket(sock); }
|
||||
|
||||
// windows has zero values as errors
|
||||
fn mkerr_winbool(ret: libc::c_int) -> IoResult<()> {
|
||||
if ret == 0 {
|
||||
Err(last_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn last_error() -> IoError {
|
||||
let errno = os::errno() as i32;
|
||||
let mut err = decode_error(errno);
|
||||
err.detail = Some(os::error_string(errno));
|
||||
err
|
||||
}
|
||||
|
||||
pub fn last_net_error() -> IoError {
|
||||
let errno = unsafe { c::WSAGetLastError() as i32 };
|
||||
let mut err = decode_error(errno);
|
||||
err.detail = Some(os::error_string(errno));
|
||||
err
|
||||
}
|
||||
|
||||
pub fn last_gai_error(_errno: i32) -> IoError {
|
||||
last_net_error()
|
||||
}
|
||||
|
||||
/// Convert an `errno` value into a high-level error variant and description.
|
||||
pub fn decode_error(errno: i32) -> IoError {
|
||||
let (kind, desc) = match errno {
|
||||
libc::EOF => (io::EndOfFile, "end of file"),
|
||||
libc::ERROR_NO_DATA => (io::BrokenPipe, "the pipe is being closed"),
|
||||
libc::ERROR_FILE_NOT_FOUND => (io::FileNotFound, "file not found"),
|
||||
libc::ERROR_INVALID_NAME => (io::InvalidInput, "invalid file name"),
|
||||
libc::WSAECONNREFUSED => (io::ConnectionRefused, "connection refused"),
|
||||
libc::WSAECONNRESET => (io::ConnectionReset, "connection reset"),
|
||||
libc::ERROR_ACCESS_DENIED | libc::WSAEACCES =>
|
||||
(io::PermissionDenied, "permission denied"),
|
||||
libc::WSAEWOULDBLOCK => {
|
||||
(io::ResourceUnavailable, "resource temporarily unavailable")
|
||||
}
|
||||
libc::WSAENOTCONN => (io::NotConnected, "not connected"),
|
||||
libc::WSAECONNABORTED => (io::ConnectionAborted, "connection aborted"),
|
||||
libc::WSAEADDRNOTAVAIL => (io::ConnectionRefused, "address not available"),
|
||||
libc::WSAEADDRINUSE => (io::ConnectionRefused, "address in use"),
|
||||
libc::ERROR_BROKEN_PIPE => (io::EndOfFile, "the pipe has ended"),
|
||||
libc::ERROR_OPERATION_ABORTED =>
|
||||
(io::TimedOut, "operation timed out"),
|
||||
libc::WSAEINVAL => (io::InvalidInput, "invalid argument"),
|
||||
libc::ERROR_CALL_NOT_IMPLEMENTED =>
|
||||
(io::IoUnavailable, "function not implemented"),
|
||||
libc::ERROR_INVALID_HANDLE =>
|
||||
(io::MismatchedFileTypeForOperation,
|
||||
"invalid handle provided to function"),
|
||||
libc::ERROR_NOTHING_TO_TERMINATE =>
|
||||
(io::InvalidInput, "no process to kill"),
|
||||
|
||||
// libuv maps this error code to EISDIR. we do too. if it is found
|
||||
// to be incorrect, we can add in some more machinery to only
|
||||
// return this message when ERROR_INVALID_FUNCTION after certain
|
||||
// Windows calls.
|
||||
libc::ERROR_INVALID_FUNCTION => (io::InvalidInput,
|
||||
"illegal operation on a directory"),
|
||||
|
||||
_ => (io::OtherIoError, "unknown error")
|
||||
};
|
||||
IoError { kind: kind, desc: desc, detail: None }
|
||||
}
|
||||
|
||||
pub fn decode_error_detailed(errno: i32) -> IoError {
|
||||
let mut err = decode_error(errno);
|
||||
err.detail = Some(os::error_string(errno));
|
||||
err
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn retry<I> (f: || -> I) -> I { f() } // PR rust-lang/rust/#17020
|
||||
|
||||
pub fn ms_to_timeval(ms: u64) -> libc::timeval {
|
||||
libc::timeval {
|
||||
tv_sec: (ms / 1000) as libc::c_long,
|
||||
tv_usec: ((ms % 1000) * 1000) as libc::c_long,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wouldblock() -> bool {
|
||||
let err = os::errno();
|
||||
err == libc::WSAEWOULDBLOCK as uint
|
||||
}
|
||||
|
||||
pub fn set_nonblocking(fd: sock_t, nb: bool) -> IoResult<()> {
|
||||
let mut set = nb as libc::c_ulong;
|
||||
if unsafe { c::ioctlsocket(fd, c::FIONBIO, &mut set) != 0 } {
|
||||
Err(last_error())
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME: call this
|
||||
pub fn init_net() {
|
||||
unsafe {
|
||||
static START: Once = ONCE_INIT;
|
||||
|
||||
START.doit(|| {
|
||||
let mut data: c::WSADATA = mem::zeroed();
|
||||
let ret = c::WSAStartup(0x202, // version 2.2
|
||||
&mut data);
|
||||
assert_eq!(ret, 0);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unimpl() -> IoError {
|
||||
IoError {
|
||||
kind: io::IoUnavailable,
|
||||
desc: "operation is not implemented",
|
||||
detail: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn to_utf16(s: Option<&str>) -> IoResult<Vec<u16>> {
|
||||
match s {
|
||||
Some(s) => Ok({
|
||||
let mut s = s.utf16_units().collect::<Vec<u16>>();
|
||||
s.push(0);
|
||||
s
|
||||
}),
|
||||
None => Err(IoError {
|
||||
kind: io::InvalidInput,
|
||||
desc: "valid unicode input required",
|
||||
detail: None
|
||||
})
|
||||
}
|
||||
}
|
103
src/libstd/sys/windows/os.rs
Normal file
103
src/libstd/sys/windows/os.rs
Normal file
@ -0,0 +1,103 @@
|
||||
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||
// file at the top-level directory of this distribution and at
|
||||
// http://rust-lang.org/COPYRIGHT.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
// FIXME: move various extern bindings from here into liblibc or
|
||||
// something similar
|
||||
|
||||
use libc;
|
||||
use libc::{c_int, c_char, c_void};
|
||||
use prelude::*;
|
||||
use io::{IoResult, IoError};
|
||||
use sys::fs::FileDesc;
|
||||
use ptr;
|
||||
|
||||
use os::TMPBUF_SZ;
|
||||
|
||||
pub fn errno() -> uint {
|
||||
use libc::types::os::arch::extra::DWORD;
|
||||
|
||||
#[link_name = "kernel32"]
|
||||
extern "system" {
|
||||
fn GetLastError() -> DWORD;
|
||||
}
|
||||
|
||||
unsafe {
|
||||
GetLastError() as uint
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a detailed string description for the given error number
|
||||
pub fn error_string(errnum: i32) -> String {
|
||||
use libc::types::os::arch::extra::DWORD;
|
||||
use libc::types::os::arch::extra::LPWSTR;
|
||||
use libc::types::os::arch::extra::LPVOID;
|
||||
use libc::types::os::arch::extra::WCHAR;
|
||||
|
||||
#[link_name = "kernel32"]
|
||||
extern "system" {
|
||||
fn FormatMessageW(flags: DWORD,
|
||||
lpSrc: LPVOID,
|
||||
msgId: DWORD,
|
||||
langId: DWORD,
|
||||
buf: LPWSTR,
|
||||
nsize: DWORD,
|
||||
args: *const c_void)
|
||||
-> DWORD;
|
||||
}
|
||||
|
||||
static FORMAT_MESSAGE_FROM_SYSTEM: DWORD = 0x00001000;
|
||||
static FORMAT_MESSAGE_IGNORE_INSERTS: DWORD = 0x00000200;
|
||||
|
||||
// This value is calculated from the macro
|
||||
// MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT)
|
||||
let langId = 0x0800 as DWORD;
|
||||
|
||||
let mut buf = [0 as WCHAR, ..TMPBUF_SZ];
|
||||
|
||||
unsafe {
|
||||
let res = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
ptr::null_mut(),
|
||||
errnum as DWORD,
|
||||
langId,
|
||||
buf.as_mut_ptr(),
|
||||
buf.len() as DWORD,
|
||||
ptr::null());
|
||||
if res == 0 {
|
||||
// Sometimes FormatMessageW can fail e.g. system doesn't like langId,
|
||||
let fm_err = errno();
|
||||
return format!("OS Error {} (FormatMessageW() returned error {})", errnum, fm_err);
|
||||
}
|
||||
|
||||
let msg = String::from_utf16(::str::truncate_utf16_at_nul(buf));
|
||||
match msg {
|
||||
Some(msg) => format!("OS Error {}: {}", errnum, msg),
|
||||
None => format!("OS Error {} (FormatMessageW() returned invalid UTF-16)", errnum),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn pipe() -> IoResult<(FileDesc, FileDesc)> {
|
||||
// Windows pipes work subtly differently than unix pipes, and their
|
||||
// inheritance has to be handled in a different way that I do not
|
||||
// fully understand. Here we explicitly make the pipe non-inheritable,
|
||||
// which means to pass it to a subprocess they need to be duplicated
|
||||
// first, as in std::run.
|
||||
let mut fds = [0, ..2];
|
||||
match libc::pipe(fds.as_mut_ptr(), 1024 as ::libc::c_uint,
|
||||
(libc::O_BINARY | libc::O_NOINHERIT) as c_int) {
|
||||
0 => {
|
||||
assert!(fds[0] != -1 && fds[0] != 0);
|
||||
assert!(fds[1] != -1 && fds[1] != 0);
|
||||
Ok((FileDesc::new(fds[0], true), FileDesc::new(fds[1], true)))
|
||||
}
|
||||
_ => Err(IoError::last_error()),
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user