Skip to content

Commit 9877d98

Browse files
committed
core: Rewrite last_os_error in Rust for unix and provide access to errno (unix) and GetLastError (windows).
1 parent a8f039a commit 9877d98

File tree

1 file changed

+103
-9
lines changed

1 file changed

+103
-9
lines changed

src/libcore/os.rs

+103-9
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ extern mod rustrt {
6666
unsafe fn rust_set_exit_status(code: libc::intptr_t);
6767
}
6868

69-
pub const tmpbuf_sz : uint = 1000u;
69+
pub const TMPBUF_SZ : uint = 1000u;
7070

7171
pub fn getcwd() -> Path {
7272
unsafe {
@@ -80,7 +80,7 @@ pub fn as_c_charp<T>(s: &str, f: fn(*c_char) -> T) -> T {
8080

8181
pub fn fill_charp_buf(f: fn(*mut c_char, size_t) -> bool)
8282
-> Option<~str> {
83-
let buf = vec::cast_to_mut(vec::from_elem(tmpbuf_sz, 0u8 as c_char));
83+
let buf = vec::cast_to_mut(vec::from_elem(TMPBUF_SZ, 0u8 as c_char));
8484
do vec::as_mut_buf(buf) |b, sz| {
8585
if f(b, sz as size_t) {
8686
unsafe {
@@ -99,19 +99,19 @@ pub mod win32 {
9999
use str;
100100
use option::{None, Option};
101101
use option;
102-
use os::tmpbuf_sz;
102+
use os::TMPBUF_SZ;
103103
use libc::types::os::arch::extra::DWORD;
104104

105105
pub fn fill_utf16_buf_and_decode(f: fn(*mut u16, DWORD) -> DWORD)
106106
-> Option<~str> {
107107
unsafe {
108-
let mut n = tmpbuf_sz as DWORD;
108+
let mut n = TMPBUF_SZ as DWORD;
109109
let mut res = None;
110110
let mut done = false;
111111
while !done {
112112
let buf = vec::cast_to_mut(vec::from_elem(n as uint, 0u16));
113113
do vec::as_mut_buf(buf) |b, _sz| {
114-
let k : DWORD = f(b, tmpbuf_sz as DWORD);
114+
let k : DWORD = f(b, TMPBUF_SZ as DWORD);
115115
if k == (0 as DWORD) {
116116
done = true;
117117
} else if (k == n &&
@@ -387,11 +387,11 @@ pub fn self_exe_path() -> Option<Path> {
387387
unsafe {
388388
use libc::funcs::posix01::unistd::readlink;
389389

390-
let mut path_str = str::with_capacity(tmpbuf_sz);
390+
let mut path_str = str::with_capacity(TMPBUF_SZ);
391391
let len = do str::as_c_str(path_str) |buf| {
392392
let buf = buf as *mut c_char;
393393
do as_c_charp("/proc/self/exe") |proc_self_buf| {
394-
readlink(proc_self_buf, buf, tmpbuf_sz as size_t)
394+
readlink(proc_self_buf, buf, TMPBUF_SZ as size_t)
395395
}
396396
};
397397
if len == -1 {
@@ -766,11 +766,105 @@ pub fn remove_file(p: &Path) -> bool {
766766
}
767767
}
768768

769+
#[cfg(unix)]
770+
pub fn errno() -> int {
771+
#[cfg(target_os = "macos")]
772+
#[cfg(target_os = "freebsd")]
773+
fn errno_location() -> *c_int {
774+
#[nolink]
775+
extern {
776+
unsafe fn __error() -> *c_int;
777+
}
778+
unsafe {
779+
__error()
780+
}
781+
}
782+
783+
#[cfg(target_os = "linux")]
784+
#[cfg(target_os = "android")]
785+
fn errno_location() -> *c_int {
786+
#[nolink]
787+
extern {
788+
unsafe fn __errno_location() -> *c_int;
789+
}
790+
unsafe {
791+
__errno_location()
792+
}
793+
}
794+
795+
unsafe {
796+
(*errno_location()) as int
797+
}
798+
}
799+
800+
#[cfg(windows)]
801+
pub fn errno() -> uint {
802+
use libc::types::os::arch::extra::DWORD;
803+
804+
#[link_name = "kernel32"]
805+
#[abi = "stdcall"]
806+
extern {
807+
unsafe fn GetLastError() -> DWORD;
808+
}
809+
810+
unsafe {
811+
GetLastError() as uint;
812+
}
813+
}
814+
769815
/// Get a string representing the platform-dependent last error
770816
pub fn last_os_error() -> ~str {
771-
unsafe {
772-
rustrt::last_os_error()
817+
#[cfg(unix)]
818+
fn strerror() -> ~str {
819+
#[cfg(target_os = "macos")]
820+
#[cfg(target_os = "android")]
821+
#[cfg(target_os = "freebsd")]
822+
fn strerror_r(errnum: c_int, buf: *c_char, buflen: size_t) -> c_int {
823+
#[nolink]
824+
extern {
825+
unsafe fn strerror_r(errnum: c_int, buf: *c_char,
826+
buflen: size_t) -> c_int;
827+
}
828+
unsafe {
829+
strerror_r(errnum, buf, buflen)
830+
}
831+
}
832+
833+
// GNU libc provides a non-compliant version of strerror_r by default
834+
// and requires macros to instead use the POSIX compliant variant.
835+
// So instead we just use __xpg_strerror_r which is always POSIX compliant
836+
#[cfg(target_os = "linux")]
837+
fn strerror_r(errnum: c_int, buf: *c_char, buflen: size_t) -> c_int {
838+
#[nolink]
839+
extern {
840+
unsafe fn __xpg_strerror_r(errnum: c_int, buf: *c_char,
841+
buflen: size_t) -> c_int;
842+
}
843+
unsafe {
844+
__xpg_strerror_r(errnum, buf, buflen)
845+
}
846+
}
847+
848+
let mut buf = [0 as c_char, ..TMPBUF_SZ];
849+
unsafe {
850+
let err = strerror_r(errno() as c_int, &buf[0],
851+
TMPBUF_SZ as size_t);
852+
if err < 0 {
853+
die!(~"strerror_r failure");
854+
}
855+
856+
str::raw::from_c_str(&buf[0])
857+
}
773858
}
859+
860+
#[cfg(windows)]
861+
fn strerror() -> ~str {
862+
unsafe {
863+
rustrt::last_os_error()
864+
}
865+
}
866+
867+
strerror()
774868
}
775869
776870
/**

0 commit comments

Comments
 (0)