Skip to content

Commit 119289b

Browse files
committed
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.
1 parent c329a17 commit 119289b

File tree

6 files changed

+104
-81
lines changed

6 files changed

+104
-81
lines changed

src/libnative/io/addrinfo.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,8 @@ extern "system" {
9696

9797
#[cfg(windows)]
9898
fn get_error(_: c_int) -> IoError {
99-
use super::translate_error;
100-
10199
unsafe {
102-
translate_error(WSAGetLastError() as i32, true)
100+
IoError::from_errno(WSAGetLastError() as uint, true)
103101
}
104102
}
105103

src/libnative/io/mod.rs

Lines changed: 2 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -86,73 +86,10 @@ fn unimpl() -> IoError {
8686
}
8787
}
8888

89-
fn translate_error(errno: i32, detail: bool) -> IoError {
90-
#[cfg(windows)]
91-
fn get_err(errno: i32) -> (io::IoErrorKind, &'static str) {
92-
match errno {
93-
libc::EOF => (io::EndOfFile, "end of file"),
94-
libc::ERROR_NO_DATA => (io::BrokenPipe, "the pipe is being closed"),
95-
libc::ERROR_FILE_NOT_FOUND => (io::FileNotFound, "file not found"),
96-
libc::ERROR_INVALID_NAME => (io::InvalidInput, "invalid file name"),
97-
libc::WSAECONNREFUSED => (io::ConnectionRefused, "connection refused"),
98-
libc::WSAECONNRESET => (io::ConnectionReset, "connection reset"),
99-
libc::WSAEACCES => (io::PermissionDenied, "permission denied"),
100-
libc::WSAEWOULDBLOCK => {
101-
(io::ResourceUnavailable, "resource temporarily unavailable")
102-
}
103-
libc::WSAENOTCONN => (io::NotConnected, "not connected"),
104-
libc::WSAECONNABORTED => (io::ConnectionAborted, "connection aborted"),
105-
libc::WSAEADDRNOTAVAIL => (io::ConnectionRefused, "address not available"),
106-
libc::WSAEADDRINUSE => (io::ConnectionRefused, "address in use"),
107-
libc::ERROR_BROKEN_PIPE => (io::EndOfFile, "the pipe has ended"),
108-
109-
// libuv maps this error code to EISDIR. we do too. if it is found
110-
// to be incorrect, we can add in some more machinery to only
111-
// return this message when ERROR_INVALID_FUNCTION after certain
112-
// win32 calls.
113-
libc::ERROR_INVALID_FUNCTION => (io::InvalidInput,
114-
"illegal operation on a directory"),
115-
116-
_ => (io::OtherIoError, "unknown error")
117-
}
118-
}
119-
120-
#[cfg(not(windows))]
121-
fn get_err(errno: i32) -> (io::IoErrorKind, &'static str) {
122-
// FIXME: this should probably be a bit more descriptive...
123-
match errno {
124-
libc::EOF => (io::EndOfFile, "end of file"),
125-
libc::ECONNREFUSED => (io::ConnectionRefused, "connection refused"),
126-
libc::ECONNRESET => (io::ConnectionReset, "connection reset"),
127-
libc::EPERM | libc::EACCES =>
128-
(io::PermissionDenied, "permission denied"),
129-
libc::EPIPE => (io::BrokenPipe, "broken pipe"),
130-
libc::ENOTCONN => (io::NotConnected, "not connected"),
131-
libc::ECONNABORTED => (io::ConnectionAborted, "connection aborted"),
132-
libc::EADDRNOTAVAIL => (io::ConnectionRefused, "address not available"),
133-
libc::EADDRINUSE => (io::ConnectionRefused, "address in use"),
134-
libc::ENOENT => (io::FileNotFound, "no such file or directory"),
135-
libc::EISDIR => (io::InvalidInput, "illegal operation on a directory"),
136-
137-
// These two constants can have the same value on some systems, but
138-
// different values on others, so we can't use a match clause
139-
x if x == libc::EAGAIN || x == libc::EWOULDBLOCK =>
140-
(io::ResourceUnavailable, "resource temporarily unavailable"),
141-
142-
_ => (io::OtherIoError, "unknown error")
143-
}
144-
}
145-
146-
let (kind, desc) = get_err(errno);
147-
IoError {
148-
kind: kind,
149-
desc: desc,
150-
detail: if detail {Some(os::last_os_error())} else {None},
151-
}
89+
fn last_error() -> IoError {
90+
IoError::last_error()
15291
}
15392

154-
fn last_error() -> IoError { translate_error(os::errno() as i32, true) }
155-
15693
// unix has nonzero values as errors
15794
fn mkerr_libc(ret: libc::c_int) -> IoResult<()> {
15895
if ret != 0 {

src/libnative/io/net.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ fn last_error() -> io::IoError {
120120
extern "system" {
121121
fn WSAGetLastError() -> libc::c_int;
122122
}
123-
super::translate_error(unsafe { WSAGetLastError() }, true)
123+
io::IoError::from_errno(unsafe { WSAGetLastError() } as uint, true)
124124
}
125125

126126
#[cfg(not(windows))]

src/libnative/io/process.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,7 @@ fn spawn_process_os(config: p::ProcessConfig,
469469
(bytes[1] << 16) as i32 |
470470
(bytes[2] << 8) as i32 |
471471
(bytes[3] << 0) as i32;
472-
Err(super::translate_error(errno, false))
472+
Err(io::IoError::from_errno(errno as uint, false))
473473
}
474474
Err(e) => {
475475
assert!(e.kind == io::BrokenPipe ||

src/libstd/io/mod.rs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,8 @@ use container::Container;
216216
use fmt;
217217
use int;
218218
use iter::Iterator;
219+
use libc;
220+
use os;
219221
use option::{Option, Some, None};
220222
use path::Path;
221223
use result::{Ok, Err, Result};
@@ -290,6 +292,88 @@ pub struct IoError {
290292
detail: Option<~str>
291293
}
292294

295+
impl IoError {
296+
/// Convert an `errno` value into an `IoError`.
297+
///
298+
/// If `detail` is `true`, the `detail` field of the `IoError`
299+
/// struct is filled with an allocated string describing the error
300+
/// in more detail, retrieved from the operating system.
301+
pub fn from_errno(errno: uint, detail: bool) -> IoError {
302+
#[cfg(windows)]
303+
fn get_err(errno: i32) -> (IoErrorKind, &'static str) {
304+
match errno {
305+
libc::EOF => (EndOfFile, "end of file"),
306+
libc::ERROR_NO_DATA => (BrokenPipe, "the pipe is being closed"),
307+
libc::ERROR_FILE_NOT_FOUND => (FileNotFound, "file not found"),
308+
libc::ERROR_INVALID_NAME => (InvalidInput, "invalid file name"),
309+
libc::WSAECONNREFUSED => (ConnectionRefused, "connection refused"),
310+
libc::WSAECONNRESET => (ConnectionReset, "connection reset"),
311+
libc::WSAEACCES => (PermissionDenied, "permission denied"),
312+
libc::WSAEWOULDBLOCK => {
313+
(ResourceUnavailable, "resource temporarily unavailable")
314+
}
315+
libc::WSAENOTCONN => (NotConnected, "not connected"),
316+
libc::WSAECONNABORTED => (ConnectionAborted, "connection aborted"),
317+
libc::WSAEADDRNOTAVAIL => (ConnectionRefused, "address not available"),
318+
libc::WSAEADDRINUSE => (ConnectionRefused, "address in use"),
319+
libc::ERROR_BROKEN_PIPE => (EndOfFile, "the pipe has ended"),
320+
321+
// libuv maps this error code to EISDIR. we do too. if it is found
322+
// to be incorrect, we can add in some more machinery to only
323+
// return this message when ERROR_INVALID_FUNCTION after certain
324+
// win32 calls.
325+
libc::ERROR_INVALID_FUNCTION => (InvalidInput,
326+
"illegal operation on a directory"),
327+
328+
_ => (OtherIoError, "unknown error")
329+
}
330+
}
331+
332+
#[cfg(not(windows))]
333+
fn get_err(errno: i32) -> (IoErrorKind, &'static str) {
334+
// FIXME: this should probably be a bit more descriptive...
335+
match errno {
336+
libc::EOF => (EndOfFile, "end of file"),
337+
libc::ECONNREFUSED => (ConnectionRefused, "connection refused"),
338+
libc::ECONNRESET => (ConnectionReset, "connection reset"),
339+
libc::EPERM | libc::EACCES =>
340+
(PermissionDenied, "permission denied"),
341+
libc::EPIPE => (BrokenPipe, "broken pipe"),
342+
libc::ENOTCONN => (NotConnected, "not connected"),
343+
libc::ECONNABORTED => (ConnectionAborted, "connection aborted"),
344+
libc::EADDRNOTAVAIL => (ConnectionRefused, "address not available"),
345+
libc::EADDRINUSE => (ConnectionRefused, "address in use"),
346+
libc::ENOENT => (FileNotFound, "no such file or directory"),
347+
libc::EISDIR => (InvalidInput, "illegal operation on a directory"),
348+
349+
// These two constants can have the same value on some systems, but
350+
// different values on others, so we can't use a match clause
351+
x if x == libc::EAGAIN || x == libc::EWOULDBLOCK =>
352+
(ResourceUnavailable, "resource temporarily unavailable"),
353+
354+
_ => (OtherIoError, "unknown error")
355+
}
356+
}
357+
358+
let (kind, desc) = get_err(errno as i32);
359+
IoError {
360+
kind: kind,
361+
desc: desc,
362+
detail: if detail {Some(os::error_string(errno))} else {None},
363+
}
364+
}
365+
366+
/// Retrieve the last error to occur as a (detailed) IoError.
367+
///
368+
/// This uses the OS `errno`, and so there should not be any task
369+
/// descheduling or migration (other than that performed by the
370+
/// operating system) between the call(s) for which errors are
371+
/// being checked and the call of this function.
372+
pub fn last_error() -> IoError {
373+
IoError::from_errno(os::errno() as uint, true)
374+
}
375+
}
376+
293377
impl fmt::Show for IoError {
294378
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
295379
try!(fmt.buf.write_str(self.desc));

src/libstd/os.rs

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -663,10 +663,12 @@ pub fn errno() -> uint {
663663
}
664664
}
665665

666-
/// Get a string representing the platform-dependent last error
667-
pub fn last_os_error() -> ~str {
666+
/// Return the string corresponding to an `errno()` value of `errnum`.
667+
pub fn error_string(errnum: uint) -> ~str {
668+
return strerror(errnum);
669+
668670
#[cfg(unix)]
669-
fn strerror() -> ~str {
671+
fn strerror(errnum: uint) -> ~str {
670672
#[cfg(target_os = "macos")]
671673
#[cfg(target_os = "android")]
672674
#[cfg(target_os = "freebsd")]
@@ -702,7 +704,7 @@ pub fn last_os_error() -> ~str {
702704

703705
let p = buf.as_mut_ptr();
704706
unsafe {
705-
if strerror_r(errno() as c_int, p, buf.len() as libc::size_t) < 0 {
707+
if strerror_r(errnum as c_int, p, buf.len() as libc::size_t) < 0 {
706708
fail!("strerror_r failure");
707709
}
708710

@@ -711,7 +713,7 @@ pub fn last_os_error() -> ~str {
711713
}
712714

713715
#[cfg(windows)]
714-
fn strerror() -> ~str {
716+
fn strerror(errnum: uint) -> ~str {
715717
use libc::types::os::arch::extra::DWORD;
716718
use libc::types::os::arch::extra::LPWSTR;
717719
use libc::types::os::arch::extra::LPVOID;
@@ -735,34 +737,36 @@ pub fn last_os_error() -> ~str {
735737
// This value is calculated from the macro
736738
// MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT)
737739
let langId = 0x0800 as DWORD;
738-
let err = errno() as DWORD;
739740

740741
let mut buf = [0 as WCHAR, ..TMPBUF_SZ];
741742

742743
unsafe {
743744
let res = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM |
744745
FORMAT_MESSAGE_IGNORE_INSERTS,
745746
ptr::mut_null(),
746-
err,
747+
errnum as DWORD,
747748
langId,
748749
buf.as_mut_ptr(),
749750
buf.len() as DWORD,
750751
ptr::null());
751752
if res == 0 {
752753
// Sometimes FormatMessageW can fail e.g. system doesn't like langId,
753754
let fm_err = errno();
754-
return format!("OS Error {} (FormatMessageW() returned error {})", err, fm_err);
755+
return format!("OS Error {} (FormatMessageW() returned error {})", errnum, fm_err);
755756
}
756757

757758
let msg = str::from_utf16(str::truncate_utf16_at_nul(buf));
758759
match msg {
759-
Some(msg) => format!("OS Error {}: {}", err, msg),
760-
None => format!("OS Error {} (FormatMessageW() returned invalid UTF-16)", err),
760+
Some(msg) => format!("OS Error {}: {}", errnum, msg),
761+
None => format!("OS Error {} (FormatMessageW() returned invalid UTF-16)", errnum),
761762
}
762763
}
763764
}
765+
}
764766

765-
strerror()
767+
/// Get a string representing the platform-dependent last error
768+
pub fn last_os_error() -> ~str {
769+
error_string(errno() as uint)
766770
}
767771

768772
static mut EXIT_STATUS: AtomicInt = INIT_ATOMIC_INT;

0 commit comments

Comments
 (0)