From 9877d98b8f91be7e1494e84d685882996b84c877 Mon Sep 17 00:00:00 2001 From: Luqman Aden Date: Mon, 11 Feb 2013 20:07:25 -0500 Subject: [PATCH] core: Rewrite last_os_error in Rust for unix and provide access to errno (unix) and GetLastError (windows). --- src/libcore/os.rs | 112 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 103 insertions(+), 9 deletions(-) diff --git a/src/libcore/os.rs b/src/libcore/os.rs index 38469c35cfa6..8abbce0649d1 100644 --- a/src/libcore/os.rs +++ b/src/libcore/os.rs @@ -66,7 +66,7 @@ extern mod rustrt { unsafe fn rust_set_exit_status(code: libc::intptr_t); } -pub const tmpbuf_sz : uint = 1000u; +pub const TMPBUF_SZ : uint = 1000u; pub fn getcwd() -> Path { unsafe { @@ -80,7 +80,7 @@ pub fn as_c_charp(s: &str, f: fn(*c_char) -> T) -> T { pub fn fill_charp_buf(f: fn(*mut c_char, size_t) -> bool) -> Option<~str> { - let buf = vec::cast_to_mut(vec::from_elem(tmpbuf_sz, 0u8 as c_char)); + let buf = vec::cast_to_mut(vec::from_elem(TMPBUF_SZ, 0u8 as c_char)); do vec::as_mut_buf(buf) |b, sz| { if f(b, sz as size_t) { unsafe { @@ -99,19 +99,19 @@ pub mod win32 { use str; use option::{None, Option}; use option; - use os::tmpbuf_sz; + use os::TMPBUF_SZ; use libc::types::os::arch::extra::DWORD; pub fn fill_utf16_buf_and_decode(f: fn(*mut u16, DWORD) -> DWORD) -> Option<~str> { unsafe { - let mut n = tmpbuf_sz as DWORD; + let mut n = TMPBUF_SZ as DWORD; let mut res = None; let mut done = false; while !done { let buf = vec::cast_to_mut(vec::from_elem(n as uint, 0u16)); do vec::as_mut_buf(buf) |b, _sz| { - let k : DWORD = f(b, tmpbuf_sz as DWORD); + let k : DWORD = f(b, TMPBUF_SZ as DWORD); if k == (0 as DWORD) { done = true; } else if (k == n && @@ -387,11 +387,11 @@ pub fn self_exe_path() -> Option { unsafe { use libc::funcs::posix01::unistd::readlink; - let mut path_str = str::with_capacity(tmpbuf_sz); + let mut path_str = str::with_capacity(TMPBUF_SZ); let len = do str::as_c_str(path_str) |buf| { let buf = buf as *mut c_char; do as_c_charp("/proc/self/exe") |proc_self_buf| { - readlink(proc_self_buf, buf, tmpbuf_sz as size_t) + readlink(proc_self_buf, buf, TMPBUF_SZ as size_t) } }; if len == -1 { @@ -766,11 +766,105 @@ pub fn remove_file(p: &Path) -> bool { } } +#[cfg(unix)] +pub fn errno() -> int { + #[cfg(target_os = "macos")] + #[cfg(target_os = "freebsd")] + fn errno_location() -> *c_int { + #[nolink] + extern { + unsafe fn __error() -> *c_int; + } + unsafe { + __error() + } + } + + #[cfg(target_os = "linux")] + #[cfg(target_os = "android")] + fn errno_location() -> *c_int { + #[nolink] + extern { + unsafe fn __errno_location() -> *c_int; + } + unsafe { + __errno_location() + } + } + + unsafe { + (*errno_location()) as int + } +} + +#[cfg(windows)] +pub fn errno() -> uint { + use libc::types::os::arch::extra::DWORD; + + #[link_name = "kernel32"] + #[abi = "stdcall"] + extern { + unsafe fn GetLastError() -> DWORD; + } + + unsafe { + GetLastError() as uint; + } +} + /// Get a string representing the platform-dependent last error pub fn last_os_error() -> ~str { - unsafe { - rustrt::last_os_error() + #[cfg(unix)] + fn strerror() -> ~str { + #[cfg(target_os = "macos")] + #[cfg(target_os = "android")] + #[cfg(target_os = "freebsd")] + fn strerror_r(errnum: c_int, buf: *c_char, buflen: size_t) -> c_int { + #[nolink] + extern { + unsafe fn strerror_r(errnum: c_int, buf: *c_char, + buflen: 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 instead we just use __xpg_strerror_r which is always POSIX compliant + #[cfg(target_os = "linux")] + fn strerror_r(errnum: c_int, buf: *c_char, buflen: size_t) -> c_int { + #[nolink] + extern { + unsafe fn __xpg_strerror_r(errnum: c_int, buf: *c_char, + buflen: size_t) -> c_int; + } + unsafe { + __xpg_strerror_r(errnum, buf, buflen) + } + } + + let mut buf = [0 as c_char, ..TMPBUF_SZ]; + unsafe { + let err = strerror_r(errno() as c_int, &buf[0], + TMPBUF_SZ as size_t); + if err < 0 { + die!(~"strerror_r failure"); + } + + str::raw::from_c_str(&buf[0]) + } } + + #[cfg(windows)] + fn strerror() -> ~str { + unsafe { + rustrt::last_os_error() + } + } + + strerror() } /**