std: migrate the errno -> IoError converter from libnative.
This also adds a direct `errno` -> `~str` converter, rather than only being possible to get a string for the very last error.
This commit is contained in:
@@ -96,10 +96,8 @@ extern "system" {
|
|||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
fn get_error(_: c_int) -> IoError {
|
fn get_error(_: c_int) -> IoError {
|
||||||
use super::translate_error;
|
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
translate_error(WSAGetLastError() as i32, true)
|
IoError::from_errno(WSAGetLastError() as uint, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -86,73 +86,10 @@ fn unimpl() -> IoError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn translate_error(errno: i32, detail: bool) -> IoError {
|
fn last_error() -> IoError {
|
||||||
#[cfg(windows)]
|
IoError::last_error()
|
||||||
fn get_err(errno: i32) -> (io::IoErrorKind, &'static str) {
|
|
||||||
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::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"),
|
|
||||||
|
|
||||||
// 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
|
|
||||||
// win32 calls.
|
|
||||||
libc::ERROR_INVALID_FUNCTION => (io::InvalidInput,
|
|
||||||
"illegal operation on a directory"),
|
|
||||||
|
|
||||||
_ => (io::OtherIoError, "unknown error")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(windows))]
|
|
||||||
fn get_err(errno: i32) -> (io::IoErrorKind, &'static str) {
|
|
||||||
// FIXME: this should probably be a bit more descriptive...
|
|
||||||
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"),
|
|
||||||
|
|
||||||
// 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")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let (kind, desc) = get_err(errno);
|
|
||||||
IoError {
|
|
||||||
kind: kind,
|
|
||||||
desc: desc,
|
|
||||||
detail: if detail {Some(os::last_os_error())} else {None},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn last_error() -> IoError { translate_error(os::errno() as i32, true) }
|
|
||||||
|
|
||||||
// unix has nonzero values as errors
|
// unix has nonzero values as errors
|
||||||
fn mkerr_libc(ret: libc::c_int) -> IoResult<()> {
|
fn mkerr_libc(ret: libc::c_int) -> IoResult<()> {
|
||||||
if ret != 0 {
|
if ret != 0 {
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ fn last_error() -> io::IoError {
|
|||||||
extern "system" {
|
extern "system" {
|
||||||
fn WSAGetLastError() -> libc::c_int;
|
fn WSAGetLastError() -> libc::c_int;
|
||||||
}
|
}
|
||||||
super::translate_error(unsafe { WSAGetLastError() }, true)
|
io::IoError::from_errno(unsafe { WSAGetLastError() } as uint, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
|
|||||||
@@ -469,7 +469,7 @@ fn spawn_process_os(config: p::ProcessConfig,
|
|||||||
(bytes[1] << 16) as i32 |
|
(bytes[1] << 16) as i32 |
|
||||||
(bytes[2] << 8) as i32 |
|
(bytes[2] << 8) as i32 |
|
||||||
(bytes[3] << 0) as i32;
|
(bytes[3] << 0) as i32;
|
||||||
Err(super::translate_error(errno, false))
|
Err(io::IoError::from_errno(errno as uint, false))
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
assert!(e.kind == io::BrokenPipe ||
|
assert!(e.kind == io::BrokenPipe ||
|
||||||
|
|||||||
@@ -216,6 +216,8 @@ use container::Container;
|
|||||||
use fmt;
|
use fmt;
|
||||||
use int;
|
use int;
|
||||||
use iter::Iterator;
|
use iter::Iterator;
|
||||||
|
use libc;
|
||||||
|
use os;
|
||||||
use option::{Option, Some, None};
|
use option::{Option, Some, None};
|
||||||
use path::Path;
|
use path::Path;
|
||||||
use result::{Ok, Err, Result};
|
use result::{Ok, Err, Result};
|
||||||
@@ -290,6 +292,88 @@ pub struct IoError {
|
|||||||
detail: Option<~str>
|
detail: Option<~str>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl IoError {
|
||||||
|
/// Convert an `errno` value into an `IoError`.
|
||||||
|
///
|
||||||
|
/// If `detail` is `true`, the `detail` field of the `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::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"),
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// win32 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"),
|
||||||
|
|
||||||
|
// 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 {Some(os::error_string(errno))} else {None},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Retrieve the last error to occur as a (detailed) IoError.
|
||||||
|
///
|
||||||
|
/// This uses the OS `errno`, and so there should not be any task
|
||||||
|
/// descheduling or migration (other than that performed by the
|
||||||
|
/// operating system) between the call(s) for which errors are
|
||||||
|
/// being checked and the call of this function.
|
||||||
|
pub fn last_error() -> IoError {
|
||||||
|
IoError::from_errno(os::errno() as uint, true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Show for IoError {
|
impl fmt::Show for IoError {
|
||||||
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
|
||||||
try!(fmt.buf.write_str(self.desc));
|
try!(fmt.buf.write_str(self.desc));
|
||||||
|
|||||||
@@ -663,10 +663,12 @@ pub fn errno() -> uint {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a string representing the platform-dependent last error
|
/// Return the string corresponding to an `errno()` value of `errnum`.
|
||||||
pub fn last_os_error() -> ~str {
|
pub fn error_string(errnum: uint) -> ~str {
|
||||||
|
return strerror(errnum);
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
fn strerror() -> ~str {
|
fn strerror(errnum: uint) -> ~str {
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
#[cfg(target_os = "android")]
|
#[cfg(target_os = "android")]
|
||||||
#[cfg(target_os = "freebsd")]
|
#[cfg(target_os = "freebsd")]
|
||||||
@@ -702,7 +704,7 @@ pub fn last_os_error() -> ~str {
|
|||||||
|
|
||||||
let p = buf.as_mut_ptr();
|
let p = buf.as_mut_ptr();
|
||||||
unsafe {
|
unsafe {
|
||||||
if strerror_r(errno() as c_int, p, buf.len() as libc::size_t) < 0 {
|
if strerror_r(errnum as c_int, p, buf.len() as libc::size_t) < 0 {
|
||||||
fail!("strerror_r failure");
|
fail!("strerror_r failure");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -711,7 +713,7 @@ pub fn last_os_error() -> ~str {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
fn strerror() -> ~str {
|
fn strerror(errnum: uint) -> ~str {
|
||||||
use libc::types::os::arch::extra::DWORD;
|
use libc::types::os::arch::extra::DWORD;
|
||||||
use libc::types::os::arch::extra::LPWSTR;
|
use libc::types::os::arch::extra::LPWSTR;
|
||||||
use libc::types::os::arch::extra::LPVOID;
|
use libc::types::os::arch::extra::LPVOID;
|
||||||
@@ -735,7 +737,6 @@ pub fn last_os_error() -> ~str {
|
|||||||
// This value is calculated from the macro
|
// This value is calculated from the macro
|
||||||
// MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT)
|
// MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT)
|
||||||
let langId = 0x0800 as DWORD;
|
let langId = 0x0800 as DWORD;
|
||||||
let err = errno() as DWORD;
|
|
||||||
|
|
||||||
let mut buf = [0 as WCHAR, ..TMPBUF_SZ];
|
let mut buf = [0 as WCHAR, ..TMPBUF_SZ];
|
||||||
|
|
||||||
@@ -743,7 +744,7 @@ pub fn last_os_error() -> ~str {
|
|||||||
let res = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM |
|
let res = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM |
|
||||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||||
ptr::mut_null(),
|
ptr::mut_null(),
|
||||||
err,
|
errnum as DWORD,
|
||||||
langId,
|
langId,
|
||||||
buf.as_mut_ptr(),
|
buf.as_mut_ptr(),
|
||||||
buf.len() as DWORD,
|
buf.len() as DWORD,
|
||||||
@@ -751,18 +752,21 @@ pub fn last_os_error() -> ~str {
|
|||||||
if res == 0 {
|
if res == 0 {
|
||||||
// Sometimes FormatMessageW can fail e.g. system doesn't like langId,
|
// Sometimes FormatMessageW can fail e.g. system doesn't like langId,
|
||||||
let fm_err = errno();
|
let fm_err = errno();
|
||||||
return format!("OS Error {} (FormatMessageW() returned error {})", err, fm_err);
|
return format!("OS Error {} (FormatMessageW() returned error {})", errnum, fm_err);
|
||||||
}
|
}
|
||||||
|
|
||||||
let msg = str::from_utf16(str::truncate_utf16_at_nul(buf));
|
let msg = str::from_utf16(str::truncate_utf16_at_nul(buf));
|
||||||
match msg {
|
match msg {
|
||||||
Some(msg) => format!("OS Error {}: {}", err, msg),
|
Some(msg) => format!("OS Error {}: {}", errnum, msg),
|
||||||
None => format!("OS Error {} (FormatMessageW() returned invalid UTF-16)", err),
|
None => format!("OS Error {} (FormatMessageW() returned invalid UTF-16)", errnum),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
strerror()
|
/// Get a string representing the platform-dependent last error
|
||||||
|
pub fn last_os_error() -> ~str {
|
||||||
|
error_string(errno() as uint)
|
||||||
}
|
}
|
||||||
|
|
||||||
static mut EXIT_STATUS: AtomicInt = INIT_ATOMIC_INT;
|
static mut EXIT_STATUS: AtomicInt = INIT_ATOMIC_INT;
|
||||||
|
|||||||
Reference in New Issue
Block a user