diff --git a/src/libcore/os.rs b/src/libcore/os.rs index 38469c35cfa..0efc17354dd 100644 --- a/src/libcore/os.rs +++ b/src/libcore/os.rs @@ -62,11 +62,10 @@ extern mod rustrt { unsafe fn rust_path_exists(path: *libc::c_char) -> c_int; unsafe fn rust_list_files2(&&path: ~str) -> ~[~str]; unsafe fn rust_process_wait(handle: c_int) -> c_int; - unsafe fn last_os_error() -> ~str; 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 +79,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 +98,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 +386,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 +765,136 @@ 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 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 { + use libc::types::os::arch::extra::DWORD; + use libc::types::os::arch::extra::LPSTR; + use libc::types::os::arch::extra::LPVOID; + + #[link_name = "kernel32"] + #[abi = "stdcall"] + extern { + unsafe fn FormatMessageA(flags: DWORD, lpSrc: LPVOID, + msgId: DWORD, langId: DWORD, + buf: LPSTR, nsize: DWORD, + args: *c_void) -> DWORD; + } + + const FORMAT_MESSAGE_FROM_SYSTEM: DWORD = 0x00001000; + const FORMAT_MESSAGE_IGNORE_INSERTS: DWORD = 0x00000200; + + let mut buf = [0 as c_char, ..TMPBUF_SZ]; + + // This value is calculated from the macro + // MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT) + let langId = 0x0800 as DWORD; + let err = errno() as DWORD; + unsafe { + let res = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + ptr::mut_null(), err, langId, + &mut buf[0], TMPBUF_SZ as DWORD, + ptr::null()); + if res == 0 { + die!(fmt!("[%?] FormatMessage failure", errno())); + } + + str::raw::from_c_str(&buf[0]) + } + } + + strerror() } /** diff --git a/src/rt/rust_builtin.cpp b/src/rt/rust_builtin.cpp index 7c1d1a8ed16..86f371a30f3 100644 --- a/src/rt/rust_builtin.cpp +++ b/src/rt/rust_builtin.cpp @@ -52,50 +52,6 @@ timegm(struct tm *tm) } #endif - -extern "C" CDECL rust_str* -last_os_error() { - rust_task *task = rust_get_current_task(); - - LOG(task, task, "last_os_error()"); - -#if defined(__WIN32__) - LPTSTR buf; - DWORD err = GetLastError(); - DWORD res = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, err, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPTSTR) &buf, 0, NULL); - if (!res) { - task->fail(); - return NULL; - } -#elif defined(_GNU_SOURCE) && !defined(__ANDROID__) - char cbuf[BUF_BYTES]; - char *buf = strerror_r(errno, cbuf, sizeof(cbuf)); - if (!buf) { - task->fail(); - return NULL; - } -#else - char buf[BUF_BYTES]; - int err = strerror_r(errno, buf, sizeof(buf)); - if (err) { - task->fail(); - return NULL; - } -#endif - - rust_str * st = make_str(task->kernel, buf, strlen(buf), - "last_os_error"); -#ifdef __WIN32__ - LocalFree((HLOCAL)buf); -#endif - return st; -} - extern "C" CDECL rust_str * rust_getcwd() { rust_task *task = rust_get_current_task(); diff --git a/src/rt/rustrt.def.in b/src/rt/rustrt.def.in index 03b18d026ad..c554489c4b3 100644 --- a/src/rt/rustrt.def.in +++ b/src/rt/rustrt.def.in @@ -14,7 +14,6 @@ rust_gmtime rust_localtime rust_timegm rust_mktime -last_os_error new_task precise_time_ns rand_free diff --git a/src/test/auxiliary/anon-extern-mod-cross-crate-1.rs b/src/test/auxiliary/anon-extern-mod-cross-crate-1.rs index bbe36f18d6c..bccbb8173aa 100644 --- a/src/test/auxiliary/anon-extern-mod-cross-crate-1.rs +++ b/src/test/auxiliary/anon-extern-mod-cross-crate-1.rs @@ -15,5 +15,5 @@ #[crate_type = "lib"]; extern { - fn last_os_error() -> ~str; + fn rust_get_argc() -> libc::c_int; } diff --git a/src/test/auxiliary/foreign_lib.rs b/src/test/auxiliary/foreign_lib.rs index eb3397a8a5f..1d9c1cdbf83 100644 --- a/src/test/auxiliary/foreign_lib.rs +++ b/src/test/auxiliary/foreign_lib.rs @@ -11,5 +11,5 @@ #[link(name="foreign_lib", vers="0.0")]; pub extern mod rustrt { - pub fn last_os_error() -> ~str; + pub fn rust_get_argc() -> libc::c_int; } diff --git a/src/test/run-fail/morestack2.rs b/src/test/run-fail/morestack2.rs index 58957aac203..8236489834d 100644 --- a/src/test/run-fail/morestack2.rs +++ b/src/test/run-fail/morestack2.rs @@ -18,7 +18,7 @@ extern mod std; extern mod rustrt { - pub fn last_os_error() -> ~str; + pub fn rust_get_argc() -> libc::c_int; } fn getbig_call_c_and_fail(i: int) { @@ -26,7 +26,7 @@ fn getbig_call_c_and_fail(i: int) { getbig_call_c_and_fail(i - 1); } else { unsafe { - rustrt::last_os_error(); + rustrt::rust_get_argc(); die!(); } } diff --git a/src/test/run-pass/anon-extern-mod-cross-crate-2.rs b/src/test/run-pass/anon-extern-mod-cross-crate-2.rs index 939903b3b12..ed57b32b3d9 100644 --- a/src/test/run-pass/anon-extern-mod-cross-crate-2.rs +++ b/src/test/run-pass/anon-extern-mod-cross-crate-2.rs @@ -15,5 +15,5 @@ extern mod anonexternmod; use anonexternmod::*; pub fn main() { - last_os_error(); + rust_get_argc(); } diff --git a/src/test/run-pass/anon-extern-mod.rs b/src/test/run-pass/anon-extern-mod.rs index 525e6b9fbd6..6e73022fad2 100644 --- a/src/test/run-pass/anon-extern-mod.rs +++ b/src/test/run-pass/anon-extern-mod.rs @@ -11,11 +11,11 @@ #[abi = "cdecl"] #[link_name = "rustrt"] extern { - fn last_os_error() -> ~str; + fn rust_get_argc() -> libc::c_int; } pub fn main() { unsafe { - let _ = last_os_error(); + let _ = rust_get_argc(); } } diff --git a/src/test/run-pass/foreign-dupe.rs b/src/test/run-pass/foreign-dupe.rs index 77ed95a8099..6230fe11363 100644 --- a/src/test/run-pass/foreign-dupe.rs +++ b/src/test/run-pass/foreign-dupe.rs @@ -14,18 +14,18 @@ #[abi = "cdecl"] #[link_name = "rustrt"] extern mod rustrt1 { - pub fn last_os_error() -> ~str; + pub fn rust_get_argc() -> libc::c_int; } #[abi = "cdecl"] #[link_name = "rustrt"] extern mod rustrt2 { - pub fn last_os_error() -> ~str; + pub fn rust_get_argc() -> libc::c_int; } pub fn main() { unsafe { - rustrt1::last_os_error(); - rustrt2::last_os_error(); + rustrt1::rust_get_argc(); + rustrt2::rust_get_argc(); } } diff --git a/src/test/run-pass/invoke-external-foreign.rs b/src/test/run-pass/invoke-external-foreign.rs index cc50e06199d..69fce9e541e 100644 --- a/src/test/run-pass/invoke-external-foreign.rs +++ b/src/test/run-pass/invoke-external-foreign.rs @@ -18,5 +18,5 @@ extern mod foreign_lib; pub fn main() { - let foo = foreign_lib::rustrt::last_os_error(); + let foo = foreign_lib::rustrt::rust_get_argc(); } diff --git a/src/test/run-pass/morestack6.rs b/src/test/run-pass/morestack6.rs index 9b852cbc635..d56d9c30b70 100644 --- a/src/test/run-pass/morestack6.rs +++ b/src/test/run-pass/morestack6.rs @@ -15,7 +15,7 @@ extern mod rustrt { pub fn debug_get_stk_seg() -> *u8; pub fn rust_get_sched_id() -> libc::intptr_t; - pub fn last_os_error() -> ~str; + pub fn rust_get_argc() -> libc::c_int; pub fn rust_getcwd() -> ~str; pub fn get_task_id() -> libc::intptr_t; pub fn rust_sched_threads(); @@ -23,7 +23,7 @@ extern mod rustrt { } fn calllink01() { unsafe { rustrt::rust_get_sched_id(); } } -fn calllink02() { unsafe { rustrt::last_os_error(); } } +fn calllink02() { unsafe { rustrt::rust_get_argc(); } } fn calllink03() { unsafe { rustrt::rust_getcwd(); } } fn calllink08() { unsafe { rustrt::get_task_id(); } } fn calllink09() { unsafe { rustrt::rust_sched_threads(); } }