diff options
| author | Aaron Turon <aturon@mozilla.com> | 2014-09-30 17:03:56 -0700 |
|---|---|---|
| committer | Aaron Turon <aturon@mozilla.com> | 2014-11-08 20:40:38 -0800 |
| commit | 3a527f2b3311d5b1c6dd7c72db71c45596e6db49 (patch) | |
| tree | 1a550dd4b679b0ccf13acef6cc7879e486a3d3de /src/libstd | |
| parent | 93c85eb8bdcc910a27caf6abd20207a626ae98e5 (diff) | |
| download | rust-3a527f2b3311d5b1c6dd7c72db71c45596e6db49.tar.gz rust-3a527f2b3311d5b1c6dd7c72db71c45596e6db49.zip | |
Runtime removal: add private sys, sys_common modules
These modules will house the code that used to be part of the runtime system in libnative. The `sys_common` module contains a few low-level but cross-platform details. The `sys` module is set up using `#[cfg()]` to include either a unix or windows implementation of a common API surface. This API surface is *not* exported directly in `libstd`, but is instead used to bulid `std::os` and `std::io`. Ultimately, the low-level details in `sys` will be exposed in a controlled way through a separate platform-specific surface, but that setup is not part of this patch.
Diffstat (limited to 'src/libstd')
| -rw-r--r-- | src/libstd/io/mod.rs | 92 | ||||
| -rw-r--r-- | src/libstd/lib.rs | 7 | ||||
| -rw-r--r-- | src/libstd/os.rs | 155 | ||||
| -rw-r--r-- | src/libstd/sys/common/mod.rs | 91 | ||||
| -rw-r--r-- | src/libstd/sys/unix/c.rs | 262 | ||||
| -rw-r--r-- | src/libstd/sys/unix/mod.rs | 92 | ||||
| -rw-r--r-- | src/libstd/sys/unix/os.rs | 101 | ||||
| -rw-r--r-- | src/libstd/sys/windows/c.rs | 250 | ||||
| -rw-r--r-- | src/libstd/sys/windows/mod.rs | 178 | ||||
| -rw-r--r-- | src/libstd/sys/windows/os.rs | 103 |
10 files changed, 1093 insertions, 238 deletions
diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index c404741b7c3..78abbb9f80d 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -236,8 +236,7 @@ use os; use boxed::Box; use result::{Ok, Err, Result}; use rt::rtio; -use slice::{AsSlice, SlicePrelude}; -use str::{Str, StrPrelude}; +use sys; use str; use string::String; use uint; @@ -312,91 +311,10 @@ impl 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::ERROR_ACCESS_DENIED | 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"), - libc::ERROR_OPERATION_ABORTED => - (TimedOut, "operation timed out"), - libc::WSAEINVAL => (InvalidInput, "invalid argument"), - libc::ERROR_CALL_NOT_IMPLEMENTED => - (IoUnavailable, "function not implemented"), - libc::ERROR_INVALID_HANDLE => - (MismatchedFileTypeForOperation, - "invalid handle provided to function"), - libc::ERROR_NOTHING_TO_TERMINATE => - (InvalidInput, "no process to kill"), - - // 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 - // Windows 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"), - libc::ENOSYS => (IoUnavailable, "function not implemented"), - libc::EINVAL => (InvalidInput, "invalid argument"), - libc::ENOTTY => - (MismatchedFileTypeForOperation, - "file descriptor is not a TTY"), - libc::ETIMEDOUT => (TimedOut, "operation timed out"), - libc::ECANCELED => (TimedOut, "operation aborted"), - - // 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 && kind == OtherIoError { - Some(os::error_string(errno).as_slice().chars().map(|c| c.to_lowercase()).collect()) - } else { - None - }, + let mut err = sys::decode_error(errno as i32); + if detail && err.kind == OtherIoError { + err.detail = Some(os::error_string(errno).as_slice().chars() + .map(|c| c.to_lowercase()).collect()) } } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index f10a1d5e5ed..7eac455f97f 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -242,6 +242,13 @@ pub mod io; pub mod path; pub mod fmt; +#[cfg(unix)] +#[path = "sys/unix/mod.rs"] mod sys; +#[cfg(windows)] +#[path = "sys/windows/mod.rs"] mod sys; + +#[path = "sys/common/mod.rs"] mod sys_common; + // FIXME #7809: This shouldn't be pub, and it should be reexported under 'unstable' // but name resolution doesn't work without it being pub. pub mod rt; diff --git a/src/libstd/os.rs b/src/libstd/os.rs index 0042a3ae205..175e23bf819 100644 --- a/src/libstd/os.rs +++ b/src/libstd/os.rs @@ -34,7 +34,7 @@ use clone::Clone; use error::{FromError, Error}; use fmt; -use io::{IoResult, IoError}; +use io::IoResult; use iter::Iterator; use libc::{c_void, c_int}; use libc; @@ -43,6 +43,7 @@ use ops::Drop; use option::{Some, None, Option}; use os; use path::{Path, GenericPath, BytesContainer}; +use sys::os as os_imp; use ptr::RawPtr; use ptr; use result::{Err, Ok, Result}; @@ -905,59 +906,9 @@ pub fn change_dir(p: &Path) -> bool { } } -#[cfg(unix)] -/// Returns the platform-specific value of errno -pub fn errno() -> int { - #[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "freebsd"))] - fn errno_location() -> *const c_int { - extern { - fn __error() -> *const c_int; - } - unsafe { - __error() - } - } - - #[cfg(target_os = "dragonfly")] - fn errno_location() -> *const c_int { - extern { - fn __dfly_error() -> *const c_int; - } - unsafe { - __dfly_error() - } - } - - #[cfg(any(target_os = "linux", target_os = "android"))] - fn errno_location() -> *const c_int { - extern { - fn __errno_location() -> *const c_int; - } - unsafe { - __errno_location() - } - } - - unsafe { - (*errno_location()) as int - } -} - -#[cfg(windows)] /// Returns the platform-specific value of errno pub fn errno() -> uint { - use libc::types::os::arch::extra::DWORD; - - #[link_name = "kernel32"] - extern "system" { - fn GetLastError() -> DWORD; - } - - unsafe { - GetLastError() as uint - } + os_imp::errno() as uint } /// Return the string corresponding to an `errno()` value of `errnum`. @@ -969,105 +920,7 @@ pub fn errno() -> uint { /// println!("{}", os::error_string(os::errno() as uint)); /// ``` pub fn error_string(errnum: uint) -> String { - return strerror(errnum); - - #[cfg(unix)] - fn strerror(errnum: uint) -> String { - #[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "android", - target_os = "freebsd", - target_os = "dragonfly"))] - fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: libc::size_t) - -> c_int { - extern { - fn strerror_r(errnum: c_int, buf: *mut c_char, - buflen: libc::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: *mut c_char, - buflen: libc::size_t) -> c_int { - extern { - fn __xpg_strerror_r(errnum: c_int, - buf: *mut c_char, - buflen: libc::size_t) - -> c_int; - } - unsafe { - __xpg_strerror_r(errnum, buf, buflen) - } - } - - let mut buf = [0 as c_char, ..TMPBUF_SZ]; - - let p = buf.as_mut_ptr(); - unsafe { - if strerror_r(errnum as c_int, p, buf.len() as libc::size_t) < 0 { - panic!("strerror_r failure"); - } - - ::string::raw::from_buf(p as *const u8) - } - } - - #[cfg(windows)] - fn strerror(errnum: uint) -> String { - use libc::types::os::arch::extra::DWORD; - use libc::types::os::arch::extra::LPWSTR; - use libc::types::os::arch::extra::LPVOID; - use libc::types::os::arch::extra::WCHAR; - - #[link_name = "kernel32"] - extern "system" { - fn FormatMessageW(flags: DWORD, - lpSrc: LPVOID, - msgId: DWORD, - langId: DWORD, - buf: LPWSTR, - nsize: DWORD, - args: *const c_void) - -> DWORD; - } - - static FORMAT_MESSAGE_FROM_SYSTEM: DWORD = 0x00001000; - static FORMAT_MESSAGE_IGNORE_INSERTS: DWORD = 0x00000200; - - // This value is calculated from the macro - // MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT) - let langId = 0x0800 as DWORD; - - let mut buf = [0 as WCHAR, ..TMPBUF_SZ]; - - unsafe { - let res = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - ptr::null_mut(), - errnum as DWORD, - langId, - buf.as_mut_ptr(), - buf.len() as DWORD, - ptr::null()); - if res == 0 { - // Sometimes FormatMessageW can fail e.g. system doesn't like langId, - let fm_err = errno(); - return format!("OS Error {} (FormatMessageW() returned error {})", errnum, fm_err); - } - - let msg = String::from_utf16(::str::truncate_utf16_at_nul(buf)); - match msg { - Some(msg) => format!("OS Error {}: {}", errnum, msg), - None => format!("OS Error {} (FormatMessageW() returned invalid UTF-16)", errnum), - } - } - } + return os_imp::error_string(errnum as i32); } /// Get a string representing the platform-dependent last error diff --git a/src/libstd/sys/common/mod.rs b/src/libstd/sys/common/mod.rs new file mode 100644 index 00000000000..402c62bb35e --- /dev/null +++ b/src/libstd/sys/common/mod.rs @@ -0,0 +1,91 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(missing_doc)] +#![allow(dead_code)] + +use io::{mod, IoError, IoResult}; +use prelude::*; +use num; +use sys::{last_error, retry, fs}; +use c_str::CString; +use path::BytesContainer; +use collections; + +pub mod net; + +// common error constructors + +pub fn eof() -> IoError { + IoError { + kind: io::EndOfFile, + desc: "end of file", + detail: None, + } +} + +pub fn timeout(desc: &'static str) -> IoError { + IoError { + kind: io::TimedOut, + desc: desc, + detail: None, + } +} + +pub fn short_write(n: uint, desc: &'static str) -> IoError { + IoError { + kind: if n == 0 { io::TimedOut } else { io::ShortWrite(n) }, + desc: desc, + detail: None, + } +} + +// unix has nonzero values as errors +pub fn mkerr_libc<Int: num::Zero>(ret: Int) -> IoResult<()> { + if !ret.is_zero() { + Err(last_error()) + } else { + Ok(()) + } +} + +pub fn keep_going(data: &[u8], f: |*const u8, uint| -> i64) -> i64 { + let origamt = data.len(); + let mut data = data.as_ptr(); + let mut amt = origamt; + while amt > 0 { + let ret = retry(|| f(data, amt)); + if ret == 0 { + break + } else if ret != -1 { + amt -= ret as uint; + data = unsafe { data.offset(ret as int) }; + } else { + return ret; + } + } + return (origamt - amt) as i64; +} + +// traits for extracting representations from + +pub trait AsFileDesc { + fn as_fd(&self) -> &fs::FileDesc; +} + +pub trait ProcessConfig<K: BytesContainer, V: BytesContainer> { + fn program(&self) -> &CString; + fn args(&self) -> &[CString]; + fn env(&self) -> Option<&collections::HashMap<K, V>>; + fn cwd(&self) -> Option<&CString>; + fn uid(&self) -> Option<uint>; + fn gid(&self) -> Option<uint>; + fn detach(&self) -> bool; +} diff --git a/src/libstd/sys/unix/c.rs b/src/libstd/sys/unix/c.rs new file mode 100644 index 00000000000..e76f2a2b872 --- /dev/null +++ b/src/libstd/sys/unix/c.rs @@ -0,0 +1,262 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! C definitions used by libnative that don't belong in liblibc + +#![allow(dead_code)] +#![allow(non_camel_case_types)] + +pub use self::select::fd_set; +pub use self::signal::{sigaction, siginfo, sigset_t}; +pub use self::signal::{SA_ONSTACK, SA_RESTART, SA_RESETHAND, SA_NOCLDSTOP}; +pub use self::signal::{SA_NODEFER, SA_NOCLDWAIT, SA_SIGINFO, SIGCHLD}; + +use libc; + +#[cfg(any(target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly"))] +pub const FIONBIO: libc::c_ulong = 0x8004667e; +#[cfg(any(all(target_os = "linux", + any(target_arch = "x86", + target_arch = "x86_64", + target_arch = "arm")), + target_os = "android"))] +pub const FIONBIO: libc::c_ulong = 0x5421; +#[cfg(all(target_os = "linux", + any(target_arch = "mips", target_arch = "mipsel")))] +pub const FIONBIO: libc::c_ulong = 0x667e; + +#[cfg(any(target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly"))] +pub const FIOCLEX: libc::c_ulong = 0x20006601; +#[cfg(any(all(target_os = "linux", + any(target_arch = "x86", + target_arch = "x86_64", + target_arch = "arm")), + target_os = "android"))] +pub const FIOCLEX: libc::c_ulong = 0x5451; +#[cfg(all(target_os = "linux", + any(target_arch = "mips", target_arch = "mipsel")))] +pub const FIOCLEX: libc::c_ulong = 0x6601; + +#[cfg(any(target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly"))] +pub const MSG_DONTWAIT: libc::c_int = 0x80; +#[cfg(any(target_os = "linux", target_os = "android"))] +pub const MSG_DONTWAIT: libc::c_int = 0x40; + +pub const WNOHANG: libc::c_int = 1; + +extern { + pub fn gettimeofday(timeval: *mut libc::timeval, + tzp: *mut libc::c_void) -> libc::c_int; + pub fn select(nfds: libc::c_int, + readfds: *mut fd_set, + writefds: *mut fd_set, + errorfds: *mut fd_set, + timeout: *mut libc::timeval) -> libc::c_int; + pub fn getsockopt(sockfd: libc::c_int, + level: libc::c_int, + optname: libc::c_int, + optval: *mut libc::c_void, + optlen: *mut libc::socklen_t) -> libc::c_int; + pub fn ioctl(fd: libc::c_int, req: libc::c_ulong, ...) -> libc::c_int; + + + pub fn waitpid(pid: libc::pid_t, status: *mut libc::c_int, + options: libc::c_int) -> libc::pid_t; + + pub fn sigaction(signum: libc::c_int, + act: *const sigaction, + oldact: *mut sigaction) -> libc::c_int; + + pub fn sigaddset(set: *mut sigset_t, signum: libc::c_int) -> libc::c_int; + pub fn sigdelset(set: *mut sigset_t, signum: libc::c_int) -> libc::c_int; + pub fn sigemptyset(set: *mut sigset_t) -> libc::c_int; +} + +#[cfg(any(target_os = "macos", target_os = "ios"))] +mod select { + pub const FD_SETSIZE: uint = 1024; + + #[repr(C)] + pub struct fd_set { + fds_bits: [i32, ..(FD_SETSIZE / 32)] + } + + pub fn fd_set(set: &mut fd_set, fd: i32) { + set.fds_bits[(fd / 32) as uint] |= 1 << ((fd % 32) as uint); + } +} + +#[cfg(any(target_os = "android", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "linux"))] +mod select { + use uint; + use libc; + + pub const FD_SETSIZE: uint = 1024; + + #[repr(C)] + pub struct fd_set { + // FIXME: shouldn't this be a c_ulong? + fds_bits: [libc::uintptr_t, ..(FD_SETSIZE / uint::BITS)] + } + + pub fn fd_set(set: &mut fd_set, fd: i32) { + let fd = fd as uint; + set.fds_bits[fd / uint::BITS] |= 1 << (fd % uint::BITS); + } +} + +#[cfg(any(all(target_os = "linux", + any(target_arch = "x86", + target_arch = "x86_64", + target_arch = "arm")), + target_os = "android"))] +mod signal { + use libc; + + pub const SA_NOCLDSTOP: libc::c_ulong = 0x00000001; + pub const SA_NOCLDWAIT: libc::c_ulong = 0x00000002; + pub const SA_NODEFER: libc::c_ulong = 0x40000000; + pub const SA_ONSTACK: libc::c_ulong = 0x08000000; + pub const SA_RESETHAND: libc::c_ulong = 0x80000000; + pub const SA_RESTART: libc::c_ulong = 0x10000000; + pub const SA_SIGINFO: libc::c_ulong = 0x00000004; + pub const SIGCHLD: libc::c_int = 17; + + // This definition is not as accurate as it could be, {pid, uid, status} is + // actually a giant union. Currently we're only interested in these fields, + // however. + #[repr(C)] + pub struct siginfo { + si_signo: libc::c_int, + si_errno: libc::c_int, + si_code: libc::c_int, + pub pid: libc::pid_t, + pub uid: libc::uid_t, + pub status: libc::c_int, + } + + #[repr(C)] + pub struct sigaction { + pub sa_handler: extern fn(libc::c_int), + pub sa_mask: sigset_t, + pub sa_flags: libc::c_ulong, + sa_restorer: *mut libc::c_void, + } + + #[repr(C)] + #[cfg(target_word_size = "32")] + pub struct sigset_t { + __val: [libc::c_ulong, ..32], + } + + #[repr(C)] + #[cfg(target_word_size = "64")] + pub struct sigset_t { + __val: [libc::c_ulong, ..16], + } +} + +#[cfg(all(target_os = "linux", + any(target_arch = "mips", target_arch = "mipsel")))] +mod signal { + use libc; + + pub const SA_NOCLDSTOP: libc::c_ulong = 0x00000001; + pub const SA_NOCLDWAIT: libc::c_ulong = 0x00010000; + pub const SA_NODEFER: libc::c_ulong = 0x40000000; + pub const SA_ONSTACK: libc::c_ulong = 0x08000000; + pub const SA_RESETHAND: libc::c_ulong = 0x80000000; + pub const SA_RESTART: libc::c_ulong = 0x10000000; + pub const SA_SIGINFO: libc::c_ulong = 0x00000008; + pub const SIGCHLD: libc::c_int = 18; + + // This definition is not as accurate as it could be, {pid, uid, status} is + // actually a giant union. Currently we're only interested in these fields, + // however. + #[repr(C)] + pub struct siginfo { + si_signo: libc::c_int, + si_code: libc::c_int, + si_errno: libc::c_int, + pub pid: libc::pid_t, + pub uid: libc::uid_t, + pub status: libc::c_int, + } + + #[repr(C)] + pub struct sigaction { + pub sa_flags: libc::c_uint, + pub sa_handler: extern fn(libc::c_int), + pub sa_mask: sigset_t, + sa_restorer: *mut libc::c_void, + sa_resv: [libc::c_int, ..1], + } + + #[repr(C)] + pub struct sigset_t { + __val: [libc::c_ulong, ..32], + } +} + +#[cfg(any(target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly"))] +mod signal { + use libc; + + pub const SA_ONSTACK: libc::c_int = 0x0001; + pub const SA_RESTART: libc::c_int = 0x0002; + pub const SA_RESETHAND: libc::c_int = 0x0004; + pub const SA_NOCLDSTOP: libc::c_int = 0x0008; + pub const SA_NODEFER: libc::c_int = 0x0010; + pub const SA_NOCLDWAIT: libc::c_int = 0x0020; + pub const SA_SIGINFO: libc::c_int = 0x0040; + pub const SIGCHLD: libc::c_int = 20; + + #[cfg(any(target_os = "macos", target_os = "ios"))] + pub type sigset_t = u32; + #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] + #[repr(C)] + pub struct sigset_t { + bits: [u32, ..4], + } + + // This structure has more fields, but we're not all that interested in + // them. + #[repr(C)] + pub struct siginfo { + pub si_signo: libc::c_int, + pub si_errno: libc::c_int, + pub si_code: libc::c_int, + pub pid: libc::pid_t, + pub uid: libc::uid_t, + pub status: libc::c_int, + } + + #[repr(C)] + pub struct sigaction { + pub sa_handler: extern fn(libc::c_int), + pub sa_flags: libc::c_int, + pub sa_mask: sigset_t, + } +} diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs new file mode 100644 index 00000000000..ad5de2dad48 --- /dev/null +++ b/src/libstd/sys/unix/mod.rs @@ -0,0 +1,92 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +extern crate libc; + +use num; +use prelude::*; +use io::{mod, IoResult, IoError}; + +pub mod fs; +pub mod os; +pub mod c; + +pub type sock_t = io::file::fd_t; +pub type wrlen = libc::size_t; +pub unsafe fn close_sock(sock: sock_t) { let _ = libc::close(sock); } + +pub fn last_error() -> IoError { + let errno = os::errno() as i32; + let mut err = decode_error(errno); + err.detail = Some(os::error_string(errno)); + err +} + +/// Convert an `errno` value into a high-level error variant and description. +pub fn decode_error(errno: i32) -> IoError { + // FIXME: this should probably be a bit more descriptive... + let (kind, desc) = 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"), + libc::ENOSYS => (io::IoUnavailable, "function not implemented"), + libc::EINVAL => (io::InvalidInput, "invalid argument"), + libc::ENOTTY => + (io::MismatchedFileTypeForOperation, + "file descriptor is not a TTY"), + libc::ETIMEDOUT => (io::TimedOut, "operation timed out"), + libc::ECANCELED => (io::TimedOut, "operation aborted"), + + // 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") + }; + IoError { kind: kind, desc: desc, detail: None } +} + +#[inline] +pub fn retry<I: PartialEq + num::One + Neg<I>> (f: || -> I) -> I { + let minus_one = -num::one::<I>(); + loop { + let n = f(); + if n == minus_one && os::errno() == libc::EINTR as int { } + else { return n } + } +} + +pub fn ms_to_timeval(ms: u64) -> libc::timeval { + libc::timeval { + tv_sec: (ms / 1000) as libc::time_t, + tv_usec: ((ms % 1000) * 1000) as libc::suseconds_t, + } +} + +pub fn wouldblock() -> bool { + let err = os::errno(); + err == libc::EWOULDBLOCK as int || err == libc::EAGAIN as int +} + +pub fn set_nonblocking(fd: net::sock_t, nb: bool) -> IoResult<()> { + let set = nb as libc::c_int; + super::mkerr_libc(retry(|| unsafe { c::ioctl(fd, c::FIONBIO, &set) })) +} diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs new file mode 100644 index 00000000000..34699eb27c1 --- /dev/null +++ b/src/libstd/sys/unix/os.rs @@ -0,0 +1,101 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use libc; +use libc::{c_int, c_char}; +use prelude::*; + +use os::TMPBUF_SZ; + +/// Returns the platform-specific value of errno +pub fn errno() -> int { + #[cfg(any(target_os = "macos", + target_os = "ios", + target_os = "freebsd"))] + fn errno_location() -> *const c_int { + extern { + fn __error() -> *const c_int; + } + unsafe { + __error() + } + } + + #[cfg(target_os = "dragonfly")] + fn errno_location() -> *const c_int { + extern { + fn __dfly_error() -> *const c_int; + } + unsafe { + __dfly_error() + } + } + + #[cfg(any(target_os = "linux", target_os = "android"))] + fn errno_location() -> *const c_int { + extern { + fn __errno_location() -> *const c_int; + } + unsafe { + __errno_location() + } + } + + unsafe { + (*errno_location()) as int + } +} + +/// Get a detailed string description for the given error number +pub fn error_string(errno: i32) -> String { + #[cfg(any(target_os = "macos", + target_os = "ios", + target_os = "android", + target_os = "freebsd", + target_os = "dragonfly"))] + fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: libc::size_t) + -> c_int { + extern { + fn strerror_r(errnum: c_int, buf: *mut c_char, + buflen: libc::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: *mut c_char, + buflen: libc::size_t) -> c_int { + extern { + fn __xpg_strerror_r(errnum: c_int, + buf: *mut c_char, + buflen: libc::size_t) + -> c_int; + } + unsafe { + __xpg_strerror_r(errnum, buf, buflen) + } + } + + let mut buf = [0 as c_char, ..TMPBUF_SZ]; + + let p = buf.as_mut_ptr(); + unsafe { + if strerror_r(errno as c_int, p, buf.len() as libc::size_t) < 0 { + panic!("strerror_r failure"); + } + + ::string::raw::from_buf(p as *const u8) + } +} diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs new file mode 100644 index 00000000000..b8e9b1dca3a --- /dev/null +++ b/src/libstd/sys/windows/c.rs @@ -0,0 +1,250 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! C definitions used by libnative that don't belong in liblibc + +#![allow(overflowing_literals)] +#![allow(dead_code)] +#![allow(non_camel_case_types)] + +use libc; +use prelude::*; + +pub const WSADESCRIPTION_LEN: uint = 256; +pub const WSASYS_STATUS_LEN: uint = 128; +pub const FIONBIO: libc::c_long = 0x8004667e; +pub const FD_SETSIZE: uint = 64; +pub const MSG_DONTWAIT: libc::c_int = 0; +pub const ERROR_ILLEGAL_CHARACTER: libc::c_int = 582; +pub const ENABLE_ECHO_INPUT: libc::DWORD = 0x4; +pub const ENABLE_EXTENDED_FLAGS: libc::DWORD = 0x80; +pub const ENABLE_INSERT_MODE: libc::DWORD = 0x20; +pub const ENABLE_LINE_INPUT: libc::DWORD = 0x2; +pub const ENABLE_PROCESSED_INPUT: libc::DWORD = 0x1; +pub const ENABLE_QUICK_EDIT_MODE: libc::DWORD = 0x40; +pub const WSA_INVALID_EVENT: WSAEVENT = 0 as WSAEVENT; + +pub const FD_ACCEPT: libc::c_long = 0x08; +pub const FD_MAX_EVENTS: uint = 10; +pub const WSA_INFINITE: libc::DWORD = libc::INFINITE; +pub const WSA_WAIT_TIMEOUT: libc::DWORD = libc::consts::os::extra::WAIT_TIMEOUT; +pub const WSA_WAIT_EVENT_0: libc::DWORD = libc::consts::os::extra::WAIT_OBJECT_0; +pub const WSA_WAIT_FAILED: libc::DWORD = libc::consts::os::extra::WAIT_FAILED; + +#[repr(C)] +#[cfg(target_arch = "x86")] +pub struct WSADATA { + pub wVersion: libc::WORD, + pub wHighVersion: libc::WORD, + pub szDescription: [u8, ..WSADESCRIPTION_LEN + 1], + pub szSystemStatus: [u8, ..WSASYS_STATUS_LEN + 1], + pub iMaxSockets: u16, + pub iMaxUdpDg: u16, + pub lpVendorInfo: *mut u8, +} +#[repr(C)] +#[cfg(target_arch = "x86_64")] +pub struct WSADATA { + pub wVersion: libc::WORD, + pub wHighVersion: libc::WORD, + pub iMaxSockets: u16, + pub iMaxUdpDg: u16, + pub lpVendorInfo: *mut u8, + pub szDescription: [u8, ..WSADESCRIPTION_LEN + 1], + pub szSystemStatus: [u8, ..WSASYS_STATUS_LEN + 1], +} + +pub type LPWSADATA = *mut WSADATA; + +#[repr(C)] +pub struct WSANETWORKEVENTS { + pub lNetworkEvents: libc::c_long, + pub iErrorCode: [libc::c_int, ..FD_MAX_EVENTS], +} + +pub type LPWSANETWORKEVENTS = *mut WSANETWORKEVENTS; + +pub type WSAEVENT = libc::HANDLE; + +#[repr(C)] +pub struct fd_set { + fd_count: libc::c_uint, + fd_array: [libc::SOCKET, ..FD_SETSIZE], +} + +pub fn fd_set(set: &mut fd_set, s: libc::SOCKET) { + set.fd_array[set.fd_count as uint] = s; + set.fd_count += 1; +} + +#[link(name = "ws2_32")] +extern "system" { + pub fn WSAStartup(wVersionRequested: libc::WORD, + lpWSAData: LPWSADATA) -> libc::c_int; + pub fn WSAGetLastError() -> libc::c_int; + pub fn WSACloseEvent(hEvent: WSAEVENT) -> libc::BOOL; + pub fn WSACreateEvent() -> WSAEVENT; + pub fn WSAEventSelect(s: libc::SOCKET, + hEventObject: WSAEVENT, + lNetworkEvents: libc::c_long) -> libc::c_int; + pub fn WSASetEvent(hEvent: WSAEVENT) -> libc::BOOL; + pub fn WSAWaitForMultipleEvents(cEvents: libc::DWORD, + lphEvents: *const WSAEVENT, + fWaitAll: libc::BOOL, + dwTimeout: libc::DWORD, + fAltertable: libc::BOOL) -> libc::DWORD; + pub fn WSAEnumNetworkEvents(s: libc::SOCKET, + hEventObject: WSAEVENT, + lpNetworkEvents: LPWSANETWORKEVENTS) + -> libc::c_int; + + pub fn ioctlsocket(s: libc::SOCKET, cmd: libc::c_long, + argp: *mut libc::c_ulong) -> libc::c_int; + pub fn select(nfds: libc::c_int, + readfds: *mut fd_set, + writefds: *mut fd_set, + exceptfds: *mut fd_set, + timeout: *mut libc::timeval) -> libc::c_int; + pub fn getsockopt(sockfd: libc::SOCKET, + level: libc::c_int, + optname: libc::c_int, + optval: *mut libc::c_char, + optlen: *mut libc::c_int) -> libc::c_int; + + pub fn SetEvent(hEvent: libc::HANDLE) -> libc::BOOL; + pub fn WaitForMultipleObjects(nCount: libc::DWORD, + lpHandles: *const libc::HANDLE, + bWaitAll: libc::BOOL, + dwMilliseconds: libc::DWORD) -> libc::DWORD; + + pub fn CancelIo(hFile: libc::HANDLE) -> libc::BOOL; + pub fn CancelIoEx(hFile: libc::HANDLE, + lpOverlapped: libc::LPOVERLAPPED) -> libc::BOOL; +} + +pub mod compat { + use intrinsics::{atomic_store_relaxed, transmute}; + use iter::Iterator; + use libc::types::os::arch::extra::{LPCWSTR, HMODULE, LPCSTR, LPVOID}; + use prelude::*; + + extern "system" { + fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE; + fn GetProcAddress(hModule: HMODULE, lpProcName: LPCSTR) -> LPVOID; + } + + // store_func() is idempotent, so using relaxed ordering for the atomics + // should be enough. This way, calling a function in this compatibility + // layer (after it's loaded) shouldn't be any slower than a regular DLL + // call. + unsafe fn store_func(ptr: *mut uint, module: &str, symbol: &str, fallback: uint) { + let mut module: Vec<u16> = module.utf16_units().collect(); + module.push(0); + symbol.with_c_str(|symbol| { + let handle = GetModuleHandleW(module.as_ptr()); + let func: uint = transmute(GetProcAddress(handle, symbol)); + atomic_store_relaxed(ptr, if func == 0 { + fallback + } else { + func + }) + }) + } + + /// Macro for creating a compatibility fallback for a Windows function + /// + /// # Example + /// ``` + /// compat_fn!(adll32::SomeFunctionW(_arg: LPCWSTR) { + /// // Fallback implementation + /// }) + /// ``` + /// + /// Note that arguments unused by the fallback implementation should not be called `_` as + /// they are used to be passed to the real function if available. + macro_rules! compat_fn( + ($module:ident::$symbol:ident($($argname:ident: $argtype:ty),*) + -> $rettype:ty $fallback:block) => ( + #[inline(always)] + pub unsafe fn $symbol($($argname: $argtype),*) -> $rettype { + static mut ptr: extern "system" fn($($argname: $argtype),*) -> $rettype = thunk; + + extern "system" fn thunk($($argname: $argtype),*) -> $rettype { + unsafe { + ::sys::c::compat::store_func(&mut ptr as *mut _ as *mut uint, + stringify!($module), + stringify!($symbol), + fallback as uint); + ::intrinsics::atomic_load_relaxed(&ptr)($($argname),*) + } + } + + extern "system" fn fallback($($argname: $argtype),*) -> $rettype $fallback + + ::intrinsics::atomic_load_relaxed(&ptr)($($argname),*) + } + ); + + ($module:ident::$symbol:ident($($argname:ident: $argtype:ty),*) $fallback:block) => ( + compat_fn!($module::$symbol($($argname: $argtype),*) -> () $fallback) + ) + ) + + /// Compatibility layer for functions in `kernel32.dll` + /// + /// Latest versions of Windows this is needed for: + /// + /// * `CreateSymbolicLinkW`: Windows XP, Windows Server 2003 + /// * `GetFinalPathNameByHandleW`: Windows XP, Windows Server 2003 + pub mod kernel32 { + use libc::types::os::arch::extra::{DWORD, LPCWSTR, BOOLEAN, HANDLE}; + use libc::consts::os::extra::ERROR_CALL_NOT_IMPLEMENTED; + + extern "system" { + fn SetLastError(dwErrCode: DWORD); + } + + compat_fn!(kernel32::CreateSymbolicLinkW(_lpSymlinkFileName: LPCWSTR, + _lpTargetFileName: LPCWSTR, + _dwFlags: DWORD) -> BOOLEAN { + unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); } + 0 + }) + + compat_fn!(kernel32::GetFinalPathNameByHandleW(_hFile: HANDLE, + _lpszFilePath: LPCWSTR, + _cchFilePath: DWORD, + _dwFlags: DWORD) -> DWORD { + unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); } + 0 + }) + } +} + +extern "system" { + // FIXME - pInputControl should be PCONSOLE_READCONSOLE_CONTROL + pub fn ReadConsoleW(hConsoleInput: libc::HANDLE, + lpBuffer: libc::LPVOID, + nNumberOfCharsToRead: libc::DWORD, + lpNumberOfCharsRead: libc::LPDWORD, + pInputControl: libc::LPVOID) -> libc::BOOL; + + pub fn WriteConsoleW(hConsoleOutput: libc::HANDLE, + lpBuffer: libc::types::os::arch::extra::LPCVOID, + nNumberOfCharsToWrite: libc::DWORD, + lpNumberOfCharsWritten: libc::LPDWORD, + lpReserved: libc::LPVOID) -> libc::BOOL; + + pub fn GetConsoleMode(hConsoleHandle: libc::HANDLE, + lpMode: libc::LPDWORD) -> libc::BOOL; + + pub fn SetConsoleMode(hConsoleHandle: libc::HANDLE, + lpMode: libc::DWORD) -> libc::BOOL; +} diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs new file mode 100644 index 00000000000..5f4129c1484 --- /dev/null +++ b/src/libstd/sys/windows/mod.rs @@ -0,0 +1,178 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(missing_doc)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(unused_imports)] +#![allow(dead_code)] +#![allow(unused_unsafe)] +#![allow(unused_mut)] + +extern crate libc; + +use num; +use mem; +use prelude::*; +use io::{mod, IoResult, IoError}; +use sync::{Once, ONCE_INIT}; + +macro_rules! helper_init( (static $name:ident: Helper<$m:ty>) => ( + static $name: Helper<$m> = Helper { + lock: ::rt::mutex::NATIVE_MUTEX_INIT, + chan: ::cell::UnsafeCell { value: 0 as *mut Sender<$m> }, + signal: ::cell::UnsafeCell { value: 0 }, + initialized: ::cell::UnsafeCell { value: false }, + }; +) ) + +pub mod fs; +pub mod os; +pub mod c; + +pub type sock_t = libc::SOCKET; +pub type wrlen = libc::c_int; +pub unsafe fn close_sock(sock: sock_t) { let _ = libc::closesocket(sock); } + +// windows has zero values as errors +fn mkerr_winbool(ret: libc::c_int) -> IoResult<()> { + if ret == 0 { + Err(last_error()) + } else { + Ok(()) + } +} + +pub fn last_error() -> IoError { + let errno = os::errno() as i32; + let mut err = decode_error(errno); + err.detail = Some(os::error_string(errno)); + err +} + +pub fn last_net_error() -> IoError { + let errno = unsafe { c::WSAGetLastError() as i32 }; + let mut err = decode_error(errno); + err.detail = Some(os::error_string(errno)); + err +} + +pub fn last_gai_error(_errno: i32) -> IoError { + last_net_error() +} + +/// Convert an `errno` value into a high-level error variant and description. +pub fn decode_error(errno: i32) -> IoError { + let (kind, desc) = 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::ERROR_ACCESS_DENIED | 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"), + libc::ERROR_OPERATION_ABORTED => + (io::TimedOut, "operation timed out"), + libc::WSAEINVAL => (io::InvalidInput, "invalid argument"), + libc::ERROR_CALL_NOT_IMPLEMENTED => + (io::IoUnavailable, "function not implemented"), + libc::ERROR_INVALID_HANDLE => + (io::MismatchedFileTypeForOperation, + "invalid handle provided to function"), + libc::ERROR_NOTHING_TO_TERMINATE => + (io::InvalidInput, "no process to kill"), + + // 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 + // Windows calls. + libc::ERROR_INVALID_FUNCTION => (io::InvalidInput, + "illegal operation on a directory"), + + _ => (io::OtherIoError, "unknown error") + }; + IoError { kind: kind, desc: desc, detail: None } +} + +pub fn decode_error_detailed(errno: i32) -> IoError { + let mut err = decode_error(errno); + err.detail = Some(os::error_string(errno)); + err +} + +#[inline] +pub fn retry<I> (f: || -> I) -> I { f() } // PR rust-lang/rust/#17020 + +pub fn ms_to_timeval(ms: u64) -> libc::timeval { + libc::timeval { + tv_sec: (ms / 1000) as libc::c_long, + tv_usec: ((ms % 1000) * 1000) as libc::c_long, + } +} + +pub fn wouldblock() -> bool { + let err = os::errno(); + err == libc::WSAEWOULDBLOCK as uint +} + +pub fn set_nonblocking(fd: sock_t, nb: bool) -> IoResult<()> { + let mut set = nb as libc::c_ulong; + if unsafe { c::ioctlsocket(fd, c::FIONBIO, &mut set) != 0 } { + Err(last_error()) + } else { + Ok(()) + } +} + +// FIXME: call this +pub fn init_net() { + unsafe { + static START: Once = ONCE_INIT; + + START.doit(|| { + let mut data: c::WSADATA = mem::zeroed(); + let ret = c::WSAStartup(0x202, // version 2.2 + &mut data); + assert_eq!(ret, 0); + }); + } +} + +pub fn unimpl() -> IoError { + IoError { + kind: io::IoUnavailable, + desc: "operation is not implemented", + detail: None, + } +} + +pub fn to_utf16(s: Option<&str>) -> IoResult<Vec<u16>> { + match s { + Some(s) => Ok({ + let mut s = s.utf16_units().collect::<Vec<u16>>(); + s.push(0); + s + }), + None => Err(IoError { + kind: io::InvalidInput, + desc: "valid unicode input required", + detail: None + }) + } +} diff --git a/src/libstd/sys/windows/os.rs b/src/libstd/sys/windows/os.rs new file mode 100644 index 00000000000..aaa1aaf6327 --- /dev/null +++ b/src/libstd/sys/windows/os.rs @@ -0,0 +1,103 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// FIXME: move various extern bindings from here into liblibc or +// something similar + +use libc; +use libc::{c_int, c_char, c_void}; +use prelude::*; +use io::{IoResult, IoError}; +use sys::fs::FileDesc; +use ptr; + +use os::TMPBUF_SZ; + +pub fn errno() -> uint { + use libc::types::os::arch::extra::DWORD; + + #[link_name = "kernel32"] + extern "system" { + fn GetLastError() -> DWORD; + } + + unsafe { + GetLastError() as uint + } +} + +/// Get a detailed string description for the given error number +pub fn error_string(errnum: i32) -> String { + use libc::types::os::arch::extra::DWORD; + use libc::types::os::arch::extra::LPWSTR; + use libc::types::os::arch::extra::LPVOID; + use libc::types::os::arch::extra::WCHAR; + + #[link_name = "kernel32"] + extern "system" { + fn FormatMessageW(flags: DWORD, + lpSrc: LPVOID, + msgId: DWORD, + langId: DWORD, + buf: LPWSTR, + nsize: DWORD, + args: *const c_void) + -> DWORD; + } + + static FORMAT_MESSAGE_FROM_SYSTEM: DWORD = 0x00001000; + static FORMAT_MESSAGE_IGNORE_INSERTS: DWORD = 0x00000200; + + // This value is calculated from the macro + // MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT) + let langId = 0x0800 as DWORD; + + let mut buf = [0 as WCHAR, ..TMPBUF_SZ]; + + unsafe { + let res = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + ptr::null_mut(), + errnum as DWORD, + langId, + buf.as_mut_ptr(), + buf.len() as DWORD, + ptr::null()); + if res == 0 { + // Sometimes FormatMessageW can fail e.g. system doesn't like langId, + let fm_err = errno(); + return format!("OS Error {} (FormatMessageW() returned error {})", errnum, fm_err); + } + + let msg = String::from_utf16(::str::truncate_utf16_at_nul(buf)); + match msg { + Some(msg) => format!("OS Error {}: {}", errnum, msg), + None => format!("OS Error {} (FormatMessageW() returned invalid UTF-16)", errnum), + } + } +} + +pub unsafe fn pipe() -> IoResult<(FileDesc, FileDesc)> { + // Windows pipes work subtly differently than unix pipes, and their + // inheritance has to be handled in a different way that I do not + // fully understand. Here we explicitly make the pipe non-inheritable, + // which means to pass it to a subprocess they need to be duplicated + // first, as in std::run. + let mut fds = [0, ..2]; + match libc::pipe(fds.as_mut_ptr(), 1024 as ::libc::c_uint, + (libc::O_BINARY | libc::O_NOINHERIT) as c_int) { + 0 => { + assert!(fds[0] != -1 && fds[0] != 0); + assert!(fds[1] != -1 && fds[1] != 0); + Ok((FileDesc::new(fds[0], true), FileDesc::new(fds[1], true))) + } + _ => Err(IoError::last_error()), + } +} |
