aboutsummaryrefslogtreecommitdiff
path: root/ctr-std/src/sys/redox
diff options
context:
space:
mode:
authorValentin <[email protected]>2018-06-15 18:57:24 +0200
committerFenrirWolf <[email protected]>2018-06-15 10:57:24 -0600
commitf2a90174bb36b9ad528e863ab34c02ebce002b02 (patch)
tree959e8d67883d3a89e179b3549b1f30d28e51a87c /ctr-std/src/sys/redox
parentMerge pull request #68 from linouxis9/master (diff)
downloadctru-rs-f2a90174bb36b9ad528e863ab34c02ebce002b02.tar.xz
ctru-rs-f2a90174bb36b9ad528e863ab34c02ebce002b02.zip
Update for latest nightly 2018-06-09 (#70)
* Update for latest nightly 2018-06-09 * We now have a proper horizon os and sys modules in libstd
Diffstat (limited to 'ctr-std/src/sys/redox')
-rw-r--r--ctr-std/src/sys/redox/args.rs111
-rw-r--r--ctr-std/src/sys/redox/backtrace/mod.rs42
-rw-r--r--ctr-std/src/sys/redox/backtrace/printing.rs11
-rw-r--r--ctr-std/src/sys/redox/backtrace/tracing.rs107
-rw-r--r--ctr-std/src/sys/redox/cmath.rs43
-rw-r--r--ctr-std/src/sys/redox/condvar.rs121
-rw-r--r--ctr-std/src/sys/redox/env.rs19
-rw-r--r--ctr-std/src/sys/redox/ext/ffi.rs65
-rw-r--r--ctr-std/src/sys/redox/ext/fs.rs349
-rw-r--r--ctr-std/src/sys/redox/ext/io.rs167
-rw-r--r--ctr-std/src/sys/redox/ext/mod.rs54
-rw-r--r--ctr-std/src/sys/redox/ext/process.rs187
-rw-r--r--ctr-std/src/sys/redox/ext/thread.rs49
-rw-r--r--ctr-std/src/sys/redox/fast_thread_local.rs121
-rw-r--r--ctr-std/src/sys/redox/fd.rs95
-rw-r--r--ctr-std/src/sys/redox/fs.rs483
-rw-r--r--ctr-std/src/sys/redox/memchr.rs14
-rw-r--r--ctr-std/src/sys/redox/mod.rs81
-rw-r--r--ctr-std/src/sys/redox/mutex.rs179
-rw-r--r--ctr-std/src/sys/redox/net/dns/answer.rs22
-rw-r--r--ctr-std/src/sys/redox/net/dns/mod.rs215
-rw-r--r--ctr-std/src/sys/redox/net/dns/query.rs18
-rw-r--r--ctr-std/src/sys/redox/net/mod.rs115
-rw-r--r--ctr-std/src/sys/redox/net/netc.rs57
-rw-r--r--ctr-std/src/sys/redox/net/tcp.rs253
-rw-r--r--ctr-std/src/sys/redox/net/udp.rs242
-rw-r--r--ctr-std/src/sys/redox/os.rs219
-rw-r--r--ctr-std/src/sys/redox/os_str.rs189
-rw-r--r--ctr-std/src/sys/redox/path.rs39
-rw-r--r--ctr-std/src/sys/redox/pipe.rs103
-rw-r--r--ctr-std/src/sys/redox/process.rs543
-rw-r--r--ctr-std/src/sys/redox/rand.rs13
-rw-r--r--ctr-std/src/sys/redox/rwlock.rs61
-rw-r--r--ctr-std/src/sys/redox/stack_overflow.rs27
-rw-r--r--ctr-std/src/sys/redox/stdio.rs81
-rw-r--r--ctr-std/src/sys/redox/syscall/arch/arm.rs83
-rw-r--r--ctr-std/src/sys/redox/syscall/arch/x86.rs83
-rw-r--r--ctr-std/src/sys/redox/syscall/arch/x86_64.rs84
-rw-r--r--ctr-std/src/sys/redox/syscall/call.rs363
-rw-r--r--ctr-std/src/sys/redox/syscall/data.rs201
-rw-r--r--ctr-std/src/sys/redox/syscall/error.rs325
-rw-r--r--ctr-std/src/sys/redox/syscall/flag.rs116
-rw-r--r--ctr-std/src/sys/redox/syscall/mod.rs43
-rw-r--r--ctr-std/src/sys/redox/syscall/number.rs83
-rw-r--r--ctr-std/src/sys/redox/thread.rs95
-rw-r--r--ctr-std/src/sys/redox/thread_local.rs71
-rw-r--r--ctr-std/src/sys/redox/time.rs214
47 files changed, 6256 insertions, 0 deletions
diff --git a/ctr-std/src/sys/redox/args.rs b/ctr-std/src/sys/redox/args.rs
new file mode 100644
index 0000000..59ae2a7
--- /dev/null
+++ b/ctr-std/src/sys/redox/args.rs
@@ -0,0 +1,111 @@
+// Copyright 2016 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.
+
+//! Global initialization and retrieval of command line arguments.
+//!
+//! On some platforms these are stored during runtime startup,
+//! and on some they are retrieved from the system on demand.
+
+#![allow(dead_code)] // runtime init functions not used during testing
+
+use ffi::OsString;
+use marker::PhantomData;
+use vec;
+
+/// One-time global initialization.
+pub unsafe fn init(argc: isize, argv: *const *const u8) { imp::init(argc, argv) }
+
+/// One-time global cleanup.
+pub unsafe fn cleanup() { imp::cleanup() }
+
+/// Returns the command line arguments
+pub fn args() -> Args {
+ imp::args()
+}
+
+pub struct Args {
+ iter: vec::IntoIter<OsString>,
+ _dont_send_or_sync_me: PhantomData<*mut ()>,
+}
+
+impl Args {
+ pub fn inner_debug(&self) -> &[OsString] {
+ self.iter.as_slice()
+ }
+}
+
+impl Iterator for Args {
+ type Item = OsString;
+ fn next(&mut self) -> Option<OsString> { self.iter.next() }
+ fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
+}
+
+impl ExactSizeIterator for Args {
+ fn len(&self) -> usize { self.iter.len() }
+}
+
+impl DoubleEndedIterator for Args {
+ fn next_back(&mut self) -> Option<OsString> { self.iter.next_back() }
+}
+
+mod imp {
+ use os::unix::prelude::*;
+ use mem;
+ use ffi::{CStr, OsString};
+ use marker::PhantomData;
+ use libc;
+ use super::Args;
+
+ use sys_common::mutex::Mutex;
+
+ static mut GLOBAL_ARGS_PTR: usize = 0;
+ static LOCK: Mutex = Mutex::new();
+
+ pub unsafe fn init(argc: isize, argv: *const *const u8) {
+ let args = (0..argc).map(|i| {
+ CStr::from_ptr(*argv.offset(i) as *const libc::c_char).to_bytes().to_vec()
+ }).collect();
+
+ LOCK.lock();
+ let ptr = get_global_ptr();
+ assert!((*ptr).is_none());
+ (*ptr) = Some(box args);
+ LOCK.unlock();
+ }
+
+ pub unsafe fn cleanup() {
+ LOCK.lock();
+ *get_global_ptr() = None;
+ LOCK.unlock();
+ }
+
+ pub fn args() -> Args {
+ let bytes = clone().unwrap_or(Vec::new());
+ let v: Vec<OsString> = bytes.into_iter().map(|v| {
+ OsStringExt::from_vec(v)
+ }).collect();
+ Args { iter: v.into_iter(), _dont_send_or_sync_me: PhantomData }
+ }
+
+ fn clone() -> Option<Vec<Vec<u8>>> {
+ unsafe {
+ LOCK.lock();
+ let ptr = get_global_ptr();
+ let ret = (*ptr).as_ref().map(|s| (**s).clone());
+ LOCK.unlock();
+ return ret
+ }
+ }
+
+ fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> {
+ unsafe { mem::transmute(&GLOBAL_ARGS_PTR) }
+ }
+
+}
diff --git a/ctr-std/src/sys/redox/backtrace/mod.rs b/ctr-std/src/sys/redox/backtrace/mod.rs
new file mode 100644
index 0000000..40b957d
--- /dev/null
+++ b/ctr-std/src/sys/redox/backtrace/mod.rs
@@ -0,0 +1,42 @@
+// Copyright 2015 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.
+
+/// See sys/unix/backtrace/mod.rs for an explanation of the method used here.
+
+pub use self::tracing::unwind_backtrace;
+pub use self::printing::{foreach_symbol_fileline, resolve_symname};
+
+// tracing impls:
+mod tracing;
+// symbol resolvers:
+mod printing;
+
+pub mod gnu {
+ use io;
+ use fs;
+ use libc::c_char;
+ use vec::Vec;
+ use ffi::OsStr;
+ use os::unix::ffi::OsStrExt;
+ use io::Read;
+
+ pub fn get_executable_filename() -> io::Result<(Vec<c_char>, fs::File)> {
+ let mut exefile = fs::File::open("sys:exe")?;
+ let mut exename = Vec::new();
+ exefile.read_to_end(&mut exename)?;
+ if exename.last() == Some(&b'\n') {
+ exename.pop();
+ }
+ let file = fs::File::open(OsStr::from_bytes(&exename))?;
+ Ok((exename.into_iter().map(|c| c as c_char).collect(), file))
+ }
+}
+
+pub struct BacktraceContext;
diff --git a/ctr-std/src/sys/redox/backtrace/printing.rs b/ctr-std/src/sys/redox/backtrace/printing.rs
new file mode 100644
index 0000000..3e937db
--- /dev/null
+++ b/ctr-std/src/sys/redox/backtrace/printing.rs
@@ -0,0 +1,11 @@
+// Copyright 2014-2015 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.
+
+pub use sys_common::gnu::libbacktrace::{foreach_symbol_fileline, resolve_symname};
diff --git a/ctr-std/src/sys/redox/backtrace/tracing.rs b/ctr-std/src/sys/redox/backtrace/tracing.rs
new file mode 100644
index 0000000..bb70ca3
--- /dev/null
+++ b/ctr-std/src/sys/redox/backtrace/tracing.rs
@@ -0,0 +1,107 @@
+// Copyright 2014-2015 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 error::Error;
+use io;
+use libc;
+use sys::backtrace::BacktraceContext;
+use sys_common::backtrace::Frame;
+
+use unwind as uw;
+
+struct Context<'a> {
+ idx: usize,
+ frames: &'a mut [Frame],
+}
+
+#[derive(Debug)]
+struct UnwindError(uw::_Unwind_Reason_Code);
+
+impl Error for UnwindError {
+ fn description(&self) -> &'static str {
+ "unexpected return value while unwinding"
+ }
+}
+
+impl ::fmt::Display for UnwindError {
+ fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
+ write!(f, "{}: {:?}", self.description(), self.0)
+ }
+}
+
+#[inline(never)] // if we know this is a function call, we can skip it when
+ // tracing
+pub fn unwind_backtrace(frames: &mut [Frame])
+ -> io::Result<(usize, BacktraceContext)>
+{
+ let mut cx = Context {
+ idx: 0,
+ frames: frames,
+ };
+ let result_unwind = unsafe {
+ uw::_Unwind_Backtrace(trace_fn,
+ &mut cx as *mut Context
+ as *mut libc::c_void)
+ };
+ // See libunwind:src/unwind/Backtrace.c for the return values.
+ // No, there is no doc.
+ match result_unwind {
+ // These return codes seem to be benign and need to be ignored for backtraces
+ // to show up properly on all tested platforms.
+ uw::_URC_END_OF_STACK | uw::_URC_FATAL_PHASE1_ERROR | uw::_URC_FAILURE => {
+ Ok((cx.idx, BacktraceContext))
+ }
+ _ => {
+ Err(io::Error::new(io::ErrorKind::Other,
+ UnwindError(result_unwind)))
+ }
+ }
+}
+
+extern fn trace_fn(ctx: *mut uw::_Unwind_Context,
+ arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code {
+ let cx = unsafe { &mut *(arg as *mut Context) };
+ let mut ip_before_insn = 0;
+ let mut ip = unsafe {
+ uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void
+ };
+ if !ip.is_null() && ip_before_insn == 0 {
+ // this is a non-signaling frame, so `ip` refers to the address
+ // after the calling instruction. account for that.
+ ip = (ip as usize - 1) as *mut _;
+ }
+
+ // dladdr() on osx gets whiny when we use FindEnclosingFunction, and
+ // it appears to work fine without it, so we only use
+ // FindEnclosingFunction on non-osx platforms. In doing so, we get a
+ // slightly more accurate stack trace in the process.
+ //
+ // This is often because panic involves the last instruction of a
+ // function being "call std::rt::begin_unwind", with no ret
+ // instructions after it. This means that the return instruction
+ // pointer points *outside* of the calling function, and by
+ // unwinding it we go back to the original function.
+ let symaddr = if cfg!(target_os = "macos") || cfg!(target_os = "ios") {
+ ip
+ } else {
+ unsafe { uw::_Unwind_FindEnclosingFunction(ip) }
+ };
+
+ if cx.idx < cx.frames.len() {
+ cx.frames[cx.idx] = Frame {
+ symbol_addr: symaddr as *mut u8,
+ exact_position: ip as *mut u8,
+ inline_context: 0,
+ };
+ cx.idx += 1;
+ }
+
+ uw::_URC_NO_REASON
+}
diff --git a/ctr-std/src/sys/redox/cmath.rs b/ctr-std/src/sys/redox/cmath.rs
new file mode 100644
index 0000000..2bc9665
--- /dev/null
+++ b/ctr-std/src/sys/redox/cmath.rs
@@ -0,0 +1,43 @@
+// Copyright 2017 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.
+
+#![cfg(not(test))]
+
+use libc::{c_float, c_double};
+
+#[link_name = "m"]
+extern {
+ pub fn acos(n: c_double) -> c_double;
+ pub fn acosf(n: c_float) -> c_float;
+ pub fn asin(n: c_double) -> c_double;
+ pub fn asinf(n: c_float) -> c_float;
+ pub fn atan(n: c_double) -> c_double;
+ pub fn atan2(a: c_double, b: c_double) -> c_double;
+ pub fn atan2f(a: c_float, b: c_float) -> c_float;
+ pub fn atanf(n: c_float) -> c_float;
+ pub fn cbrt(n: c_double) -> c_double;
+ pub fn cbrtf(n: c_float) -> c_float;
+ pub fn cosh(n: c_double) -> c_double;
+ pub fn coshf(n: c_float) -> c_float;
+ pub fn expm1(n: c_double) -> c_double;
+ pub fn expm1f(n: c_float) -> c_float;
+ pub fn fdim(a: c_double, b: c_double) -> c_double;
+ pub fn fdimf(a: c_float, b: c_float) -> c_float;
+ pub fn hypot(x: c_double, y: c_double) -> c_double;
+ pub fn hypotf(x: c_float, y: c_float) -> c_float;
+ pub fn log1p(n: c_double) -> c_double;
+ pub fn log1pf(n: c_float) -> c_float;
+ pub fn sinh(n: c_double) -> c_double;
+ pub fn sinhf(n: c_float) -> c_float;
+ pub fn tan(n: c_double) -> c_double;
+ pub fn tanf(n: c_float) -> c_float;
+ pub fn tanh(n: c_double) -> c_double;
+ pub fn tanhf(n: c_float) -> c_float;
+}
diff --git a/ctr-std/src/sys/redox/condvar.rs b/ctr-std/src/sys/redox/condvar.rs
new file mode 100644
index 0000000..2a611ed
--- /dev/null
+++ b/ctr-std/src/sys/redox/condvar.rs
@@ -0,0 +1,121 @@
+// Copyright 2016 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 cell::UnsafeCell;
+use intrinsics::{atomic_cxchg, atomic_load, atomic_xadd, atomic_xchg};
+use ptr;
+use time::Duration;
+
+use sys::mutex::{mutex_unlock, Mutex};
+use sys::syscall::{futex, TimeSpec, FUTEX_WAIT, FUTEX_WAKE, FUTEX_REQUEUE};
+
+pub struct Condvar {
+ lock: UnsafeCell<*mut i32>,
+ seq: UnsafeCell<i32>
+}
+
+impl Condvar {
+ pub const fn new() -> Condvar {
+ Condvar {
+ lock: UnsafeCell::new(ptr::null_mut()),
+ seq: UnsafeCell::new(0)
+ }
+ }
+
+ #[inline]
+ pub unsafe fn init(&self) {
+ *self.lock.get() = ptr::null_mut();
+ *self.seq.get() = 0;
+ }
+
+ #[inline]
+ pub fn notify_one(&self) {
+ unsafe {
+ let seq = self.seq.get();
+
+ atomic_xadd(seq, 1);
+
+ let _ = futex(seq, FUTEX_WAKE, 1, 0, ptr::null_mut());
+ }
+ }
+
+ #[inline]
+ pub fn notify_all(&self) {
+ unsafe {
+ let lock = self.lock.get();
+ let seq = self.seq.get();
+
+ if *lock == ptr::null_mut() {
+ return;
+ }
+
+ atomic_xadd(seq, 1);
+
+ let _ = futex(seq, FUTEX_REQUEUE, 1, ::usize::MAX, *lock);
+ }
+ }
+
+ #[inline]
+ unsafe fn wait_inner(&self, mutex: &Mutex, timeout_ptr: *const TimeSpec) -> bool {
+ let lock = self.lock.get();
+ let seq = self.seq.get();
+
+ if *lock != mutex.lock.get() {
+ if *lock != ptr::null_mut() {
+ panic!("Condvar used with more than one Mutex");
+ }
+
+ atomic_cxchg(lock as *mut usize, 0, mutex.lock.get() as usize);
+ }
+
+ mutex_unlock(*lock);
+
+ let seq_before = atomic_load(seq);
+
+ let _ = futex(seq, FUTEX_WAIT, seq_before, timeout_ptr as usize, ptr::null_mut());
+
+ let seq_after = atomic_load(seq);
+
+ while atomic_xchg(*lock, 2) != 0 {
+ let _ = futex(*lock, FUTEX_WAIT, 2, 0, ptr::null_mut());
+ }
+
+ seq_before != seq_after
+ }
+
+ #[inline]
+ pub fn wait(&self, mutex: &Mutex) {
+ unsafe {
+ assert!(self.wait_inner(mutex, ptr::null()));
+ }
+ }
+
+ #[inline]
+ pub fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
+ unsafe {
+ let timeout = TimeSpec {
+ tv_sec: dur.as_secs() as i64,
+ tv_nsec: dur.subsec_nanos() as i32
+ };
+
+ self.wait_inner(mutex, &timeout as *const TimeSpec)
+ }
+ }
+
+ #[inline]
+ pub unsafe fn destroy(&self) {
+ *self.lock.get() = ptr::null_mut();
+ *self.seq.get() = 0;
+ }
+}
+
+unsafe impl Send for Condvar {}
+
+unsafe impl Sync for Condvar {}
diff --git a/ctr-std/src/sys/redox/env.rs b/ctr-std/src/sys/redox/env.rs
new file mode 100644
index 0000000..669b752
--- /dev/null
+++ b/ctr-std/src/sys/redox/env.rs
@@ -0,0 +1,19 @@
+// Copyright 2016 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.
+
+pub mod os {
+ pub const FAMILY: &'static str = "redox";
+ pub const OS: &'static str = "redox";
+ pub const DLL_PREFIX: &'static str = "lib";
+ pub const DLL_SUFFIX: &'static str = ".so";
+ pub const DLL_EXTENSION: &'static str = "so";
+ pub const EXE_SUFFIX: &'static str = "";
+ pub const EXE_EXTENSION: &'static str = "";
+}
diff --git a/ctr-std/src/sys/redox/ext/ffi.rs b/ctr-std/src/sys/redox/ext/ffi.rs
new file mode 100644
index 0000000..cd88c8f
--- /dev/null
+++ b/ctr-std/src/sys/redox/ext/ffi.rs
@@ -0,0 +1,65 @@
+// Copyright 2015 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.
+
+//! Redox-specific extension to the primitives in the `std::ffi` module.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use ffi::{OsStr, OsString};
+use mem;
+use sys::os_str::Buf;
+use sys_common::{FromInner, IntoInner, AsInner};
+
+/// Redox-specific extensions to [`OsString`].
+///
+/// [`OsString`]: ../../../../std/ffi/struct.OsString.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait OsStringExt {
+ /// Creates an `OsString` from a byte vector.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn from_vec(vec: Vec<u8>) -> Self;
+
+ /// Yields the underlying byte vector of this `OsString`.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn into_vec(self) -> Vec<u8>;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl OsStringExt for OsString {
+ fn from_vec(vec: Vec<u8>) -> OsString {
+ FromInner::from_inner(Buf { inner: vec })
+ }
+ fn into_vec(self) -> Vec<u8> {
+ self.into_inner().inner
+ }
+}
+
+/// Redox-specific extensions to [`OsStr`].
+///
+/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait OsStrExt {
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn from_bytes(slice: &[u8]) -> &Self;
+
+ /// Gets the underlying byte view of the `OsStr` slice.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn as_bytes(&self) -> &[u8];
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl OsStrExt for OsStr {
+ fn from_bytes(slice: &[u8]) -> &OsStr {
+ unsafe { mem::transmute(slice) }
+ }
+ fn as_bytes(&self) -> &[u8] {
+ &self.as_inner().inner
+ }
+}
diff --git a/ctr-std/src/sys/redox/ext/fs.rs b/ctr-std/src/sys/redox/ext/fs.rs
new file mode 100644
index 0000000..c1dba6e
--- /dev/null
+++ b/ctr-std/src/sys/redox/ext/fs.rs
@@ -0,0 +1,349 @@
+// Copyright 2016 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.
+
+//! Redox-specific extensions to primitives in the `std::fs` module.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use fs::{self, Permissions, OpenOptions};
+use io;
+use path::Path;
+use sys;
+use sys_common::{FromInner, AsInner, AsInnerMut};
+
+/// Redox-specific extensions to [`fs::Permissions`].
+///
+/// [`fs::Permissions`]: ../../../../std/fs/struct.Permissions.html
+#[stable(feature = "fs_ext", since = "1.1.0")]
+pub trait PermissionsExt {
+ /// Returns the underlying raw `mode_t` bits that are the standard Redox
+ /// permissions for this file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ /// use std::os::redox::fs::PermissionsExt;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let f = File::create("foo.txt")?;
+ /// let metadata = f.metadata()?;
+ /// let permissions = metadata.permissions();
+ ///
+ /// println!("permissions: {}", permissions.mode());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "fs_ext", since = "1.1.0")]
+ fn mode(&self) -> u32;
+
+ /// Sets the underlying raw bits for this set of permissions.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::File;
+ /// use std::os::redox::fs::PermissionsExt;
+ ///
+ /// fn main() -> std::io::Result<()> {
+ /// let f = File::create("foo.txt")?;
+ /// let metadata = f.metadata()?;
+ /// let mut permissions = metadata.permissions();
+ ///
+ /// permissions.set_mode(0o644); // Read/write for owner and read for others.
+ /// assert_eq!(permissions.mode(), 0o644);
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "fs_ext", since = "1.1.0")]
+ fn set_mode(&mut self, mode: u32);
+
+ /// Creates a new instance of `Permissions` from the given set of Redox
+ /// permission bits.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::fs::Permissions;
+ /// use std::os::redox::fs::PermissionsExt;
+ ///
+ /// // Read/write for owner and read for others.
+ /// let permissions = Permissions::from_mode(0o644);
+ /// assert_eq!(permissions.mode(), 0o644);
+ /// ```
+ #[stable(feature = "fs_ext", since = "1.1.0")]
+ fn from_mode(mode: u32) -> Self;
+}
+
+#[stable(feature = "fs_ext", since = "1.1.0")]
+impl PermissionsExt for Permissions {
+ fn mode(&self) -> u32 {
+ self.as_inner().mode()
+ }
+
+ fn set_mode(&mut self, mode: u32) {
+ *self = Permissions::from_inner(FromInner::from_inner(mode));
+ }
+
+ fn from_mode(mode: u32) -> Permissions {
+ Permissions::from_inner(FromInner::from_inner(mode))
+ }
+}
+
+/// Redox-specific extensions to [`fs::OpenOptions`].
+///
+/// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html
+#[stable(feature = "fs_ext", since = "1.1.0")]
+pub trait OpenOptionsExt {
+ /// Sets the mode bits that a new file will be created with.
+ ///
+ /// If a new file is created as part of a `File::open_opts` call then this
+ /// specified `mode` will be used as the permission bits for the new file.
+ /// If no `mode` is set, the default of `0o666` will be used.
+ /// The operating system masks out bits with the systems `umask`, to produce
+ /// the final permissions.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # #![feature(libc)]
+ /// extern crate libc;
+ /// use std::fs::OpenOptions;
+ /// use std::os::redox::fs::OpenOptionsExt;
+ ///
+ /// # fn main() {
+ /// let mut options = OpenOptions::new();
+ /// options.mode(0o644); // Give read/write for owner and read for others.
+ /// let file = options.open("foo.txt");
+ /// # }
+ /// ```
+ #[stable(feature = "fs_ext", since = "1.1.0")]
+ fn mode(&mut self, mode: u32) -> &mut Self;
+
+ /// Pass custom flags to the `flags` argument of `open`.
+ ///
+ /// The bits that define the access mode are masked out with `O_ACCMODE`, to
+ /// ensure they do not interfere with the access mode set by Rusts options.
+ ///
+ /// Custom flags can only set flags, not remove flags set by Rusts options.
+ /// This options overwrites any previously set custom flags.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// # #![feature(libc)]
+ /// extern crate libc;
+ /// use std::fs::OpenOptions;
+ /// use std::os::redox::fs::OpenOptionsExt;
+ ///
+ /// # fn main() {
+ /// let mut options = OpenOptions::new();
+ /// options.write(true);
+ /// if cfg!(target_os = "redox") {
+ /// options.custom_flags(libc::O_NOFOLLOW);
+ /// }
+ /// let file = options.open("foo.txt");
+ /// # }
+ /// ```
+ #[stable(feature = "open_options_ext", since = "1.10.0")]
+ fn custom_flags(&mut self, flags: i32) -> &mut Self;
+}
+
+#[stable(feature = "fs_ext", since = "1.1.0")]
+impl OpenOptionsExt for OpenOptions {
+ fn mode(&mut self, mode: u32) -> &mut OpenOptions {
+ self.as_inner_mut().mode(mode); self
+ }
+
+ fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions {
+ self.as_inner_mut().custom_flags(flags); self
+ }
+}
+
+/// Redox-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn dev(&self) -> u64;
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn ino(&self) -> u64;
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn mode(&self) -> u32;
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn nlink(&self) -> u64;
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn uid(&self) -> u32;
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn gid(&self) -> u32;
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn size(&self) -> u64;
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn atime(&self) -> i64;
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn atime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn mtime(&self) -> i64;
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn mtime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn ctime(&self) -> i64;
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn ctime_nsec(&self) -> i64;
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn blksize(&self) -> u64;
+ #[stable(feature = "metadata_ext", since = "1.1.0")]
+ fn blocks(&self) -> u64;
+}
+
+// Hm, why are there casts here to the returned type, shouldn't the types always
+// be the same? Right you are! Turns out, however, on android at least the types
+// in the raw `stat` structure are not the same as the types being returned. Who
+// knew!
+//
+// As a result to make sure this compiles for all platforms we do the manual
+// casts and rely on manual lowering to `stat` if the raw type is desired.
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for fs::Metadata {
+ fn dev(&self) -> u64 {
+ self.as_inner().as_inner().st_dev as u64
+ }
+ fn ino(&self) -> u64 {
+ self.as_inner().as_inner().st_ino as u64
+ }
+ fn mode(&self) -> u32 {
+ self.as_inner().as_inner().st_mode as u32
+ }
+ fn nlink(&self) -> u64 {
+ self.as_inner().as_inner().st_nlink as u64
+ }
+ fn uid(&self) -> u32 {
+ self.as_inner().as_inner().st_uid as u32
+ }
+ fn gid(&self) -> u32 {
+ self.as_inner().as_inner().st_gid as u32
+ }
+ fn size(&self) -> u64 {
+ self.as_inner().as_inner().st_size as u64
+ }
+ fn atime(&self) -> i64 {
+ self.as_inner().as_inner().st_atime as i64
+ }
+ fn atime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_atime_nsec as i64
+ }
+ fn mtime(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime as i64
+ }
+ fn mtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_mtime_nsec as i64
+ }
+ fn ctime(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime as i64
+ }
+ fn ctime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_ctime_nsec as i64
+ }
+ fn blksize(&self) -> u64 {
+ self.as_inner().as_inner().st_blksize as u64
+ }
+ fn blocks(&self) -> u64 {
+ self.as_inner().as_inner().st_blocks as u64
+ }
+}
+
+/// Redox-specific extensions for [`FileType`].
+///
+/// Adds support for special Unix file types such as block/character devices,
+/// pipes, and sockets.
+///
+/// [`FileType`]: ../../../../std/fs/struct.FileType.html
+#[stable(feature = "file_type_ext", since = "1.5.0")]
+pub trait FileTypeExt {
+ /// Returns whether this file type is a block device.
+ #[stable(feature = "file_type_ext", since = "1.5.0")]
+ fn is_block_device(&self) -> bool;
+ /// Returns whether this file type is a char device.
+ #[stable(feature = "file_type_ext", since = "1.5.0")]
+ fn is_char_device(&self) -> bool;
+ /// Returns whether this file type is a fifo.
+ #[stable(feature = "file_type_ext", since = "1.5.0")]
+ fn is_fifo(&self) -> bool;
+ /// Returns whether this file type is a socket.
+ #[stable(feature = "file_type_ext", since = "1.5.0")]
+ fn is_socket(&self) -> bool;
+}
+
+#[stable(feature = "file_type_ext", since = "1.5.0")]
+impl FileTypeExt for fs::FileType {
+ fn is_block_device(&self) -> bool { false /*FIXME: Implement block device mode*/ }
+ fn is_char_device(&self) -> bool { false /*FIXME: Implement char device mode*/ }
+ fn is_fifo(&self) -> bool { false /*FIXME: Implement fifo mode*/ }
+ fn is_socket(&self) -> bool { false /*FIXME: Implement socket mode*/ }
+}
+
+/// Creates a new symbolic link on the filesystem.
+///
+/// The `dst` path will be a symbolic link pointing to the `src` path.
+///
+/// # Note
+///
+/// On Windows, you must specify whether a symbolic link points to a file
+/// or directory. Use `os::windows::fs::symlink_file` to create a
+/// symbolic link to a file, or `os::windows::fs::symlink_dir` to create a
+/// symbolic link to a directory. Additionally, the process must have
+/// `SeCreateSymbolicLinkPrivilege` in order to be able to create a
+/// symbolic link.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::os::redox::fs;
+///
+/// fn main() -> std::io::Result<()> {
+/// fs::symlink("a.txt", "b.txt")?;
+/// Ok(())
+/// }
+/// ```
+#[stable(feature = "symlink", since = "1.1.0")]
+pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()>
+{
+ sys::fs::symlink(src.as_ref(), dst.as_ref())
+}
+
+/// Redox-specific extensions to [`fs::DirBuilder`].
+///
+/// [`fs::DirBuilder`]: ../../../../std/fs/struct.DirBuilder.html
+#[stable(feature = "dir_builder", since = "1.6.0")]
+pub trait DirBuilderExt {
+ /// Sets the mode to create new directories with. This option defaults to
+ /// 0o777.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs::DirBuilder;
+ /// use std::os::redox::fs::DirBuilderExt;
+ ///
+ /// let mut builder = DirBuilder::new();
+ /// builder.mode(0o755);
+ /// ```
+ #[stable(feature = "dir_builder", since = "1.6.0")]
+ fn mode(&mut self, mode: u32) -> &mut Self;
+}
+
+#[stable(feature = "dir_builder", since = "1.6.0")]
+impl DirBuilderExt for fs::DirBuilder {
+ fn mode(&mut self, mode: u32) -> &mut fs::DirBuilder {
+ self.as_inner_mut().set_mode(mode);
+ self
+ }
+}
diff --git a/ctr-std/src/sys/redox/ext/io.rs b/ctr-std/src/sys/redox/ext/io.rs
new file mode 100644
index 0000000..c4d9956
--- /dev/null
+++ b/ctr-std/src/sys/redox/ext/io.rs
@@ -0,0 +1,167 @@
+// Copyright 2016 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.
+
+//! Unix-specific extensions to general I/O primitives
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use fs;
+use net;
+use sys;
+use io;
+use sys_common::{self, AsInner, FromInner, IntoInner};
+
+/// Raw file descriptors.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub type RawFd = usize;
+
+/// A trait to extract the raw unix file descriptor from an underlying
+/// object.
+///
+/// This is only available on unix platforms and must be imported in order
+/// to call the method. Windows platforms have a corresponding `AsRawHandle`
+/// and `AsRawSocket` set of traits.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait AsRawFd {
+ /// Extracts the raw file descriptor.
+ ///
+ /// This method does **not** pass ownership of the raw file descriptor
+ /// to the caller. The descriptor is only guaranteed to be valid while
+ /// the original object has not yet been destroyed.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn as_raw_fd(&self) -> RawFd;
+}
+
+/// A trait to express the ability to construct an object from a raw file
+/// descriptor.
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+pub trait FromRawFd {
+ /// Constructs a new instances of `Self` from the given raw file
+ /// descriptor.
+ ///
+ /// This function **consumes ownership** of the specified file
+ /// descriptor. The returned object will take responsibility for closing
+ /// it when the object goes out of scope.
+ ///
+ /// This function is also unsafe as the primitives currently returned
+ /// have the contract that they are the sole owner of the file
+ /// descriptor they are wrapping. Usage of this function could
+ /// accidentally allow violating this contract which can cause memory
+ /// unsafety in code that relies on it being true.
+ #[stable(feature = "from_raw_os", since = "1.1.0")]
+ unsafe fn from_raw_fd(fd: RawFd) -> Self;
+}
+
+/// A trait to express the ability to consume an object and acquire ownership of
+/// its raw file descriptor.
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+pub trait IntoRawFd {
+ /// Consumes this object, returning the raw underlying file descriptor.
+ ///
+ /// This function **transfers ownership** of the underlying file descriptor
+ /// to the caller. Callers are then the unique owners of the file descriptor
+ /// and must close the descriptor once it's no longer needed.
+ #[stable(feature = "into_raw_os", since = "1.4.0")]
+ fn into_raw_fd(self) -> RawFd;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawFd for fs::File {
+ fn as_raw_fd(&self) -> RawFd {
+ self.as_inner().fd().raw()
+ }
+}
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawFd for fs::File {
+ unsafe fn from_raw_fd(fd: RawFd) -> fs::File {
+ fs::File::from_inner(sys::fs::File::from_inner(fd))
+ }
+}
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for fs::File {
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_fd().into_raw()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawFd for net::TcpStream {
+ fn as_raw_fd(&self) -> RawFd {
+ self.as_inner().as_inner().fd().raw()
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawFd for net::TcpListener {
+ fn as_raw_fd(&self) -> RawFd {
+ self.as_inner().as_inner().fd().raw()
+ }
+}
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawFd for net::UdpSocket {
+ fn as_raw_fd(&self) -> RawFd {
+ self.as_inner().as_inner().fd().raw()
+ }
+}
+
+#[stable(feature = "asraw_stdio", since = "1.21.0")]
+impl AsRawFd for io::Stdin {
+ fn as_raw_fd(&self) -> RawFd { 0 }
+}
+
+#[stable(feature = "asraw_stdio", since = "1.21.0")]
+impl AsRawFd for io::Stdout {
+ fn as_raw_fd(&self) -> RawFd { 1 }
+}
+
+#[stable(feature = "asraw_stdio", since = "1.21.0")]
+impl AsRawFd for io::Stderr {
+ fn as_raw_fd(&self) -> RawFd { 2 }
+}
+
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawFd for net::TcpStream {
+ unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream {
+ let file = sys::fs::File::from_inner(fd);
+ net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(file))
+ }
+}
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawFd for net::TcpListener {
+ unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener {
+ let file = sys::fs::File::from_inner(fd);
+ net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(file))
+ }
+}
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawFd for net::UdpSocket {
+ unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket {
+ let file = sys::fs::File::from_inner(fd);
+ net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(file))
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for net::TcpStream {
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_inner().into_fd().into_raw()
+ }
+}
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for net::TcpListener {
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_inner().into_fd().into_raw()
+ }
+}
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for net::UdpSocket {
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_inner().into_fd().into_raw()
+ }
+}
diff --git a/ctr-std/src/sys/redox/ext/mod.rs b/ctr-std/src/sys/redox/ext/mod.rs
new file mode 100644
index 0000000..9fd8d6c
--- /dev/null
+++ b/ctr-std/src/sys/redox/ext/mod.rs
@@ -0,0 +1,54 @@
+// Copyright 2016 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.
+
+//! Experimental extensions to `std` for Unix platforms.
+//!
+//! For now, this module is limited to extracting file descriptors,
+//! but its functionality will grow over time.
+//!
+//! # Examples
+//!
+//! ```no_run
+//! use std::fs::File;
+//! use std::os::unix::prelude::*;
+//!
+//! fn main() {
+//! let f = File::create("foo.txt").unwrap();
+//! let fd = f.as_raw_fd();
+//!
+//! // use fd with native unix bindings
+//! }
+//! ```
+
+#![stable(feature = "rust1", since = "1.0.0")]
+#![doc(cfg(target_os = "redox"))]
+
+pub mod ffi;
+pub mod fs;
+pub mod io;
+pub mod process;
+pub mod thread;
+
+/// A prelude for conveniently writing platform-specific code.
+///
+/// Includes all extension traits, and some important type definitions.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub mod prelude {
+ #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd};
+ #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::ffi::{OsStrExt, OsStringExt};
+ #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::fs::{FileTypeExt, PermissionsExt, OpenOptionsExt, MetadataExt};
+ #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::thread::JoinHandleExt;
+ #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::process::{CommandExt, ExitStatusExt};
+}
diff --git a/ctr-std/src/sys/redox/ext/process.rs b/ctr-std/src/sys/redox/ext/process.rs
new file mode 100644
index 0000000..cfb6d5f
--- /dev/null
+++ b/ctr-std/src/sys/redox/ext/process.rs
@@ -0,0 +1,187 @@
+// Copyright 2016 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.
+
+//! Redox-specific extensions to primitives in the `std::process` module.
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use io;
+use os::unix::io::{FromRawFd, RawFd, AsRawFd, IntoRawFd};
+use process;
+use sys;
+use sys_common::{AsInnerMut, AsInner, FromInner, IntoInner};
+
+/// Redox-specific extensions to the [`process::Command`] builder,
+///
+/// [`process::Command`]: ../../../../std/process/struct.Command.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait CommandExt {
+ /// Sets the child process's user id. This translates to a
+ /// `setuid` call in the child process. Failure in the `setuid`
+ /// call will cause the spawn to fail.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn uid(&mut self, id: u32) -> &mut process::Command;
+
+ /// Similar to `uid`, but sets the group id of the child process. This has
+ /// the same semantics as the `uid` field.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn gid(&mut self, id: u32) -> &mut process::Command;
+
+ /// Schedules a closure to be run just before the `exec` function is
+ /// invoked.
+ ///
+ /// The closure is allowed to return an I/O error whose OS error code will
+ /// be communicated back to the parent and returned as an error from when
+ /// the spawn was requested.
+ ///
+ /// Multiple closures can be registered and they will be called in order of
+ /// their registration. If a closure returns `Err` then no further closures
+ /// will be called and the spawn operation will immediately return with a
+ /// failure.
+ ///
+ /// # Notes
+ ///
+ /// This closure will be run in the context of the child process after a
+ /// `fork`. This primarily means that any modifications made to memory on
+ /// behalf of this closure will **not** be visible to the parent process.
+ /// This is often a very constrained environment where normal operations
+ /// like `malloc` or acquiring a mutex are not guaranteed to work (due to
+ /// other threads perhaps still running when the `fork` was run).
+ ///
+ /// When this closure is run, aspects such as the stdio file descriptors and
+ /// working directory have successfully been changed, so output to these
+ /// locations may not appear where intended.
+ #[stable(feature = "process_exec", since = "1.15.0")]
+ fn before_exec<F>(&mut self, f: F) -> &mut process::Command
+ where F: FnMut() -> io::Result<()> + Send + Sync + 'static;
+
+ /// Performs all the required setup by this `Command`, followed by calling
+ /// the `execvp` syscall.
+ ///
+ /// On success this function will not return, and otherwise it will return
+ /// an error indicating why the exec (or another part of the setup of the
+ /// `Command`) failed.
+ ///
+ /// This function, unlike `spawn`, will **not** `fork` the process to create
+ /// a new child. Like spawn, however, the default behavior for the stdio
+ /// descriptors will be to inherited from the current process.
+ ///
+ /// # Notes
+ ///
+ /// The process may be in a "broken state" if this function returns in
+ /// error. For example the working directory, environment variables, signal
+ /// handling settings, various user/group information, or aspects of stdio
+ /// file descriptors may have changed. If a "transactional spawn" is
+ /// required to gracefully handle errors it is recommended to use the
+ /// cross-platform `spawn` instead.
+ #[stable(feature = "process_exec2", since = "1.9.0")]
+ fn exec(&mut self) -> io::Error;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl CommandExt for process::Command {
+ fn uid(&mut self, id: u32) -> &mut process::Command {
+ self.as_inner_mut().uid(id);
+ self
+ }
+
+ fn gid(&mut self, id: u32) -> &mut process::Command {
+ self.as_inner_mut().gid(id);
+ self
+ }
+
+ fn before_exec<F>(&mut self, f: F) -> &mut process::Command
+ where F: FnMut() -> io::Result<()> + Send + Sync + 'static
+ {
+ self.as_inner_mut().before_exec(Box::new(f));
+ self
+ }
+
+ fn exec(&mut self) -> io::Error {
+ self.as_inner_mut().exec(sys::process::Stdio::Inherit)
+ }
+}
+
+/// Redox-specific extensions to [`process::ExitStatus`].
+///
+/// [`process::ExitStatus`]: ../../../../std/process/struct.ExitStatus.html
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait ExitStatusExt {
+ /// Creates a new `ExitStatus` from the raw underlying `i32` return value of
+ /// a process.
+ #[stable(feature = "exit_status_from", since = "1.12.0")]
+ fn from_raw(raw: i32) -> Self;
+
+ /// If the process was terminated by a signal, returns that signal.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn signal(&self) -> Option<i32>;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl ExitStatusExt for process::ExitStatus {
+ fn from_raw(raw: i32) -> Self {
+ process::ExitStatus::from_inner(From::from(raw))
+ }
+
+ fn signal(&self) -> Option<i32> {
+ self.as_inner().signal()
+ }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl FromRawFd for process::Stdio {
+ unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio {
+ let fd = sys::fd::FileDesc::new(fd);
+ let io = sys::process::Stdio::Fd(fd);
+ process::Stdio::from_inner(io)
+ }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawFd for process::ChildStdin {
+ fn as_raw_fd(&self) -> RawFd {
+ self.as_inner().fd().raw()
+ }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawFd for process::ChildStdout {
+ fn as_raw_fd(&self) -> RawFd {
+ self.as_inner().fd().raw()
+ }
+}
+
+#[stable(feature = "process_extensions", since = "1.2.0")]
+impl AsRawFd for process::ChildStderr {
+ fn as_raw_fd(&self) -> RawFd {
+ self.as_inner().fd().raw()
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for process::ChildStdin {
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_fd().into_raw()
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for process::ChildStdout {
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_fd().into_raw()
+ }
+}
+
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for process::ChildStderr {
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_fd().into_raw()
+ }
+}
diff --git a/ctr-std/src/sys/redox/ext/thread.rs b/ctr-std/src/sys/redox/ext/thread.rs
new file mode 100644
index 0000000..71ff0d4
--- /dev/null
+++ b/ctr-std/src/sys/redox/ext/thread.rs
@@ -0,0 +1,49 @@
+// Copyright 2015 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.
+
+//! Redox-specific extensions to primitives in the `std::thread` module.
+
+#![stable(feature = "thread_extensions", since = "1.9.0")]
+
+use sys_common::{AsInner, IntoInner};
+use thread::JoinHandle;
+
+#[stable(feature = "thread_extensions", since = "1.9.0")]
+#[allow(deprecated)]
+pub type RawPthread = usize;
+
+/// Redox-specific extensions to [`thread::JoinHandle`].
+///
+/// [`thread::JoinHandle`]: ../../../../std/thread/struct.JoinHandle.html
+#[stable(feature = "thread_extensions", since = "1.9.0")]
+pub trait JoinHandleExt {
+ /// Extracts the raw pthread_t without taking ownership
+ #[stable(feature = "thread_extensions", since = "1.9.0")]
+ fn as_pthread_t(&self) -> RawPthread;
+
+ /// Consumes the thread, returning the raw pthread_t
+ ///
+ /// This function **transfers ownership** of the underlying pthread_t to
+ /// the caller. Callers are then the unique owners of the pthread_t and
+ /// must either detach or join the pthread_t once it's no longer needed.
+ #[stable(feature = "thread_extensions", since = "1.9.0")]
+ fn into_pthread_t(self) -> RawPthread;
+}
+
+#[stable(feature = "thread_extensions", since = "1.9.0")]
+impl<T> JoinHandleExt for JoinHandle<T> {
+ fn as_pthread_t(&self) -> RawPthread {
+ self.as_inner().id() as RawPthread
+ }
+
+ fn into_pthread_t(self) -> RawPthread {
+ self.into_inner().into_id() as RawPthread
+ }
+}
diff --git a/ctr-std/src/sys/redox/fast_thread_local.rs b/ctr-std/src/sys/redox/fast_thread_local.rs
new file mode 100644
index 0000000..6a007e9
--- /dev/null
+++ b/ctr-std/src/sys/redox/fast_thread_local.rs
@@ -0,0 +1,121 @@
+// Copyright 2016 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.
+
+#![cfg(target_thread_local)]
+#![unstable(feature = "thread_local_internals", issue = "0")]
+
+use cell::{Cell, UnsafeCell};
+use mem;
+use ptr;
+
+
+pub struct Key<T> {
+ inner: UnsafeCell<Option<T>>,
+
+ // Metadata to keep track of the state of the destructor. Remember that
+ // these variables are thread-local, not global.
+ dtor_registered: Cell<bool>,
+ dtor_running: Cell<bool>,
+}
+
+unsafe impl<T> ::marker::Sync for Key<T> { }
+
+impl<T> Key<T> {
+ pub const fn new() -> Key<T> {
+ Key {
+ inner: UnsafeCell::new(None),
+ dtor_registered: Cell::new(false),
+ dtor_running: Cell::new(false)
+ }
+ }
+
+ pub fn get(&'static self) -> Option<&'static UnsafeCell<Option<T>>> {
+ unsafe {
+ if mem::needs_drop::<T>() && self.dtor_running.get() {
+ return None
+ }
+ self.register_dtor();
+ }
+ Some(&self.inner)
+ }
+
+ unsafe fn register_dtor(&self) {
+ if !mem::needs_drop::<T>() || self.dtor_registered.get() {
+ return
+ }
+
+ register_dtor(self as *const _ as *mut u8,
+ destroy_value::<T>);
+ self.dtor_registered.set(true);
+ }
+}
+
+pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
+ // The fallback implementation uses a vanilla OS-based TLS key to track
+ // the list of destructors that need to be run for this thread. The key
+ // then has its own destructor which runs all the other destructors.
+ //
+ // The destructor for DTORS is a little special in that it has a `while`
+ // loop to continuously drain the list of registered destructors. It
+ // *should* be the case that this loop always terminates because we
+ // provide the guarantee that a TLS key cannot be set after it is
+ // flagged for destruction.
+ use sys_common::thread_local as os;
+
+ static DTORS: os::StaticKey = os::StaticKey::new(Some(run_dtors));
+ type List = Vec<(*mut u8, unsafe extern fn(*mut u8))>;
+ if DTORS.get().is_null() {
+ let v: Box<List> = box Vec::new();
+ DTORS.set(Box::into_raw(v) as *mut u8);
+ }
+ let list: &mut List = &mut *(DTORS.get() as *mut List);
+ list.push((t, dtor));
+
+ unsafe extern fn run_dtors(mut ptr: *mut u8) {
+ while !ptr.is_null() {
+ let list: Box<List> = Box::from_raw(ptr as *mut List);
+ for (ptr, dtor) in list.into_iter() {
+ dtor(ptr);
+ }
+ ptr = DTORS.get();
+ DTORS.set(ptr::null_mut());
+ }
+ }
+}
+
+pub unsafe extern fn destroy_value<T>(ptr: *mut u8) {
+ let ptr = ptr as *mut Key<T>;
+ // Right before we run the user destructor be sure to flag the
+ // destructor as running for this thread so calls to `get` will return
+ // `None`.
+ (*ptr).dtor_running.set(true);
+
+ // The macOS implementation of TLS apparently had an odd aspect to it
+ // where the pointer we have may be overwritten while this destructor
+ // is running. Specifically if a TLS destructor re-accesses TLS it may
+ // trigger a re-initialization of all TLS variables, paving over at
+ // least some destroyed ones with initial values.
+ //
+ // This means that if we drop a TLS value in place on macOS that we could
+ // revert the value to its original state halfway through the
+ // destructor, which would be bad!
+ //
+ // Hence, we use `ptr::read` on macOS (to move to a "safe" location)
+ // instead of drop_in_place.
+ if cfg!(target_os = "macos") {
+ ptr::read((*ptr).inner.get());
+ } else {
+ ptr::drop_in_place((*ptr).inner.get());
+ }
+}
+
+pub fn requires_move_before_drop() -> bool {
+ false
+}
diff --git a/ctr-std/src/sys/redox/fd.rs b/ctr-std/src/sys/redox/fd.rs
new file mode 100644
index 0000000..ba7bbdc
--- /dev/null
+++ b/ctr-std/src/sys/redox/fd.rs
@@ -0,0 +1,95 @@
+// Copyright 2016 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.
+
+#![unstable(reason = "not public", issue = "0", feature = "fd")]
+
+use io::{self, Read};
+use mem;
+use sys::{cvt, syscall};
+use sys_common::AsInner;
+
+pub struct FileDesc {
+ fd: usize,
+}
+
+impl FileDesc {
+ pub fn new(fd: usize) -> FileDesc {
+ FileDesc { fd: fd }
+ }
+
+ pub fn raw(&self) -> usize { self.fd }
+
+ /// Extracts the actual filedescriptor without closing it.
+ pub fn into_raw(self) -> usize {
+ let fd = self.fd;
+ mem::forget(self);
+ fd
+ }
+
+ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+ cvt(syscall::read(self.fd, buf))
+ }
+
+ pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
+ let mut me = self;
+ (&mut me).read_to_end(buf)
+ }
+
+ pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+ cvt(syscall::write(self.fd, buf))
+ }
+
+ pub fn duplicate(&self) -> io::Result<FileDesc> {
+ let new_fd = cvt(syscall::dup(self.fd, &[]))?;
+ Ok(FileDesc::new(new_fd))
+ }
+
+ pub fn nonblocking(&self) -> io::Result<bool> {
+ let flags = cvt(syscall::fcntl(self.fd, syscall::F_GETFL, 0))?;
+ Ok(flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK)
+ }
+
+ pub fn set_cloexec(&self) -> io::Result<()> {
+ let mut flags = cvt(syscall::fcntl(self.fd, syscall::F_GETFD, 0))?;
+ flags |= syscall::O_CLOEXEC;
+ cvt(syscall::fcntl(self.fd, syscall::F_SETFD, flags)).and(Ok(()))
+ }
+
+ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+ let mut flags = cvt(syscall::fcntl(self.fd, syscall::F_GETFL, 0))?;
+ if nonblocking {
+ flags |= syscall::O_NONBLOCK;
+ } else {
+ flags &= !syscall::O_NONBLOCK;
+ }
+ cvt(syscall::fcntl(self.fd, syscall::F_SETFL, flags)).and(Ok(()))
+ }
+}
+
+impl<'a> Read for &'a FileDesc {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ (**self).read(buf)
+ }
+}
+
+impl AsInner<usize> for FileDesc {
+ fn as_inner(&self) -> &usize { &self.fd }
+}
+
+impl Drop for FileDesc {
+ fn drop(&mut self) {
+ // Note that errors are ignored when closing a file descriptor. The
+ // reason for this is that if an error occurs we don't actually know if
+ // the file descriptor was closed or not, and if we retried (for
+ // something like EINTR), we might close another valid file descriptor
+ // (opened after we closed ours.
+ let _ = syscall::close(self.fd);
+ }
+}
diff --git a/ctr-std/src/sys/redox/fs.rs b/ctr-std/src/sys/redox/fs.rs
new file mode 100644
index 0000000..2e22161
--- /dev/null
+++ b/ctr-std/src/sys/redox/fs.rs
@@ -0,0 +1,483 @@
+// Copyright 2016 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 os::unix::prelude::*;
+
+use ffi::{OsString, OsStr};
+use fmt;
+use io::{self, Error, ErrorKind, SeekFrom};
+use path::{Path, PathBuf};
+use sync::Arc;
+use sys::fd::FileDesc;
+use sys::time::SystemTime;
+use sys::{cvt, syscall};
+use sys_common::{AsInner, FromInner};
+
+pub struct File(FileDesc);
+
+#[derive(Clone)]
+pub struct FileAttr {
+ stat: syscall::Stat,
+}
+
+pub struct ReadDir {
+ data: Vec<u8>,
+ i: usize,
+ root: Arc<PathBuf>,
+}
+
+struct Dir(FileDesc);
+
+unsafe impl Send for Dir {}
+unsafe impl Sync for Dir {}
+
+pub struct DirEntry {
+ root: Arc<PathBuf>,
+ name: Box<[u8]>
+}
+
+#[derive(Clone, Debug)]
+pub struct OpenOptions {
+ // generic
+ read: bool,
+ write: bool,
+ append: bool,
+ truncate: bool,
+ create: bool,
+ create_new: bool,
+ // system-specific
+ custom_flags: i32,
+ mode: u16,
+}
+
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub struct FilePermissions { mode: u16 }
+
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
+pub struct FileType { mode: u16 }
+
+#[derive(Debug)]
+pub struct DirBuilder { mode: u16 }
+
+impl FileAttr {
+ pub fn size(&self) -> u64 { self.stat.st_size as u64 }
+ pub fn perm(&self) -> FilePermissions {
+ FilePermissions { mode: (self.stat.st_mode as u16) & 0o777 }
+ }
+
+ pub fn file_type(&self) -> FileType {
+ FileType { mode: self.stat.st_mode as u16 }
+ }
+}
+
+impl FileAttr {
+ pub fn modified(&self) -> io::Result<SystemTime> {
+ Ok(SystemTime::from(syscall::TimeSpec {
+ tv_sec: self.stat.st_mtime as i64,
+ tv_nsec: self.stat.st_mtime_nsec as i32,
+ }))
+ }
+
+ pub fn accessed(&self) -> io::Result<SystemTime> {
+ Ok(SystemTime::from(syscall::TimeSpec {
+ tv_sec: self.stat.st_atime as i64,
+ tv_nsec: self.stat.st_atime_nsec as i32,
+ }))
+ }
+
+ pub fn created(&self) -> io::Result<SystemTime> {
+ Ok(SystemTime::from(syscall::TimeSpec {
+ tv_sec: self.stat.st_ctime as i64,
+ tv_nsec: self.stat.st_ctime_nsec as i32,
+ }))
+ }
+}
+
+impl AsInner<syscall::Stat> for FileAttr {
+ fn as_inner(&self) -> &syscall::Stat { &self.stat }
+}
+
+impl FilePermissions {
+ pub fn readonly(&self) -> bool { self.mode & 0o222 == 0 }
+ pub fn set_readonly(&mut self, readonly: bool) {
+ if readonly {
+ self.mode &= !0o222;
+ } else {
+ self.mode |= 0o222;
+ }
+ }
+ pub fn mode(&self) -> u32 { self.mode as u32 }
+}
+
+impl FileType {
+ pub fn is_dir(&self) -> bool { self.is(syscall::MODE_DIR) }
+ pub fn is_file(&self) -> bool { self.is(syscall::MODE_FILE) }
+ pub fn is_symlink(&self) -> bool { self.is(syscall::MODE_SYMLINK) }
+
+ pub fn is(&self, mode: u16) -> bool {
+ self.mode & syscall::MODE_TYPE == mode
+ }
+}
+
+impl FromInner<u32> for FilePermissions {
+ fn from_inner(mode: u32) -> FilePermissions {
+ FilePermissions { mode: mode as u16 }
+ }
+}
+
+impl fmt::Debug for ReadDir {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame.
+ // Thus the result will be e g 'ReadDir("/home")'
+ fmt::Debug::fmt(&*self.root, f)
+ }
+}
+
+impl Iterator for ReadDir {
+ type Item = io::Result<DirEntry>;
+
+ fn next(&mut self) -> Option<io::Result<DirEntry>> {
+ loop {
+ let start = self.i;
+ let mut i = self.i;
+ while i < self.data.len() {
+ self.i += 1;
+ if self.data[i] == b'\n' {
+ break;
+ }
+ i += 1;
+ }
+ if start < self.i {
+ let ret = DirEntry {
+ name: self.data[start .. i].to_owned().into_boxed_slice(),
+ root: self.root.clone()
+ };
+ if ret.name_bytes() != b"." && ret.name_bytes() != b".." {
+ return Some(Ok(ret))
+ }
+ } else {
+ return None;
+ }
+ }
+ }
+}
+
+impl DirEntry {
+ pub fn path(&self) -> PathBuf {
+ self.root.join(OsStr::from_bytes(self.name_bytes()))
+ }
+
+ pub fn file_name(&self) -> OsString {
+ OsStr::from_bytes(self.name_bytes()).to_os_string()
+ }
+
+ pub fn metadata(&self) -> io::Result<FileAttr> {
+ lstat(&self.path())
+ }
+
+ pub fn file_type(&self) -> io::Result<FileType> {
+ lstat(&self.path()).map(|m| m.file_type())
+ }
+
+ fn name_bytes(&self) -> &[u8] {
+ &*self.name
+ }
+}
+
+impl OpenOptions {
+ pub fn new() -> OpenOptions {
+ OpenOptions {
+ // generic
+ read: false,
+ write: false,
+ append: false,
+ truncate: false,
+ create: false,
+ create_new: false,
+ // system-specific
+ custom_flags: 0,
+ mode: 0o666,
+ }
+ }
+
+ pub fn read(&mut self, read: bool) { self.read = read; }
+ pub fn write(&mut self, write: bool) { self.write = write; }
+ pub fn append(&mut self, append: bool) { self.append = append; }
+ pub fn truncate(&mut self, truncate: bool) { self.truncate = truncate; }
+ pub fn create(&mut self, create: bool) { self.create = create; }
+ pub fn create_new(&mut self, create_new: bool) { self.create_new = create_new; }
+
+ pub fn custom_flags(&mut self, flags: i32) { self.custom_flags = flags; }
+ pub fn mode(&mut self, mode: u32) { self.mode = mode as u16; }
+
+ fn get_access_mode(&self) -> io::Result<usize> {
+ match (self.read, self.write, self.append) {
+ (true, false, false) => Ok(syscall::O_RDONLY),
+ (false, true, false) => Ok(syscall::O_WRONLY),
+ (true, true, false) => Ok(syscall::O_RDWR),
+ (false, _, true) => Ok(syscall::O_WRONLY | syscall::O_APPEND),
+ (true, _, true) => Ok(syscall::O_RDWR | syscall::O_APPEND),
+ (false, false, false) => Err(Error::from_raw_os_error(syscall::EINVAL)),
+ }
+ }
+
+ fn get_creation_mode(&self) -> io::Result<usize> {
+ match (self.write, self.append) {
+ (true, false) => {}
+ (false, false) =>
+ if self.truncate || self.create || self.create_new {
+ return Err(Error::from_raw_os_error(syscall::EINVAL));
+ },
+ (_, true) =>
+ if self.truncate && !self.create_new {
+ return Err(Error::from_raw_os_error(syscall::EINVAL));
+ },
+ }
+
+ Ok(match (self.create, self.truncate, self.create_new) {
+ (false, false, false) => 0,
+ (true, false, false) => syscall::O_CREAT,
+ (false, true, false) => syscall::O_TRUNC,
+ (true, true, false) => syscall::O_CREAT | syscall::O_TRUNC,
+ (_, _, true) => syscall::O_CREAT | syscall::O_EXCL,
+ })
+ }
+}
+
+impl File {
+ pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
+ let flags = syscall::O_CLOEXEC |
+ opts.get_access_mode()? as usize |
+ opts.get_creation_mode()? as usize |
+ (opts.custom_flags as usize & !syscall::O_ACCMODE);
+ let fd = cvt(syscall::open(path.to_str().unwrap(), flags | opts.mode as usize))?;
+ Ok(File(FileDesc::new(fd)))
+ }
+
+ pub fn file_attr(&self) -> io::Result<FileAttr> {
+ let mut stat = syscall::Stat::default();
+ cvt(syscall::fstat(self.0.raw(), &mut stat))?;
+ Ok(FileAttr { stat: stat })
+ }
+
+ pub fn fsync(&self) -> io::Result<()> {
+ cvt(syscall::fsync(self.0.raw()))?;
+ Ok(())
+ }
+
+ pub fn datasync(&self) -> io::Result<()> {
+ self.fsync()
+ }
+
+ pub fn truncate(&self, size: u64) -> io::Result<()> {
+ cvt(syscall::ftruncate(self.0.raw(), size as usize))?;
+ Ok(())
+ }
+
+ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.0.read(buf)
+ }
+
+ pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+ self.0.write(buf)
+ }
+
+ pub fn flush(&self) -> io::Result<()> { Ok(()) }
+
+ pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
+ let (whence, pos) = match pos {
+ // Casting to `i64` is fine, too large values will end up as
+ // negative which will cause an error in `lseek64`.
+ SeekFrom::Start(off) => (syscall::SEEK_SET, off as i64),
+ SeekFrom::End(off) => (syscall::SEEK_END, off),
+ SeekFrom::Current(off) => (syscall::SEEK_CUR, off),
+ };
+ let n = cvt(syscall::lseek(self.0.raw(), pos as isize, whence))?;
+ Ok(n as u64)
+ }
+
+ pub fn duplicate(&self) -> io::Result<File> {
+ self.0.duplicate().map(File)
+ }
+
+ pub fn dup(&self, buf: &[u8]) -> io::Result<File> {
+ let fd = cvt(syscall::dup(*self.fd().as_inner() as usize, buf))?;
+ Ok(File(FileDesc::new(fd)))
+ }
+
+ pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> {
+ set_perm(&self.path()?, perm)
+ }
+
+ pub fn path(&self) -> io::Result<PathBuf> {
+ let mut buf: [u8; 4096] = [0; 4096];
+ let count = cvt(syscall::fpath(*self.fd().as_inner() as usize, &mut buf))?;
+ Ok(PathBuf::from(unsafe { String::from_utf8_unchecked(Vec::from(&buf[..count])) }))
+ }
+
+ pub fn fd(&self) -> &FileDesc { &self.0 }
+
+ pub fn into_fd(self) -> FileDesc { self.0 }
+}
+
+impl DirBuilder {
+ pub fn new() -> DirBuilder {
+ DirBuilder { mode: 0o777 }
+ }
+
+ pub fn mkdir(&self, p: &Path) -> io::Result<()> {
+ let flags = syscall::O_CREAT | syscall::O_CLOEXEC | syscall::O_DIRECTORY | syscall::O_EXCL;
+ let fd = cvt(syscall::open(p.to_str().unwrap(), flags | (self.mode as usize & 0o777)))?;
+ let _ = syscall::close(fd);
+ Ok(())
+ }
+
+ pub fn set_mode(&mut self, mode: u32) {
+ self.mode = mode as u16;
+ }
+}
+
+impl FromInner<usize> for File {
+ fn from_inner(fd: usize) -> File {
+ File(FileDesc::new(fd))
+ }
+}
+
+impl fmt::Debug for File {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let mut b = f.debug_struct("File");
+ b.field("fd", &self.0.raw());
+ if let Ok(path) = self.path() {
+ b.field("path", &path);
+ }
+ /*
+ if let Some((read, write)) = get_mode(fd) {
+ b.field("read", &read).field("write", &write);
+ }
+ */
+ b.finish()
+ }
+}
+
+pub fn readdir(p: &Path) -> io::Result<ReadDir> {
+ let root = Arc::new(p.to_path_buf());
+
+ let flags = syscall::O_CLOEXEC | syscall::O_RDONLY | syscall::O_DIRECTORY;
+ let fd = cvt(syscall::open(p.to_str().unwrap(), flags))?;
+ let file = FileDesc::new(fd);
+ let mut data = Vec::new();
+ file.read_to_end(&mut data)?;
+
+ Ok(ReadDir { data: data, i: 0, root: root })
+}
+
+pub fn unlink(p: &Path) -> io::Result<()> {
+ cvt(syscall::unlink(p.to_str().unwrap()))?;
+ Ok(())
+}
+
+pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
+ let fd = cvt(syscall::open(old.to_str().unwrap(),
+ syscall::O_CLOEXEC | syscall::O_STAT | syscall::O_NOFOLLOW))?;
+ let res = cvt(syscall::frename(fd, new.to_str().unwrap()));
+ cvt(syscall::close(fd))?;
+ res?;
+ Ok(())
+}
+
+pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> {
+ cvt(syscall::chmod(p.to_str().unwrap(), perm.mode as usize))?;
+ Ok(())
+}
+
+pub fn rmdir(p: &Path) -> io::Result<()> {
+ cvt(syscall::rmdir(p.to_str().unwrap()))?;
+ Ok(())
+}
+
+pub fn remove_dir_all(path: &Path) -> io::Result<()> {
+ let filetype = lstat(path)?.file_type();
+ if filetype.is_symlink() {
+ unlink(path)
+ } else {
+ remove_dir_all_recursive(path)
+ }
+}
+
+fn remove_dir_all_recursive(path: &Path) -> io::Result<()> {
+ for child in readdir(path)? {
+ let child = child?;
+ if child.file_type()?.is_dir() {
+ remove_dir_all_recursive(&child.path())?;
+ } else {
+ unlink(&child.path())?;
+ }
+ }
+ rmdir(path)
+}
+
+pub fn readlink(p: &Path) -> io::Result<PathBuf> {
+ let fd = cvt(syscall::open(p.to_str().unwrap(),
+ syscall::O_CLOEXEC | syscall::O_SYMLINK | syscall::O_RDONLY))?;
+ let mut buf: [u8; 4096] = [0; 4096];
+ let res = cvt(syscall::read(fd, &mut buf));
+ cvt(syscall::close(fd))?;
+ let count = res?;
+ Ok(PathBuf::from(unsafe { String::from_utf8_unchecked(Vec::from(&buf[..count])) }))
+}
+
+pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> {
+ let fd = cvt(syscall::open(dst.to_str().unwrap(),
+ syscall::O_CLOEXEC | syscall::O_SYMLINK |
+ syscall::O_CREAT | syscall::O_WRONLY | 0o777))?;
+ let res = cvt(syscall::write(fd, src.to_str().unwrap().as_bytes()));
+ cvt(syscall::close(fd))?;
+ res?;
+ Ok(())
+}
+
+pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> {
+ Err(Error::from_raw_os_error(syscall::ENOSYS))
+}
+
+pub fn stat(p: &Path) -> io::Result<FileAttr> {
+ let fd = cvt(syscall::open(p.to_str().unwrap(), syscall::O_CLOEXEC | syscall::O_STAT))?;
+ let file = File(FileDesc::new(fd));
+ file.file_attr()
+}
+
+pub fn lstat(p: &Path) -> io::Result<FileAttr> {
+ let fd = cvt(syscall::open(p.to_str().unwrap(),
+ syscall::O_CLOEXEC | syscall::O_STAT | syscall::O_NOFOLLOW))?;
+ let file = File(FileDesc::new(fd));
+ file.file_attr()
+}
+
+pub fn canonicalize(p: &Path) -> io::Result<PathBuf> {
+ let fd = cvt(syscall::open(p.to_str().unwrap(), syscall::O_CLOEXEC | syscall::O_STAT))?;
+ let file = File(FileDesc::new(fd));
+ file.path()
+}
+
+pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
+ use fs::{File, set_permissions};
+ if !from.is_file() {
+ return Err(Error::new(ErrorKind::InvalidInput,
+ "the source path is not an existing regular file"))
+ }
+
+ let mut reader = File::open(from)?;
+ let mut writer = File::create(to)?;
+ let perm = reader.metadata()?.permissions();
+
+ let ret = io::copy(&mut reader, &mut writer)?;
+ set_permissions(to, perm)?;
+ Ok(ret)
+}
diff --git a/ctr-std/src/sys/redox/memchr.rs b/ctr-std/src/sys/redox/memchr.rs
new file mode 100644
index 0000000..873b335
--- /dev/null
+++ b/ctr-std/src/sys/redox/memchr.rs
@@ -0,0 +1,14 @@
+// Copyright 2015 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.
+//
+// Original implementation taken from rust-memchr
+// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
+
+pub use core::slice::memchr::{memchr, memrchr};
diff --git a/ctr-std/src/sys/redox/mod.rs b/ctr-std/src/sys/redox/mod.rs
new file mode 100644
index 0000000..4352b72
--- /dev/null
+++ b/ctr-std/src/sys/redox/mod.rs
@@ -0,0 +1,81 @@
+// Copyright 2016 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(dead_code, missing_docs, bad_style)]
+
+use io::{self, ErrorKind};
+
+pub use libc::strlen;
+pub use self::rand::hashmap_random_keys;
+
+pub mod args;
+#[cfg(feature = "backtrace")]
+pub mod backtrace;
+pub mod cmath;
+pub mod condvar;
+pub mod env;
+pub mod ext;
+pub mod fast_thread_local;
+pub mod fd;
+pub mod fs;
+pub mod memchr;
+pub mod mutex;
+pub mod net;
+pub mod os;
+pub mod os_str;
+pub mod path;
+pub mod pipe;
+pub mod process;
+pub mod rand;
+pub mod rwlock;
+pub mod stack_overflow;
+pub mod stdio;
+pub mod syscall;
+pub mod thread;
+pub mod thread_local;
+pub mod time;
+
+#[cfg(not(test))]
+pub fn init() {}
+
+pub fn decode_error_kind(errno: i32) -> ErrorKind {
+ match errno {
+ syscall::ECONNREFUSED => ErrorKind::ConnectionRefused,
+ syscall::ECONNRESET => ErrorKind::ConnectionReset,
+ syscall::EPERM | syscall::EACCES => ErrorKind::PermissionDenied,
+ syscall::EPIPE => ErrorKind::BrokenPipe,
+ syscall::ENOTCONN => ErrorKind::NotConnected,
+ syscall::ECONNABORTED => ErrorKind::ConnectionAborted,
+ syscall::EADDRNOTAVAIL => ErrorKind::AddrNotAvailable,
+ syscall::EADDRINUSE => ErrorKind::AddrInUse,
+ syscall::ENOENT => ErrorKind::NotFound,
+ syscall::EINTR => ErrorKind::Interrupted,
+ syscall::EINVAL => ErrorKind::InvalidInput,
+ syscall::ETIMEDOUT => ErrorKind::TimedOut,
+ syscall::EEXIST => ErrorKind::AlreadyExists,
+
+ // 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 == syscall::EAGAIN || x == syscall::EWOULDBLOCK =>
+ ErrorKind::WouldBlock,
+
+ _ => ErrorKind::Other,
+ }
+}
+
+pub fn cvt(result: Result<usize, syscall::Error>) -> io::Result<usize> {
+ result.map_err(|err| io::Error::from_raw_os_error(err.errno))
+}
+
+/// On Redox, use an illegal instruction to abort
+pub unsafe fn abort_internal() -> ! {
+ ::core::intrinsics::abort();
+}
diff --git a/ctr-std/src/sys/redox/mutex.rs b/ctr-std/src/sys/redox/mutex.rs
new file mode 100644
index 0000000..a995f59
--- /dev/null
+++ b/ctr-std/src/sys/redox/mutex.rs
@@ -0,0 +1,179 @@
+// Copyright 2016 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 cell::UnsafeCell;
+use intrinsics::{atomic_cxchg, atomic_xchg};
+use ptr;
+
+use sys::syscall::{futex, getpid, FUTEX_WAIT, FUTEX_WAKE};
+
+pub unsafe fn mutex_try_lock(m: *mut i32) -> bool {
+ atomic_cxchg(m, 0, 1).0 == 0
+}
+
+pub unsafe fn mutex_lock(m: *mut i32) {
+ let mut c = 0;
+ //Set to larger value for longer spin test
+ for _i in 0..100 {
+ c = atomic_cxchg(m, 0, 1).0;
+ if c == 0 {
+ break;
+ }
+ //cpu_relax()
+ }
+ if c == 1 {
+ c = atomic_xchg(m, 2);
+ }
+ while c != 0 {
+ let _ = futex(m, FUTEX_WAIT, 2, 0, ptr::null_mut());
+ c = atomic_xchg(m, 2);
+ }
+}
+
+pub unsafe fn mutex_unlock(m: *mut i32) {
+ if *m == 2 {
+ *m = 0;
+ } else if atomic_xchg(m, 0) == 1 {
+ return;
+ }
+ //Set to larger value for longer spin test
+ for _i in 0..100 {
+ if *m != 0 {
+ if atomic_cxchg(m, 1, 2).0 != 0 {
+ return;
+ }
+ }
+ //cpu_relax()
+ }
+ let _ = futex(m, FUTEX_WAKE, 1, 0, ptr::null_mut());
+}
+
+pub struct Mutex {
+ pub lock: UnsafeCell<i32>,
+}
+
+impl Mutex {
+ /// Create a new mutex.
+ pub const fn new() -> Self {
+ Mutex {
+ lock: UnsafeCell::new(0),
+ }
+ }
+
+ #[inline]
+ pub unsafe fn init(&self) {
+ *self.lock.get() = 0;
+ }
+
+ /// Try to lock the mutex
+ #[inline]
+ pub unsafe fn try_lock(&self) -> bool {
+ mutex_try_lock(self.lock.get())
+ }
+
+ /// Lock the mutex
+ #[inline]
+ pub unsafe fn lock(&self) {
+ mutex_lock(self.lock.get());
+ }
+
+ /// Unlock the mutex
+ #[inline]
+ pub unsafe fn unlock(&self) {
+ mutex_unlock(self.lock.get());
+ }
+
+ #[inline]
+ pub unsafe fn destroy(&self) {
+ *self.lock.get() = 0;
+ }
+}
+
+unsafe impl Send for Mutex {}
+
+unsafe impl Sync for Mutex {}
+
+pub struct ReentrantMutex {
+ pub lock: UnsafeCell<i32>,
+ pub owner: UnsafeCell<usize>,
+ pub own_count: UnsafeCell<usize>,
+}
+
+impl ReentrantMutex {
+ pub const fn uninitialized() -> Self {
+ ReentrantMutex {
+ lock: UnsafeCell::new(0),
+ owner: UnsafeCell::new(0),
+ own_count: UnsafeCell::new(0),
+ }
+ }
+
+ #[inline]
+ pub unsafe fn init(&mut self) {
+ *self.lock.get() = 0;
+ *self.owner.get() = 0;
+ *self.own_count.get() = 0;
+ }
+
+ /// Try to lock the mutex
+ #[inline]
+ pub unsafe fn try_lock(&self) -> bool {
+ let pid = getpid().unwrap();
+ if *self.own_count.get() > 0 && *self.owner.get() == pid {
+ *self.own_count.get() += 1;
+ true
+ } else {
+ if mutex_try_lock(self.lock.get()) {
+ *self.owner.get() = pid;
+ *self.own_count.get() = 1;
+ true
+ } else {
+ false
+ }
+ }
+ }
+
+ /// Lock the mutex
+ #[inline]
+ pub unsafe fn lock(&self) {
+ let pid = getpid().unwrap();
+ if *self.own_count.get() > 0 && *self.owner.get() == pid {
+ *self.own_count.get() += 1;
+ } else {
+ mutex_lock(self.lock.get());
+ *self.owner.get() = pid;
+ *self.own_count.get() = 1;
+ }
+ }
+
+ /// Unlock the mutex
+ #[inline]
+ pub unsafe fn unlock(&self) {
+ let pid = getpid().unwrap();
+ if *self.own_count.get() > 0 && *self.owner.get() == pid {
+ *self.own_count.get() -= 1;
+ if *self.own_count.get() == 0 {
+ *self.owner.get() = 0;
+ mutex_unlock(self.lock.get());
+ }
+ }
+ }
+
+ #[inline]
+ pub unsafe fn destroy(&self) {
+ *self.lock.get() = 0;
+ *self.owner.get() = 0;
+ *self.own_count.get() = 0;
+ }
+}
+
+unsafe impl Send for ReentrantMutex {}
+
+unsafe impl Sync for ReentrantMutex {}
diff --git a/ctr-std/src/sys/redox/net/dns/answer.rs b/ctr-std/src/sys/redox/net/dns/answer.rs
new file mode 100644
index 0000000..8e6aaeb
--- /dev/null
+++ b/ctr-std/src/sys/redox/net/dns/answer.rs
@@ -0,0 +1,22 @@
+// Copyright 2016 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 string::String;
+use vec::Vec;
+
+#[derive(Clone, Debug)]
+pub struct DnsAnswer {
+ pub name: String,
+ pub a_type: u16,
+ pub a_class: u16,
+ pub ttl_a: u16,
+ pub ttl_b: u16,
+ pub data: Vec<u8>
+}
diff --git a/ctr-std/src/sys/redox/net/dns/mod.rs b/ctr-std/src/sys/redox/net/dns/mod.rs
new file mode 100644
index 0000000..1a26257
--- /dev/null
+++ b/ctr-std/src/sys/redox/net/dns/mod.rs
@@ -0,0 +1,215 @@
+// Copyright 2016 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.
+
+pub use self::answer::DnsAnswer;
+pub use self::query::DnsQuery;
+
+use slice;
+use u16;
+use string::String;
+use vec::Vec;
+
+mod answer;
+mod query;
+
+#[unstable(feature = "n16", issue="0")]
+#[allow(non_camel_case_types)]
+#[derive(Copy, Clone, Debug, Default)]
+#[repr(packed)]
+pub struct n16 {
+ inner: u16
+}
+
+impl n16 {
+ #[unstable(feature = "n16", issue="0")]
+ pub fn as_bytes(&self) -> &[u8] {
+ unsafe { slice::from_raw_parts((&self.inner as *const u16) as *const u8, 2) }
+ }
+
+ #[unstable(feature = "n16", issue="0")]
+ pub fn from_bytes(bytes: &[u8]) -> Self {
+ n16 {
+ inner: unsafe { slice::from_raw_parts(bytes.as_ptr() as *const u16, bytes.len()/2)[0] }
+ }
+ }
+}
+
+#[unstable(feature = "n16", issue="0")]
+impl From<u16> for n16 {
+ fn from(value: u16) -> Self {
+ n16 {
+ inner: value.to_be()
+ }
+ }
+}
+
+#[unstable(feature = "n16", issue="0")]
+impl From<n16> for u16 {
+ fn from(value: n16) -> Self {
+ u16::from_be(value.inner)
+ }
+}
+
+#[derive(Clone, Debug)]
+pub struct Dns {
+ pub transaction_id: u16,
+ pub flags: u16,
+ pub queries: Vec<DnsQuery>,
+ pub answers: Vec<DnsAnswer>
+}
+
+impl Dns {
+ pub fn compile(&self) -> Vec<u8> {
+ let mut data = Vec::new();
+
+ macro_rules! push_u8 {
+ ($value:expr) => {
+ data.push($value);
+ };
+ };
+
+ macro_rules! push_n16 {
+ ($value:expr) => {
+ data.extend_from_slice(n16::from($value).as_bytes());
+ };
+ };
+
+ push_n16!(self.transaction_id);
+ push_n16!(self.flags);
+ push_n16!(self.queries.len() as u16);
+ push_n16!(self.answers.len() as u16);
+ push_n16!(0);
+ push_n16!(0);
+
+ for query in self.queries.iter() {
+ for part in query.name.split('.') {
+ push_u8!(part.len() as u8);
+ data.extend_from_slice(part.as_bytes());
+ }
+ push_u8!(0);
+ push_n16!(query.q_type);
+ push_n16!(query.q_class);
+ }
+
+ data
+ }
+
+ pub fn parse(data: &[u8]) -> Result<Self, String> {
+ let name_ind = 0b11000000;
+ let mut i = 0;
+
+ macro_rules! pop_u8 {
+ () => {
+ {
+ i += 1;
+ if i > data.len() {
+ return Err(format!("{}: {}: pop_u8", file!(), line!()));
+ }
+ data[i - 1]
+ }
+ };
+ };
+
+ macro_rules! pop_n16 {
+ () => {
+ {
+ i += 2;
+ if i > data.len() {
+ return Err(format!("{}: {}: pop_n16", file!(), line!()));
+ }
+ u16::from(n16::from_bytes(&data[i - 2 .. i]))
+ }
+ };
+ };
+
+ macro_rules! pop_data {
+ () => {
+ {
+ let mut data = Vec::new();
+
+ let data_len = pop_n16!();
+ for _data_i in 0..data_len {
+ data.push(pop_u8!());
+ }
+
+ data
+ }
+ };
+ };
+
+ macro_rules! pop_name {
+ () => {
+ {
+ let mut name = String::new();
+ let old_i = i;
+
+ loop {
+ let name_len = pop_u8!();
+ if name_len & name_ind == name_ind {
+ i -= 1;
+ i = (pop_n16!() - ((name_ind as u16) << 8)) as usize;
+ continue;
+ }
+ if name_len == 0 {
+ break;
+ }
+ if ! name.is_empty() {
+ name.push('.');
+ }
+ for _name_i in 0..name_len {
+ name.push(pop_u8!() as char);
+ }
+ }
+
+ if i <= old_i {
+ i = old_i + 2;
+ }
+
+ name
+ }
+ };
+ };
+
+ let transaction_id = pop_n16!();
+ let flags = pop_n16!();
+ let queries_len = pop_n16!();
+ let answers_len = pop_n16!();
+ pop_n16!();
+ pop_n16!();
+
+ let mut queries = Vec::new();
+ for _query_i in 0..queries_len {
+ queries.push(DnsQuery {
+ name: pop_name!(),
+ q_type: pop_n16!(),
+ q_class: pop_n16!()
+ });
+ }
+
+ let mut answers = Vec::new();
+ for _answer_i in 0..answers_len {
+ answers.push(DnsAnswer {
+ name: pop_name!(),
+ a_type: pop_n16!(),
+ a_class: pop_n16!(),
+ ttl_a: pop_n16!(),
+ ttl_b: pop_n16!(),
+ data: pop_data!()
+ });
+ }
+
+ Ok(Dns {
+ transaction_id,
+ flags,
+ queries,
+ answers,
+ })
+ }
+}
diff --git a/ctr-std/src/sys/redox/net/dns/query.rs b/ctr-std/src/sys/redox/net/dns/query.rs
new file mode 100644
index 0000000..b0dcdcb
--- /dev/null
+++ b/ctr-std/src/sys/redox/net/dns/query.rs
@@ -0,0 +1,18 @@
+// Copyright 2016 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 string::String;
+
+#[derive(Clone, Debug)]
+pub struct DnsQuery {
+ pub name: String,
+ pub q_type: u16,
+ pub q_class: u16
+}
diff --git a/ctr-std/src/sys/redox/net/mod.rs b/ctr-std/src/sys/redox/net/mod.rs
new file mode 100644
index 0000000..0291d7f
--- /dev/null
+++ b/ctr-std/src/sys/redox/net/mod.rs
@@ -0,0 +1,115 @@
+// Copyright 2016 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 fs::File;
+use io::{Error, Result, Read};
+use iter::Iterator;
+use net::{Ipv4Addr, SocketAddr, SocketAddrV4};
+use str::FromStr;
+use string::{String, ToString};
+use sys::syscall::EINVAL;
+use time::{self, Duration};
+use vec::{IntoIter, Vec};
+
+use self::dns::{Dns, DnsQuery};
+
+pub use self::tcp::{TcpStream, TcpListener};
+pub use self::udp::UdpSocket;
+
+pub mod netc;
+
+mod dns;
+mod tcp;
+mod udp;
+
+pub struct LookupHost(IntoIter<SocketAddr>);
+
+impl Iterator for LookupHost {
+ type Item = SocketAddr;
+ fn next(&mut self) -> Option<Self::Item> {
+ self.0.next()
+ }
+}
+
+pub fn lookup_host(host: &str) -> Result<LookupHost> {
+ let mut ip_string = String::new();
+ File::open("/etc/net/ip")?.read_to_string(&mut ip_string)?;
+ let ip: Vec<u8> = ip_string.trim().split(".").map(|part| part.parse::<u8>()
+ .unwrap_or(0)).collect();
+
+ let mut dns_string = String::new();
+ File::open("/etc/net/dns")?.read_to_string(&mut dns_string)?;
+ let dns: Vec<u8> = dns_string.trim().split(".").map(|part| part.parse::<u8>()
+ .unwrap_or(0)).collect();
+
+ if ip.len() == 4 && dns.len() == 4 {
+ let time = time::SystemTime::now().duration_since(time::UNIX_EPOCH).unwrap();
+ let tid = (time.subsec_nanos() >> 16) as u16;
+
+ let packet = Dns {
+ transaction_id: tid,
+ flags: 0x0100,
+ queries: vec![DnsQuery {
+ name: host.to_string(),
+ q_type: 0x0001,
+ q_class: 0x0001,
+ }],
+ answers: vec![]
+ };
+
+ let packet_data = packet.compile();
+
+ let my_ip = Ipv4Addr::new(ip[0], ip[1], ip[2], ip[3]);
+ let dns_ip = Ipv4Addr::new(dns[0], dns[1], dns[2], dns[3]);
+ let socket = UdpSocket::bind(&SocketAddr::V4(SocketAddrV4::new(my_ip, 0)))?;
+ socket.set_read_timeout(Some(Duration::new(5, 0)))?;
+ socket.set_write_timeout(Some(Duration::new(5, 0)))?;
+ socket.connect(&SocketAddr::V4(SocketAddrV4::new(dns_ip, 53)))?;
+ socket.send(&packet_data)?;
+
+ let mut buf = [0; 65536];
+ let count = socket.recv(&mut buf)?;
+
+ match Dns::parse(&buf[.. count]) {
+ Ok(response) => {
+ let mut addrs = vec![];
+ for answer in response.answers.iter() {
+ if answer.a_type == 0x0001 && answer.a_class == 0x0001
+ && answer.data.len() == 4
+ {
+ let answer_ip = Ipv4Addr::new(answer.data[0],
+ answer.data[1],
+ answer.data[2],
+ answer.data[3]);
+ addrs.push(SocketAddr::V4(SocketAddrV4::new(answer_ip, 0)));
+ }
+ }
+ Ok(LookupHost(addrs.into_iter()))
+ },
+ Err(_err) => Err(Error::from_raw_os_error(EINVAL))
+ }
+ } else {
+ Err(Error::from_raw_os_error(EINVAL))
+ }
+}
+
+fn path_to_peer_addr(path_str: &str) -> SocketAddr {
+ let mut parts = path_str.split('/').next().unwrap_or("").split(':').skip(1);
+ let host = Ipv4Addr::from_str(parts.next().unwrap_or("")).unwrap_or(Ipv4Addr::new(0, 0, 0, 0));
+ let port = parts.next().unwrap_or("").parse::<u16>().unwrap_or(0);
+ SocketAddr::V4(SocketAddrV4::new(host, port))
+}
+
+fn path_to_local_addr(path_str: &str) -> SocketAddr {
+ let mut parts = path_str.split('/').nth(1).unwrap_or("").split(':');
+ let host = Ipv4Addr::from_str(parts.next().unwrap_or("")).unwrap_or(Ipv4Addr::new(0, 0, 0, 0));
+ let port = parts.next().unwrap_or("").parse::<u16>().unwrap_or(0);
+ SocketAddr::V4(SocketAddrV4::new(host, port))
+}
diff --git a/ctr-std/src/sys/redox/net/netc.rs b/ctr-std/src/sys/redox/net/netc.rs
new file mode 100644
index 0000000..d443a4d
--- /dev/null
+++ b/ctr-std/src/sys/redox/net/netc.rs
@@ -0,0 +1,57 @@
+// Copyright 2016 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.
+
+pub type in_addr_t = u32;
+pub type in_port_t = u16;
+
+pub type socklen_t = u32;
+pub type sa_family_t = u16;
+
+pub const AF_INET: sa_family_t = 2;
+pub const AF_INET6: sa_family_t = 23;
+
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub struct in_addr {
+ pub s_addr: in_addr_t,
+}
+
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub struct in6_addr {
+ pub s6_addr: [u8; 16],
+ __align: [u32; 0],
+}
+
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub struct sockaddr {
+ pub sa_family: sa_family_t,
+ pub sa_data: [u8; 14],
+}
+
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub struct sockaddr_in {
+ pub sin_family: sa_family_t,
+ pub sin_port: in_port_t,
+ pub sin_addr: in_addr,
+ pub sin_zero: [u8; 8],
+}
+
+#[derive(Copy, Clone)]
+#[repr(C)]
+pub struct sockaddr_in6 {
+ pub sin6_family: sa_family_t,
+ pub sin6_port: in_port_t,
+ pub sin6_flowinfo: u32,
+ pub sin6_addr: in6_addr,
+ pub sin6_scope_id: u32,
+}
diff --git a/ctr-std/src/sys/redox/net/tcp.rs b/ctr-std/src/sys/redox/net/tcp.rs
new file mode 100644
index 0000000..b566490
--- /dev/null
+++ b/ctr-std/src/sys/redox/net/tcp.rs
@@ -0,0 +1,253 @@
+// Copyright 2016 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 cmp;
+use io::{self, Error, ErrorKind, Result};
+use mem;
+use net::{SocketAddr, Shutdown};
+use path::Path;
+use sys::fs::{File, OpenOptions};
+use sys::syscall::TimeSpec;
+use sys_common::{AsInner, FromInner, IntoInner};
+use time::Duration;
+
+use super::{path_to_peer_addr, path_to_local_addr};
+
+#[derive(Debug)]
+pub struct TcpStream(File);
+
+impl TcpStream {
+ pub fn connect(addr: &SocketAddr) -> Result<TcpStream> {
+ let path = format!("tcp:{}", addr);
+ let mut options = OpenOptions::new();
+ options.read(true);
+ options.write(true);
+ Ok(TcpStream(File::open(Path::new(path.as_str()), &options)?))
+ }
+
+ pub fn connect_timeout(_addr: &SocketAddr, _timeout: Duration) -> Result<TcpStream> {
+ Err(Error::new(ErrorKind::Other, "TcpStream::connect_timeout not implemented"))
+ }
+
+ pub fn duplicate(&self) -> Result<TcpStream> {
+ Ok(TcpStream(self.0.dup(&[])?))
+ }
+
+ pub fn read(&self, buf: &mut [u8]) -> Result<usize> {
+ self.0.read(buf)
+ }
+
+ pub fn write(&self, buf: &[u8]) -> Result<usize> {
+ self.0.write(buf)
+ }
+
+ pub fn take_error(&self) -> Result<Option<Error>> {
+ Ok(None)
+ }
+
+ pub fn peer_addr(&self) -> Result<SocketAddr> {
+ let path = self.0.path()?;
+ Ok(path_to_peer_addr(path.to_str().unwrap_or("")))
+ }
+
+ pub fn socket_addr(&self) -> Result<SocketAddr> {
+ let path = self.0.path()?;
+ Ok(path_to_local_addr(path.to_str().unwrap_or("")))
+ }
+
+ pub fn peek(&self, _buf: &mut [u8]) -> Result<usize> {
+ Err(Error::new(ErrorKind::Other, "TcpStream::peek not implemented"))
+ }
+
+ pub fn shutdown(&self, _how: Shutdown) -> Result<()> {
+ Err(Error::new(ErrorKind::Other, "TcpStream::shutdown not implemented"))
+ }
+
+ pub fn nodelay(&self) -> Result<bool> {
+ Err(Error::new(ErrorKind::Other, "TcpStream::nodelay not implemented"))
+ }
+
+ pub fn nonblocking(&self) -> Result<bool> {
+ self.0.fd().nonblocking()
+ }
+
+ pub fn only_v6(&self) -> Result<bool> {
+ Err(Error::new(ErrorKind::Other, "TcpStream::only_v6 not implemented"))
+ }
+
+ pub fn ttl(&self) -> Result<u32> {
+ let mut ttl = [0];
+ let file = self.0.dup(b"ttl")?;
+ file.read(&mut ttl)?;
+ Ok(ttl[0] as u32)
+ }
+
+ pub fn read_timeout(&self) -> Result<Option<Duration>> {
+ let mut time = TimeSpec::default();
+ let file = self.0.dup(b"read_timeout")?;
+ if file.read(&mut time)? >= mem::size_of::<TimeSpec>() {
+ Ok(Some(Duration::new(time.tv_sec as u64, time.tv_nsec as u32)))
+ } else {
+ Ok(None)
+ }
+ }
+
+ pub fn write_timeout(&self) -> Result<Option<Duration>> {
+ let mut time = TimeSpec::default();
+ let file = self.0.dup(b"write_timeout")?;
+ if file.read(&mut time)? >= mem::size_of::<TimeSpec>() {
+ Ok(Some(Duration::new(time.tv_sec as u64, time.tv_nsec as u32)))
+ } else {
+ Ok(None)
+ }
+ }
+
+ pub fn set_nodelay(&self, _nodelay: bool) -> Result<()> {
+ Err(Error::new(ErrorKind::Other, "TcpStream::set_nodelay not implemented"))
+ }
+
+ pub fn set_nonblocking(&self, nonblocking: bool) -> Result<()> {
+ self.0.fd().set_nonblocking(nonblocking)
+ }
+
+ pub fn set_only_v6(&self, _only_v6: bool) -> Result<()> {
+ Err(Error::new(ErrorKind::Other, "TcpStream::set_only_v6 not implemented"))
+ }
+
+ pub fn set_ttl(&self, ttl: u32) -> Result<()> {
+ let file = self.0.dup(b"ttl")?;
+ file.write(&[cmp::min(ttl, 255) as u8])?;
+ Ok(())
+ }
+
+ pub fn set_read_timeout(&self, duration_option: Option<Duration>) -> Result<()> {
+ let file = self.0.dup(b"read_timeout")?;
+ if let Some(duration) = duration_option {
+ if duration.as_secs() == 0 && duration.subsec_nanos() == 0 {
+ return Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "cannot set a 0 duration timeout"));
+ }
+ file.write(&TimeSpec {
+ tv_sec: duration.as_secs() as i64,
+ tv_nsec: duration.subsec_nanos() as i32
+ })?;
+ } else {
+ file.write(&[])?;
+ }
+ Ok(())
+ }
+
+ pub fn set_write_timeout(&self, duration_option: Option<Duration>) -> Result<()> {
+ let file = self.0.dup(b"write_timeout")?;
+ if let Some(duration) = duration_option {
+ if duration.as_secs() == 0 && duration.subsec_nanos() == 0 {
+ return Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "cannot set a 0 duration timeout"));
+ }
+ file.write(&TimeSpec {
+ tv_sec: duration.as_secs() as i64,
+ tv_nsec: duration.subsec_nanos() as i32
+ })?;
+ } else {
+ file.write(&[])?;
+ }
+ Ok(())
+ }
+}
+
+impl AsInner<File> for TcpStream {
+ fn as_inner(&self) -> &File { &self.0 }
+}
+
+impl FromInner<File> for TcpStream {
+ fn from_inner(file: File) -> TcpStream {
+ TcpStream(file)
+ }
+}
+
+impl IntoInner<File> for TcpStream {
+ fn into_inner(self) -> File { self.0 }
+}
+
+#[derive(Debug)]
+pub struct TcpListener(File);
+
+impl TcpListener {
+ pub fn bind(addr: &SocketAddr) -> Result<TcpListener> {
+ let path = format!("tcp:/{}", addr);
+ let mut options = OpenOptions::new();
+ options.read(true);
+ options.write(true);
+ Ok(TcpListener(File::open(Path::new(path.as_str()), &options)?))
+ }
+
+ pub fn accept(&self) -> Result<(TcpStream, SocketAddr)> {
+ let file = self.0.dup(b"listen")?;
+ let path = file.path()?;
+ let peer_addr = path_to_peer_addr(path.to_str().unwrap_or(""));
+ Ok((TcpStream(file), peer_addr))
+ }
+
+ pub fn duplicate(&self) -> Result<TcpListener> {
+ Ok(TcpListener(self.0.dup(&[])?))
+ }
+
+ pub fn take_error(&self) -> Result<Option<Error>> {
+ Ok(None)
+ }
+
+ pub fn socket_addr(&self) -> Result<SocketAddr> {
+ let path = self.0.path()?;
+ Ok(path_to_local_addr(path.to_str().unwrap_or("")))
+ }
+
+ pub fn nonblocking(&self) -> Result<bool> {
+ Err(Error::new(ErrorKind::Other, "TcpListener::nonblocking not implemented"))
+ }
+
+ pub fn only_v6(&self) -> Result<bool> {
+ Err(Error::new(ErrorKind::Other, "TcpListener::only_v6 not implemented"))
+ }
+
+ pub fn ttl(&self) -> Result<u32> {
+ let mut ttl = [0];
+ let file = self.0.dup(b"ttl")?;
+ file.read(&mut ttl)?;
+ Ok(ttl[0] as u32)
+ }
+
+ pub fn set_nonblocking(&self, _nonblocking: bool) -> Result<()> {
+ Err(Error::new(ErrorKind::Other, "TcpListener::set_nonblocking not implemented"))
+ }
+
+ pub fn set_only_v6(&self, _only_v6: bool) -> Result<()> {
+ Err(Error::new(ErrorKind::Other, "TcpListener::set_only_v6 not implemented"))
+ }
+
+ pub fn set_ttl(&self, ttl: u32) -> Result<()> {
+ let file = self.0.dup(b"ttl")?;
+ file.write(&[cmp::min(ttl, 255) as u8])?;
+ Ok(())
+ }
+}
+
+impl AsInner<File> for TcpListener {
+ fn as_inner(&self) -> &File { &self.0 }
+}
+
+impl FromInner<File> for TcpListener {
+ fn from_inner(file: File) -> TcpListener {
+ TcpListener(file)
+ }
+}
+
+impl IntoInner<File> for TcpListener {
+ fn into_inner(self) -> File { self.0 }
+}
diff --git a/ctr-std/src/sys/redox/net/udp.rs b/ctr-std/src/sys/redox/net/udp.rs
new file mode 100644
index 0000000..2ed67bd
--- /dev/null
+++ b/ctr-std/src/sys/redox/net/udp.rs
@@ -0,0 +1,242 @@
+// Copyright 2016 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 cell::UnsafeCell;
+use cmp;
+use io::{self, Error, ErrorKind, Result};
+use mem;
+use net::{SocketAddr, Ipv4Addr, Ipv6Addr};
+use path::Path;
+use sys::fs::{File, OpenOptions};
+use sys::syscall::TimeSpec;
+use sys_common::{AsInner, FromInner, IntoInner};
+use time::Duration;
+
+use super::{path_to_peer_addr, path_to_local_addr};
+
+#[derive(Debug)]
+pub struct UdpSocket(File, UnsafeCell<Option<SocketAddr>>);
+
+impl UdpSocket {
+ pub fn bind(addr: &SocketAddr) -> Result<UdpSocket> {
+ let path = format!("udp:/{}", addr);
+ let mut options = OpenOptions::new();
+ options.read(true);
+ options.write(true);
+ Ok(UdpSocket(File::open(Path::new(path.as_str()), &options)?, UnsafeCell::new(None)))
+ }
+
+ fn get_conn(&self) -> &mut Option<SocketAddr> {
+ unsafe { &mut *(self.1.get()) }
+ }
+
+ pub fn connect(&self, addr: &SocketAddr) -> Result<()> {
+ unsafe { *self.1.get() = Some(*addr) };
+ Ok(())
+ }
+
+ pub fn duplicate(&self) -> Result<UdpSocket> {
+ let new_bind = self.0.dup(&[])?;
+ let new_conn = *self.get_conn();
+ Ok(UdpSocket(new_bind, UnsafeCell::new(new_conn)))
+ }
+
+ pub fn recv_from(&self, buf: &mut [u8]) -> Result<(usize, SocketAddr)> {
+ let from = self.0.dup(b"listen")?;
+ let path = from.path()?;
+ let peer_addr = path_to_peer_addr(path.to_str().unwrap_or(""));
+ let count = from.read(buf)?;
+ Ok((count, peer_addr))
+ }
+
+ pub fn recv(&self, buf: &mut [u8]) -> Result<usize> {
+ if let Some(addr) = *self.get_conn() {
+ let from = self.0.dup(format!("{}", addr).as_bytes())?;
+ from.read(buf)
+ } else {
+ Err(Error::new(ErrorKind::Other, "UdpSocket::recv not connected"))
+ }
+ }
+
+ pub fn send_to(&self, buf: &[u8], addr: &SocketAddr) -> Result<usize> {
+ let to = self.0.dup(format!("{}", addr).as_bytes())?;
+ to.write(buf)
+ }
+
+ pub fn send(&self, buf: &[u8]) -> Result<usize> {
+ if let Some(addr) = *self.get_conn() {
+ self.send_to(buf, &addr)
+ } else {
+ Err(Error::new(ErrorKind::Other, "UdpSocket::send not connected"))
+ }
+ }
+
+ pub fn take_error(&self) -> Result<Option<Error>> {
+ Ok(None)
+ }
+
+ pub fn socket_addr(&self) -> Result<SocketAddr> {
+ let path = self.0.path()?;
+ Ok(path_to_local_addr(path.to_str().unwrap_or("")))
+ }
+
+ pub fn peek(&self, _buf: &mut [u8]) -> Result<usize> {
+ Err(Error::new(ErrorKind::Other, "UdpSocket::peek not implemented"))
+ }
+
+ pub fn peek_from(&self, _buf: &mut [u8]) -> Result<(usize, SocketAddr)> {
+ Err(Error::new(ErrorKind::Other, "UdpSocket::peek_from not implemented"))
+ }
+
+ pub fn broadcast(&self) -> Result<bool> {
+ Err(Error::new(ErrorKind::Other, "UdpSocket::broadcast not implemented"))
+ }
+
+ pub fn multicast_loop_v4(&self) -> Result<bool> {
+ Err(Error::new(ErrorKind::Other, "UdpSocket::multicast_loop_v4 not implemented"))
+ }
+
+ pub fn multicast_loop_v6(&self) -> Result<bool> {
+ Err(Error::new(ErrorKind::Other, "UdpSocket::multicast_loop_v6 not implemented"))
+ }
+
+ pub fn multicast_ttl_v4(&self) -> Result<u32> {
+ Err(Error::new(ErrorKind::Other, "UdpSocket::multicast_ttl_v4 not implemented"))
+ }
+
+ pub fn nonblocking(&self) -> Result<bool> {
+ self.0.fd().nonblocking()
+ }
+
+ pub fn only_v6(&self) -> Result<bool> {
+ Err(Error::new(ErrorKind::Other, "UdpSocket::only_v6 not implemented"))
+ }
+
+ pub fn ttl(&self) -> Result<u32> {
+ let mut ttl = [0];
+ let file = self.0.dup(b"ttl")?;
+ file.read(&mut ttl)?;
+ Ok(ttl[0] as u32)
+ }
+
+ pub fn read_timeout(&self) -> Result<Option<Duration>> {
+ let mut time = TimeSpec::default();
+ let file = self.0.dup(b"read_timeout")?;
+ if file.read(&mut time)? >= mem::size_of::<TimeSpec>() {
+ Ok(Some(Duration::new(time.tv_sec as u64, time.tv_nsec as u32)))
+ } else {
+ Ok(None)
+ }
+ }
+
+ pub fn write_timeout(&self) -> Result<Option<Duration>> {
+ let mut time = TimeSpec::default();
+ let file = self.0.dup(b"write_timeout")?;
+ if file.read(&mut time)? >= mem::size_of::<TimeSpec>() {
+ Ok(Some(Duration::new(time.tv_sec as u64, time.tv_nsec as u32)))
+ } else {
+ Ok(None)
+ }
+ }
+
+ pub fn set_broadcast(&self, _broadcast: bool) -> Result<()> {
+ Err(Error::new(ErrorKind::Other, "UdpSocket::set_broadcast not implemented"))
+ }
+
+ pub fn set_multicast_loop_v4(&self, _multicast_loop_v4: bool) -> Result<()> {
+ Err(Error::new(ErrorKind::Other, "UdpSocket::set_multicast_loop_v4 not implemented"))
+ }
+
+ pub fn set_multicast_loop_v6(&self, _multicast_loop_v6: bool) -> Result<()> {
+ Err(Error::new(ErrorKind::Other, "UdpSocket::set_multicast_loop_v6 not implemented"))
+ }
+
+ pub fn set_multicast_ttl_v4(&self, _multicast_ttl_v4: u32) -> Result<()> {
+ Err(Error::new(ErrorKind::Other, "UdpSocket::set_multicast_ttl_v4 not implemented"))
+ }
+
+ pub fn set_nonblocking(&self, nonblocking: bool) -> Result<()> {
+ self.0.fd().set_nonblocking(nonblocking)
+ }
+
+ pub fn set_only_v6(&self, _only_v6: bool) -> Result<()> {
+ Err(Error::new(ErrorKind::Other, "UdpSocket::set_only_v6 not implemented"))
+ }
+
+ pub fn set_ttl(&self, ttl: u32) -> Result<()> {
+ let file = self.0.dup(b"ttl")?;
+ file.write(&[cmp::min(ttl, 255) as u8])?;
+ Ok(())
+ }
+
+ pub fn set_read_timeout(&self, duration_option: Option<Duration>) -> Result<()> {
+ let file = self.0.dup(b"read_timeout")?;
+ if let Some(duration) = duration_option {
+ if duration.as_secs() == 0 && duration.subsec_nanos() == 0 {
+ return Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "cannot set a 0 duration timeout"));
+ }
+ file.write(&TimeSpec {
+ tv_sec: duration.as_secs() as i64,
+ tv_nsec: duration.subsec_nanos() as i32
+ })?;
+ } else {
+ file.write(&[])?;
+ }
+ Ok(())
+ }
+
+ pub fn set_write_timeout(&self, duration_option: Option<Duration>) -> Result<()> {
+ let file = self.0.dup(b"write_timeout")?;
+ if let Some(duration) = duration_option {
+ if duration.as_secs() == 0 && duration.subsec_nanos() == 0 {
+ return Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "cannot set a 0 duration timeout"));
+ }
+ file.write(&TimeSpec {
+ tv_sec: duration.as_secs() as i64,
+ tv_nsec: duration.subsec_nanos() as i32
+ })?;
+ } else {
+ file.write(&[])?;
+ }
+ Ok(())
+ }
+
+ pub fn join_multicast_v4(&self, _multiaddr: &Ipv4Addr, _interface: &Ipv4Addr) -> Result<()> {
+ Err(Error::new(ErrorKind::Other, "UdpSocket::join_multicast_v4 not implemented"))
+ }
+
+ pub fn join_multicast_v6(&self, _multiaddr: &Ipv6Addr, _interface: u32) -> Result<()> {
+ Err(Error::new(ErrorKind::Other, "UdpSocket::join_multicast_v6 not implemented"))
+ }
+
+ pub fn leave_multicast_v4(&self, _multiaddr: &Ipv4Addr, _interface: &Ipv4Addr) -> Result<()> {
+ Err(Error::new(ErrorKind::Other, "UdpSocket::leave_multicast_v4 not implemented"))
+ }
+
+ pub fn leave_multicast_v6(&self, _multiaddr: &Ipv6Addr, _interface: u32) -> Result<()> {
+ Err(Error::new(ErrorKind::Other, "UdpSocket::leave_multicast_v6 not implemented"))
+ }
+}
+
+impl AsInner<File> for UdpSocket {
+ fn as_inner(&self) -> &File { &self.0 }
+}
+
+impl FromInner<File> for UdpSocket {
+ fn from_inner(file: File) -> UdpSocket {
+ UdpSocket(file, UnsafeCell::new(None))
+ }
+}
+
+impl IntoInner<File> for UdpSocket {
+ fn into_inner(self) -> File { self.0 }
+}
diff --git a/ctr-std/src/sys/redox/os.rs b/ctr-std/src/sys/redox/os.rs
new file mode 100644
index 0000000..480765b
--- /dev/null
+++ b/ctr-std/src/sys/redox/os.rs
@@ -0,0 +1,219 @@
+// Copyright 2016 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.
+
+//! Implementation of `std::os` functionality for unix systems
+
+#![allow(unused_imports)] // lots of cfg code here
+
+use os::unix::prelude::*;
+
+use error::Error as StdError;
+use ffi::{OsString, OsStr};
+use fmt;
+use io::{self, Read, Write};
+use iter;
+use marker::PhantomData;
+use mem;
+use memchr;
+use path::{self, PathBuf};
+use ptr;
+use slice;
+use str;
+use sys_common::mutex::Mutex;
+use sys::{cvt, fd, syscall};
+use vec;
+
+const TMPBUF_SZ: usize = 128;
+static ENV_LOCK: Mutex = Mutex::new();
+
+extern {
+ #[link_name = "__errno_location"]
+ fn errno_location() -> *mut i32;
+}
+
+/// Returns the platform-specific value of errno
+pub fn errno() -> i32 {
+ unsafe {
+ (*errno_location())
+ }
+}
+
+/// Gets a detailed string description for the given error number.
+pub fn error_string(errno: i32) -> String {
+ if let Some(string) = syscall::STR_ERROR.get(errno as usize) {
+ string.to_string()
+ } else {
+ "unknown error".to_string()
+ }
+}
+
+pub fn getcwd() -> io::Result<PathBuf> {
+ let mut buf = [0; 4096];
+ let count = cvt(syscall::getcwd(&mut buf))?;
+ Ok(PathBuf::from(OsString::from_vec(buf[.. count].to_vec())))
+}
+
+pub fn chdir(p: &path::Path) -> io::Result<()> {
+ cvt(syscall::chdir(p.to_str().unwrap())).and(Ok(()))
+}
+
+pub struct SplitPaths<'a> {
+ iter: iter::Map<slice::Split<'a, u8, fn(&u8) -> bool>,
+ fn(&'a [u8]) -> PathBuf>,
+}
+
+pub fn split_paths(unparsed: &OsStr) -> SplitPaths {
+ fn bytes_to_path(b: &[u8]) -> PathBuf {
+ PathBuf::from(<OsStr as OsStrExt>::from_bytes(b))
+ }
+ fn is_semicolon(b: &u8) -> bool { *b == b';' }
+ let unparsed = unparsed.as_bytes();
+ SplitPaths {
+ iter: unparsed.split(is_semicolon as fn(&u8) -> bool)
+ .map(bytes_to_path as fn(&[u8]) -> PathBuf)
+ }
+}
+
+impl<'a> Iterator for SplitPaths<'a> {
+ type Item = PathBuf;
+ fn next(&mut self) -> Option<PathBuf> { self.iter.next() }
+ fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
+}
+
+#[derive(Debug)]
+pub struct JoinPathsError;
+
+pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
+ where I: Iterator<Item=T>, T: AsRef<OsStr>
+{
+ let mut joined = Vec::new();
+ let sep = b';';
+
+ for (i, path) in paths.enumerate() {
+ let path = path.as_ref().as_bytes();
+ if i > 0 { joined.push(sep) }
+ if path.contains(&sep) {
+ return Err(JoinPathsError)
+ }
+ joined.extend_from_slice(path);
+ }
+ Ok(OsStringExt::from_vec(joined))
+}
+
+impl fmt::Display for JoinPathsError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ "path segment contains separator `:`".fmt(f)
+ }
+}
+
+impl StdError for JoinPathsError {
+ fn description(&self) -> &str { "failed to join paths" }
+}
+
+pub fn current_exe() -> io::Result<PathBuf> {
+ use fs::File;
+
+ let mut file = File::open("sys:exe")?;
+
+ let mut path = String::new();
+ file.read_to_string(&mut path)?;
+
+ if path.ends_with('\n') {
+ path.pop();
+ }
+
+ Ok(PathBuf::from(path))
+}
+
+pub struct Env {
+ iter: vec::IntoIter<(OsString, OsString)>,
+ _dont_send_or_sync_me: PhantomData<*mut ()>,
+}
+
+impl Iterator for Env {
+ type Item = (OsString, OsString);
+ fn next(&mut self) -> Option<(OsString, OsString)> { self.iter.next() }
+ fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
+}
+
+/// Returns a vector of (variable, value) byte-vector pairs for all the
+/// environment variables of the current process.
+pub fn env() -> Env {
+ let mut variables: Vec<(OsString, OsString)> = Vec::new();
+ if let Ok(mut file) = ::fs::File::open("env:") {
+ let mut string = String::new();
+ if file.read_to_string(&mut string).is_ok() {
+ for line in string.lines() {
+ let mut parts = line.splitn(2, '=');
+ if let Some(name) = parts.next() {
+ let value = parts.next().unwrap_or("");
+ variables.push((OsString::from(name.to_string()),
+ OsString::from(value.to_string())));
+ }
+ }
+ }
+ }
+ Env { iter: variables.into_iter(), _dont_send_or_sync_me: PhantomData }
+}
+
+pub fn getenv(key: &OsStr) -> io::Result<Option<OsString>> {
+ if ! key.is_empty() {
+ if let Ok(mut file) = ::fs::File::open(&("env:".to_owned() + key.to_str().unwrap())) {
+ let mut string = String::new();
+ file.read_to_string(&mut string)?;
+ Ok(Some(OsString::from(string)))
+ } else {
+ Ok(None)
+ }
+ } else {
+ Ok(None)
+ }
+}
+
+pub fn setenv(key: &OsStr, value: &OsStr) -> io::Result<()> {
+ if ! key.is_empty() {
+ let mut file = ::fs::File::create(&("env:".to_owned() + key.to_str().unwrap()))?;
+ file.write_all(value.as_bytes())?;
+ file.set_len(value.len() as u64)?;
+ }
+ Ok(())
+}
+
+pub fn unsetenv(key: &OsStr) -> io::Result<()> {
+ ::fs::remove_file(&("env:".to_owned() + key.to_str().unwrap()))?;
+ Ok(())
+}
+
+pub fn page_size() -> usize {
+ 4096
+}
+
+pub fn temp_dir() -> PathBuf {
+ ::env::var_os("TMPDIR").map(PathBuf::from).unwrap_or_else(|| {
+ PathBuf::from("/tmp")
+ })
+}
+
+pub fn home_dir() -> Option<PathBuf> {
+ return ::env::var_os("HOME").map(PathBuf::from);
+}
+
+pub fn exit(code: i32) -> ! {
+ let _ = syscall::exit(code as usize);
+ unreachable!();
+}
+
+pub fn getpid() -> u32 {
+ syscall::getpid().unwrap() as u32
+}
+
+pub fn getppid() -> u32 {
+ syscall::getppid().unwrap() as u32
+}
diff --git a/ctr-std/src/sys/redox/os_str.rs b/ctr-std/src/sys/redox/os_str.rs
new file mode 100644
index 0000000..eb3a1ea
--- /dev/null
+++ b/ctr-std/src/sys/redox/os_str.rs
@@ -0,0 +1,189 @@
+// Copyright 2016 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.
+
+/// The underlying OsString/OsStr implementation on Unix systems: just
+/// a `Vec<u8>`/`[u8]`.
+
+use borrow::Cow;
+use fmt;
+use str;
+use mem;
+use rc::Rc;
+use sync::Arc;
+use sys_common::{AsInner, IntoInner};
+use sys_common::bytestring::debug_fmt_bytestring;
+use core::str::lossy::Utf8Lossy;
+
+#[derive(Clone, Hash)]
+pub struct Buf {
+ pub inner: Vec<u8>
+}
+
+pub struct Slice {
+ pub inner: [u8]
+}
+
+impl fmt::Debug for Slice {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ debug_fmt_bytestring(&self.inner, formatter)
+ }
+}
+
+impl fmt::Display for Slice {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(&Utf8Lossy::from_bytes(&self.inner), formatter)
+ }
+}
+
+impl fmt::Debug for Buf {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Debug::fmt(self.as_slice(), formatter)
+ }
+}
+
+impl fmt::Display for Buf {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(self.as_slice(), formatter)
+ }
+}
+
+impl IntoInner<Vec<u8>> for Buf {
+ fn into_inner(self) -> Vec<u8> {
+ self.inner
+ }
+}
+
+impl AsInner<[u8]> for Buf {
+ fn as_inner(&self) -> &[u8] {
+ &self.inner
+ }
+}
+
+
+impl Buf {
+ pub fn from_string(s: String) -> Buf {
+ Buf { inner: s.into_bytes() }
+ }
+
+ #[inline]
+ pub fn with_capacity(capacity: usize) -> Buf {
+ Buf {
+ inner: Vec::with_capacity(capacity)
+ }
+ }
+
+ #[inline]
+ pub fn clear(&mut self) {
+ self.inner.clear()
+ }
+
+ #[inline]
+ pub fn capacity(&self) -> usize {
+ self.inner.capacity()
+ }
+
+ #[inline]
+ pub fn reserve(&mut self, additional: usize) {
+ self.inner.reserve(additional)
+ }
+
+ #[inline]
+ pub fn reserve_exact(&mut self, additional: usize) {
+ self.inner.reserve_exact(additional)
+ }
+
+ #[inline]
+ pub fn shrink_to_fit(&mut self) {
+ self.inner.shrink_to_fit()
+ }
+
+ #[inline]
+ pub fn shrink_to(&mut self, min_capacity: usize) {
+ self.inner.shrink_to(min_capacity)
+ }
+
+ pub fn as_slice(&self) -> &Slice {
+ unsafe { mem::transmute(&*self.inner) }
+ }
+
+ pub fn into_string(self) -> Result<String, Buf> {
+ String::from_utf8(self.inner).map_err(|p| Buf { inner: p.into_bytes() } )
+ }
+
+ pub fn push_slice(&mut self, s: &Slice) {
+ self.inner.extend_from_slice(&s.inner)
+ }
+
+ #[inline]
+ pub fn into_box(self) -> Box<Slice> {
+ unsafe { mem::transmute(self.inner.into_boxed_slice()) }
+ }
+
+ #[inline]
+ pub fn from_box(boxed: Box<Slice>) -> Buf {
+ let inner: Box<[u8]> = unsafe { mem::transmute(boxed) };
+ Buf { inner: inner.into_vec() }
+ }
+
+ #[inline]
+ pub fn into_arc(&self) -> Arc<Slice> {
+ self.as_slice().into_arc()
+ }
+
+ #[inline]
+ pub fn into_rc(&self) -> Rc<Slice> {
+ self.as_slice().into_rc()
+ }
+}
+
+impl Slice {
+ fn from_u8_slice(s: &[u8]) -> &Slice {
+ unsafe { mem::transmute(s) }
+ }
+
+ pub fn from_str(s: &str) -> &Slice {
+ Slice::from_u8_slice(s.as_bytes())
+ }
+
+ pub fn to_str(&self) -> Option<&str> {
+ str::from_utf8(&self.inner).ok()
+ }
+
+ pub fn to_string_lossy(&self) -> Cow<str> {
+ String::from_utf8_lossy(&self.inner)
+ }
+
+ pub fn to_owned(&self) -> Buf {
+ Buf { inner: self.inner.to_vec() }
+ }
+
+ #[inline]
+ pub fn into_box(&self) -> Box<Slice> {
+ let boxed: Box<[u8]> = self.inner.into();
+ unsafe { mem::transmute(boxed) }
+ }
+
+ pub fn empty_box() -> Box<Slice> {
+ let boxed: Box<[u8]> = Default::default();
+ unsafe { mem::transmute(boxed) }
+ }
+
+ #[inline]
+ pub fn into_arc(&self) -> Arc<Slice> {
+ let arc: Arc<[u8]> = Arc::from(&self.inner);
+ unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Slice) }
+ }
+
+ #[inline]
+ pub fn into_rc(&self) -> Rc<Slice> {
+ let rc: Rc<[u8]> = Rc::from(&self.inner);
+ unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Slice) }
+ }
+}
diff --git a/ctr-std/src/sys/redox/path.rs b/ctr-std/src/sys/redox/path.rs
new file mode 100644
index 0000000..e6a267d
--- /dev/null
+++ b/ctr-std/src/sys/redox/path.rs
@@ -0,0 +1,39 @@
+// Copyright 2016 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 ffi::OsStr;
+use path::Prefix;
+
+#[inline]
+pub fn is_sep_byte(b: u8) -> bool {
+ b == b'/'
+}
+
+#[inline]
+pub fn is_verbatim_sep(b: u8) -> bool {
+ b == b'/'
+}
+
+pub fn parse_prefix(path: &OsStr) -> Option<Prefix> {
+ if let Some(path_str) = path.to_str() {
+ if let Some(_i) = path_str.find(':') {
+ // FIXME: Redox specific prefix
+ // Some(Prefix::Verbatim(OsStr::new(&path_str[..i])))
+ None
+ } else {
+ None
+ }
+ } else {
+ None
+ }
+}
+
+pub const MAIN_SEP_STR: &'static str = "/";
+pub const MAIN_SEP: char = '/';
diff --git a/ctr-std/src/sys/redox/pipe.rs b/ctr-std/src/sys/redox/pipe.rs
new file mode 100644
index 0000000..28645fa
--- /dev/null
+++ b/ctr-std/src/sys/redox/pipe.rs
@@ -0,0 +1,103 @@
+// Copyright 2016 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 io;
+use sys::{cvt, syscall};
+use sys::fd::FileDesc;
+
+////////////////////////////////////////////////////////////////////////////////
+// Anonymous pipes
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct AnonPipe(FileDesc);
+
+pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
+ let mut fds = [0; 2];
+ cvt(syscall::pipe2(&mut fds, syscall::O_CLOEXEC))?;
+ Ok((AnonPipe(FileDesc::new(fds[0])), AnonPipe(FileDesc::new(fds[1]))))
+}
+
+impl AnonPipe {
+ pub fn from_fd(fd: FileDesc) -> io::Result<AnonPipe> {
+ fd.set_cloexec()?;
+ Ok(AnonPipe(fd))
+ }
+
+ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.0.read(buf)
+ }
+
+ pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+ self.0.write(buf)
+ }
+
+ pub fn fd(&self) -> &FileDesc { &self.0 }
+ pub fn into_fd(self) -> FileDesc { self.0 }
+}
+
+pub fn read2(p1: AnonPipe,
+ v1: &mut Vec<u8>,
+ p2: AnonPipe,
+ v2: &mut Vec<u8>) -> io::Result<()> {
+ //FIXME: Use event based I/O multiplexing
+ //unimplemented!()
+
+ p1.0.read_to_end(v1)?;
+ p2.0.read_to_end(v2)?;
+
+ Ok(())
+
+ /*
+ // Set both pipes into nonblocking mode as we're gonna be reading from both
+ // in the `select` loop below, and we wouldn't want one to block the other!
+ let p1 = p1.into_fd();
+ let p2 = p2.into_fd();
+ p1.set_nonblocking(true)?;
+ p2.set_nonblocking(true)?;
+
+ loop {
+ // wait for either pipe to become readable using `select`
+ cvt_r(|| unsafe {
+ let mut read: libc::fd_set = mem::zeroed();
+ libc::FD_SET(p1.raw(), &mut read);
+ libc::FD_SET(p2.raw(), &mut read);
+ libc::select(max + 1, &mut read, ptr::null_mut(), ptr::null_mut(),
+ ptr::null_mut())
+ })?;
+
+ // Read as much as we can from each pipe, ignoring EWOULDBLOCK or
+ // EAGAIN. If we hit EOF, then this will happen because the underlying
+ // reader will return Ok(0), in which case we'll see `Ok` ourselves. In
+ // this case we flip the other fd back into blocking mode and read
+ // whatever's leftover on that file descriptor.
+ let read = |fd: &FileDesc, dst: &mut Vec<u8>| {
+ match fd.read_to_end(dst) {
+ Ok(_) => Ok(true),
+ Err(e) => {
+ if e.raw_os_error() == Some(libc::EWOULDBLOCK) ||
+ e.raw_os_error() == Some(libc::EAGAIN) {
+ Ok(false)
+ } else {
+ Err(e)
+ }
+ }
+ }
+ };
+ if read(&p1, v1)? {
+ p2.set_nonblocking(false)?;
+ return p2.read_to_end(v2).map(|_| ());
+ }
+ if read(&p2, v2)? {
+ p1.set_nonblocking(false)?;
+ return p1.read_to_end(v1).map(|_| ());
+ }
+ }
+ */
+}
diff --git a/ctr-std/src/sys/redox/process.rs b/ctr-std/src/sys/redox/process.rs
new file mode 100644
index 0000000..d0b94e1
--- /dev/null
+++ b/ctr-std/src/sys/redox/process.rs
@@ -0,0 +1,543 @@
+// Copyright 2016 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 env::{split_paths};
+use ffi::OsStr;
+use os::unix::ffi::OsStrExt;
+use fmt;
+use io::{self, Error, ErrorKind};
+use libc::{EXIT_SUCCESS, EXIT_FAILURE};
+use path::{Path, PathBuf};
+use sys::fd::FileDesc;
+use sys::fs::{File, OpenOptions};
+use sys::pipe::{self, AnonPipe};
+use sys::{cvt, syscall};
+use sys_common::process::{CommandEnv, DefaultEnvKey};
+
+////////////////////////////////////////////////////////////////////////////////
+// Command
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct Command {
+ // Currently we try hard to ensure that the call to `.exec()` doesn't
+ // actually allocate any memory. While many platforms try to ensure that
+ // memory allocation works after a fork in a multithreaded process, it's
+ // been observed to be buggy and somewhat unreliable, so we do our best to
+ // just not do it at all!
+ //
+ // Along those lines, the `argv` and `envp` raw pointers here are exactly
+ // what's gonna get passed to `execvp`. The `argv` array starts with the
+ // `program` and ends with a NULL, and the `envp` pointer, if present, is
+ // also null-terminated.
+ //
+ // Right now we don't support removing arguments, so there's no much fancy
+ // support there, but we support adding and removing environment variables,
+ // so a side table is used to track where in the `envp` array each key is
+ // located. Whenever we add a key we update it in place if it's already
+ // present, and whenever we remove a key we update the locations of all
+ // other keys.
+ program: String,
+ args: Vec<String>,
+ env: CommandEnv<DefaultEnvKey>,
+
+ cwd: Option<String>,
+ uid: Option<u32>,
+ gid: Option<u32>,
+ saw_nul: bool,
+ closures: Vec<Box<FnMut() -> io::Result<()> + Send + Sync>>,
+ stdin: Option<Stdio>,
+ stdout: Option<Stdio>,
+ stderr: Option<Stdio>,
+}
+
+// passed back to std::process with the pipes connected to the child, if any
+// were requested
+pub struct StdioPipes {
+ pub stdin: Option<AnonPipe>,
+ pub stdout: Option<AnonPipe>,
+ pub stderr: Option<AnonPipe>,
+}
+
+// passed to do_exec() with configuration of what the child stdio should look
+// like
+struct ChildPipes {
+ stdin: ChildStdio,
+ stdout: ChildStdio,
+ stderr: ChildStdio,
+}
+
+enum ChildStdio {
+ Inherit,
+ Explicit(usize),
+ Owned(FileDesc),
+}
+
+pub enum Stdio {
+ Inherit,
+ Null,
+ MakePipe,
+ Fd(FileDesc),
+}
+
+impl Command {
+ pub fn new(program: &OsStr) -> Command {
+ Command {
+ program: program.to_str().unwrap().to_owned(),
+ args: Vec::new(),
+ env: Default::default(),
+ cwd: None,
+ uid: None,
+ gid: None,
+ saw_nul: false,
+ closures: Vec::new(),
+ stdin: None,
+ stdout: None,
+ stderr: None,
+ }
+ }
+
+ pub fn arg(&mut self, arg: &OsStr) {
+ self.args.push(arg.to_str().unwrap().to_owned());
+ }
+
+ pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> {
+ &mut self.env
+ }
+
+ pub fn cwd(&mut self, dir: &OsStr) {
+ self.cwd = Some(dir.to_str().unwrap().to_owned());
+ }
+ pub fn uid(&mut self, id: u32) {
+ self.uid = Some(id);
+ }
+ pub fn gid(&mut self, id: u32) {
+ self.gid = Some(id);
+ }
+
+ pub fn before_exec(&mut self,
+ f: Box<FnMut() -> io::Result<()> + Send + Sync>) {
+ self.closures.push(f);
+ }
+
+ pub fn stdin(&mut self, stdin: Stdio) {
+ self.stdin = Some(stdin);
+ }
+ pub fn stdout(&mut self, stdout: Stdio) {
+ self.stdout = Some(stdout);
+ }
+ pub fn stderr(&mut self, stderr: Stdio) {
+ self.stderr = Some(stderr);
+ }
+
+ pub fn spawn(&mut self, default: Stdio, needs_stdin: bool)
+ -> io::Result<(Process, StdioPipes)> {
+ const CLOEXEC_MSG_FOOTER: &'static [u8] = b"NOEX";
+
+ if self.saw_nul {
+ return Err(io::Error::new(ErrorKind::InvalidInput,
+ "nul byte found in provided data"));
+ }
+
+ let (ours, theirs) = self.setup_io(default, needs_stdin)?;
+ let (input, output) = pipe::anon_pipe()?;
+
+ let pid = unsafe {
+ match cvt(syscall::clone(0))? {
+ 0 => {
+ drop(input);
+ let err = self.do_exec(theirs);
+ let errno = err.raw_os_error().unwrap_or(syscall::EINVAL) as u32;
+ let bytes = [
+ (errno >> 24) as u8,
+ (errno >> 16) as u8,
+ (errno >> 8) as u8,
+ (errno >> 0) as u8,
+ CLOEXEC_MSG_FOOTER[0], CLOEXEC_MSG_FOOTER[1],
+ CLOEXEC_MSG_FOOTER[2], CLOEXEC_MSG_FOOTER[3]
+ ];
+ // pipe I/O up to PIPE_BUF bytes should be atomic, and then
+ // we want to be sure we *don't* run at_exit destructors as
+ // we're being torn down regardless
+ assert!(output.write(&bytes).is_ok());
+ let _ = syscall::exit(1);
+ panic!("failed to exit");
+ }
+ n => n,
+ }
+ };
+
+ let mut p = Process { pid: pid, status: None };
+ drop(output);
+ let mut bytes = [0; 8];
+
+ // loop to handle EINTR
+ loop {
+ match input.read(&mut bytes) {
+ Ok(0) => return Ok((p, ours)),
+ Ok(8) => {
+ assert!(combine(CLOEXEC_MSG_FOOTER) == combine(&bytes[4.. 8]),
+ "Validation on the CLOEXEC pipe failed: {:?}", bytes);
+ let errno = combine(&bytes[0.. 4]);
+ assert!(p.wait().is_ok(),
+ "wait() should either return Ok or panic");
+ return Err(Error::from_raw_os_error(errno))
+ }
+ Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
+ Err(e) => {
+ assert!(p.wait().is_ok(),
+ "wait() should either return Ok or panic");
+ panic!("the CLOEXEC pipe failed: {:?}", e)
+ },
+ Ok(..) => { // pipe I/O up to PIPE_BUF bytes should be atomic
+ assert!(p.wait().is_ok(),
+ "wait() should either return Ok or panic");
+ panic!("short read on the CLOEXEC pipe")
+ }
+ }
+ }
+
+ fn combine(arr: &[u8]) -> i32 {
+ let a = arr[0] as u32;
+ let b = arr[1] as u32;
+ let c = arr[2] as u32;
+ let d = arr[3] as u32;
+
+ ((a << 24) | (b << 16) | (c << 8) | (d << 0)) as i32
+ }
+ }
+
+ pub fn exec(&mut self, default: Stdio) -> io::Error {
+ if self.saw_nul {
+ return io::Error::new(ErrorKind::InvalidInput,
+ "nul byte found in provided data")
+ }
+
+ match self.setup_io(default, true) {
+ Ok((_, theirs)) => unsafe { self.do_exec(theirs) },
+ Err(e) => e,
+ }
+ }
+
+ // And at this point we've reached a special time in the life of the
+ // child. The child must now be considered hamstrung and unable to
+ // do anything other than syscalls really. Consider the following
+ // scenario:
+ //
+ // 1. Thread A of process 1 grabs the malloc() mutex
+ // 2. Thread B of process 1 forks(), creating thread C
+ // 3. Thread C of process 2 then attempts to malloc()
+ // 4. The memory of process 2 is the same as the memory of
+ // process 1, so the mutex is locked.
+ //
+ // This situation looks a lot like deadlock, right? It turns out
+ // that this is what pthread_atfork() takes care of, which is
+ // presumably implemented across platforms. The first thing that
+ // threads to *before* forking is to do things like grab the malloc
+ // mutex, and then after the fork they unlock it.
+ //
+ // Despite this information, libnative's spawn has been witnessed to
+ // deadlock on both macOS and FreeBSD. I'm not entirely sure why, but
+ // all collected backtraces point at malloc/free traffic in the
+ // child spawned process.
+ //
+ // For this reason, the block of code below should contain 0
+ // invocations of either malloc of free (or their related friends).
+ //
+ // As an example of not having malloc/free traffic, we don't close
+ // this file descriptor by dropping the FileDesc (which contains an
+ // allocation). Instead we just close it manually. This will never
+ // have the drop glue anyway because this code never returns (the
+ // child will either exec() or invoke syscall::exit)
+ unsafe fn do_exec(&mut self, stdio: ChildPipes) -> io::Error {
+ macro_rules! t {
+ ($e:expr) => (match $e {
+ Ok(e) => e,
+ Err(e) => return e,
+ })
+ }
+
+ if let Some(fd) = stdio.stderr.fd() {
+ t!(cvt(syscall::dup2(fd, 2, &[])));
+ let mut flags = t!(cvt(syscall::fcntl(2, syscall::F_GETFD, 0)));
+ flags &= ! syscall::O_CLOEXEC;
+ t!(cvt(syscall::fcntl(2, syscall::F_SETFD, flags)));
+ }
+ if let Some(fd) = stdio.stdout.fd() {
+ t!(cvt(syscall::dup2(fd, 1, &[])));
+ let mut flags = t!(cvt(syscall::fcntl(1, syscall::F_GETFD, 0)));
+ flags &= ! syscall::O_CLOEXEC;
+ t!(cvt(syscall::fcntl(1, syscall::F_SETFD, flags)));
+ }
+ if let Some(fd) = stdio.stdin.fd() {
+ t!(cvt(syscall::dup2(fd, 0, &[])));
+ let mut flags = t!(cvt(syscall::fcntl(0, syscall::F_GETFD, 0)));
+ flags &= ! syscall::O_CLOEXEC;
+ t!(cvt(syscall::fcntl(0, syscall::F_SETFD, flags)));
+ }
+
+ if let Some(g) = self.gid {
+ t!(cvt(syscall::setregid(g as usize, g as usize)));
+ }
+ if let Some(u) = self.uid {
+ t!(cvt(syscall::setreuid(u as usize, u as usize)));
+ }
+ if let Some(ref cwd) = self.cwd {
+ t!(cvt(syscall::chdir(cwd)));
+ }
+
+ for callback in self.closures.iter_mut() {
+ t!(callback());
+ }
+
+ let mut args: Vec<[usize; 2]> = Vec::new();
+ args.push([self.program.as_ptr() as usize, self.program.len()]);
+ for arg in self.args.iter() {
+ args.push([arg.as_ptr() as usize, arg.len()]);
+ }
+
+ self.env.apply();
+
+ let program = if self.program.contains(':') || self.program.contains('/') {
+ Some(PathBuf::from(&self.program))
+ } else if let Ok(path_env) = ::env::var("PATH") {
+ let mut program = None;
+ for mut path in split_paths(&path_env) {
+ path.push(&self.program);
+ if path.exists() {
+ program = Some(path);
+ break;
+ }
+ }
+ program
+ } else {
+ None
+ };
+
+ if let Some(program) = program {
+ if let Err(err) = syscall::execve(program.as_os_str().as_bytes(), &args) {
+ io::Error::from_raw_os_error(err.errno as i32)
+ } else {
+ panic!("return from exec without err");
+ }
+ } else {
+ io::Error::from_raw_os_error(syscall::ENOENT)
+ }
+ }
+
+
+ fn setup_io(&self, default: Stdio, needs_stdin: bool)
+ -> io::Result<(StdioPipes, ChildPipes)> {
+ let null = Stdio::Null;
+ let default_stdin = if needs_stdin {&default} else {&null};
+ let stdin = self.stdin.as_ref().unwrap_or(default_stdin);
+ let stdout = self.stdout.as_ref().unwrap_or(&default);
+ let stderr = self.stderr.as_ref().unwrap_or(&default);
+ let (their_stdin, our_stdin) = stdin.to_child_stdio(true)?;
+ let (their_stdout, our_stdout) = stdout.to_child_stdio(false)?;
+ let (their_stderr, our_stderr) = stderr.to_child_stdio(false)?;
+ let ours = StdioPipes {
+ stdin: our_stdin,
+ stdout: our_stdout,
+ stderr: our_stderr,
+ };
+ let theirs = ChildPipes {
+ stdin: their_stdin,
+ stdout: their_stdout,
+ stderr: their_stderr,
+ };
+ Ok((ours, theirs))
+ }
+}
+
+impl Stdio {
+ fn to_child_stdio(&self, readable: bool)
+ -> io::Result<(ChildStdio, Option<AnonPipe>)> {
+ match *self {
+ Stdio::Inherit => Ok((ChildStdio::Inherit, None)),
+
+ // Make sure that the source descriptors are not an stdio
+ // descriptor, otherwise the order which we set the child's
+ // descriptors may blow away a descriptor which we are hoping to
+ // save. For example, suppose we want the child's stderr to be the
+ // parent's stdout, and the child's stdout to be the parent's
+ // stderr. No matter which we dup first, the second will get
+ // overwritten prematurely.
+ Stdio::Fd(ref fd) => {
+ if fd.raw() <= 2 {
+ Ok((ChildStdio::Owned(fd.duplicate()?), None))
+ } else {
+ Ok((ChildStdio::Explicit(fd.raw()), None))
+ }
+ }
+
+ Stdio::MakePipe => {
+ let (reader, writer) = pipe::anon_pipe()?;
+ let (ours, theirs) = if readable {
+ (writer, reader)
+ } else {
+ (reader, writer)
+ };
+ Ok((ChildStdio::Owned(theirs.into_fd()), Some(ours)))
+ }
+
+ Stdio::Null => {
+ let mut opts = OpenOptions::new();
+ opts.read(readable);
+ opts.write(!readable);
+ let fd = File::open(Path::new("null:"), &opts)?;
+ Ok((ChildStdio::Owned(fd.into_fd()), None))
+ }
+ }
+ }
+}
+
+impl From<AnonPipe> for Stdio {
+ fn from(pipe: AnonPipe) -> Stdio {
+ Stdio::Fd(pipe.into_fd())
+ }
+}
+
+impl From<File> for Stdio {
+ fn from(file: File) -> Stdio {
+ Stdio::Fd(file.into_fd())
+ }
+}
+
+impl ChildStdio {
+ fn fd(&self) -> Option<usize> {
+ match *self {
+ ChildStdio::Inherit => None,
+ ChildStdio::Explicit(fd) => Some(fd),
+ ChildStdio::Owned(ref fd) => Some(fd.raw()),
+ }
+ }
+}
+
+impl fmt::Debug for Command {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ write!(f, "{:?}", self.program)?;
+ for arg in &self.args {
+ write!(f, " {:?}", arg)?;
+ }
+ Ok(())
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Processes
+////////////////////////////////////////////////////////////////////////////////
+
+/// Unix exit statuses
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct ExitStatus(i32);
+
+impl ExitStatus {
+ fn exited(&self) -> bool {
+ self.0 & 0x7F == 0
+ }
+
+ pub fn success(&self) -> bool {
+ self.code() == Some(0)
+ }
+
+ pub fn code(&self) -> Option<i32> {
+ if self.exited() {
+ Some((self.0 >> 8) & 0xFF)
+ } else {
+ None
+ }
+ }
+
+ pub fn signal(&self) -> Option<i32> {
+ if !self.exited() {
+ Some(self.0 & 0x7F)
+ } else {
+ None
+ }
+ }
+}
+
+impl From<i32> for ExitStatus {
+ fn from(a: i32) -> ExitStatus {
+ ExitStatus(a)
+ }
+}
+
+impl fmt::Display for ExitStatus {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ if let Some(code) = self.code() {
+ write!(f, "exit code: {}", code)
+ } else {
+ let signal = self.signal().unwrap();
+ write!(f, "signal: {}", signal)
+ }
+ }
+}
+
+#[derive(PartialEq, Eq, Clone, Copy, Debug)]
+pub struct ExitCode(u8);
+
+impl ExitCode {
+ pub const SUCCESS: ExitCode = ExitCode(EXIT_SUCCESS as _);
+ pub const FAILURE: ExitCode = ExitCode(EXIT_FAILURE as _);
+
+ pub fn as_i32(&self) -> i32 {
+ self.0 as i32
+ }
+}
+
+/// The unique id of the process (this should never be negative).
+pub struct Process {
+ pid: usize,
+ status: Option<ExitStatus>,
+}
+
+impl Process {
+ pub fn id(&self) -> u32 {
+ self.pid as u32
+ }
+
+ pub fn kill(&mut self) -> io::Result<()> {
+ // If we've already waited on this process then the pid can be recycled
+ // and used for another process, and we probably shouldn't be killing
+ // random processes, so just return an error.
+ if self.status.is_some() {
+ Err(Error::new(ErrorKind::InvalidInput,
+ "invalid argument: can't kill an exited process"))
+ } else {
+ cvt(syscall::kill(self.pid, syscall::SIGKILL))?;
+ Ok(())
+ }
+ }
+
+ pub fn wait(&mut self) -> io::Result<ExitStatus> {
+ if let Some(status) = self.status {
+ return Ok(status)
+ }
+ let mut status = 0;
+ cvt(syscall::waitpid(self.pid, &mut status, 0))?;
+ self.status = Some(ExitStatus(status as i32));
+ Ok(ExitStatus(status as i32))
+ }
+
+ pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
+ if let Some(status) = self.status {
+ return Ok(Some(status))
+ }
+ let mut status = 0;
+ let pid = cvt(syscall::waitpid(self.pid, &mut status, syscall::WNOHANG))?;
+ if pid == 0 {
+ Ok(None)
+ } else {
+ self.status = Some(ExitStatus(status as i32));
+ Ok(Some(ExitStatus(status as i32)))
+ }
+ }
+}
diff --git a/ctr-std/src/sys/redox/rand.rs b/ctr-std/src/sys/redox/rand.rs
new file mode 100644
index 0000000..3b378f5
--- /dev/null
+++ b/ctr-std/src/sys/redox/rand.rs
@@ -0,0 +1,13 @@
+// Copyright 2016 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.
+
+pub fn hashmap_random_keys() -> (u64, u64) {
+ (0, 0)
+}
diff --git a/ctr-std/src/sys/redox/rwlock.rs b/ctr-std/src/sys/redox/rwlock.rs
new file mode 100644
index 0000000..d74b614
--- /dev/null
+++ b/ctr-std/src/sys/redox/rwlock.rs
@@ -0,0 +1,61 @@
+// Copyright 2016 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 super::mutex::Mutex;
+
+pub struct RWLock {
+ mutex: Mutex
+}
+
+unsafe impl Send for RWLock {}
+unsafe impl Sync for RWLock {}
+
+impl RWLock {
+ pub const fn new() -> RWLock {
+ RWLock {
+ mutex: Mutex::new()
+ }
+ }
+
+ #[inline]
+ pub unsafe fn read(&self) {
+ self.mutex.lock();
+ }
+
+ #[inline]
+ pub unsafe fn try_read(&self) -> bool {
+ self.mutex.try_lock()
+ }
+
+ #[inline]
+ pub unsafe fn write(&self) {
+ self.mutex.lock();
+ }
+
+ #[inline]
+ pub unsafe fn try_write(&self) -> bool {
+ self.mutex.try_lock()
+ }
+
+ #[inline]
+ pub unsafe fn read_unlock(&self) {
+ self.mutex.unlock();
+ }
+
+ #[inline]
+ pub unsafe fn write_unlock(&self) {
+ self.mutex.unlock();
+ }
+
+ #[inline]
+ pub unsafe fn destroy(&self) {
+ self.mutex.destroy();
+ }
+}
diff --git a/ctr-std/src/sys/redox/stack_overflow.rs b/ctr-std/src/sys/redox/stack_overflow.rs
new file mode 100644
index 0000000..760fe06
--- /dev/null
+++ b/ctr-std/src/sys/redox/stack_overflow.rs
@@ -0,0 +1,27 @@
+// Copyright 2016 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.
+
+#![cfg_attr(test, allow(dead_code))]
+
+pub struct Handler;
+
+impl Handler {
+ pub unsafe fn new() -> Handler {
+ Handler
+ }
+}
+
+pub unsafe fn init() {
+
+}
+
+pub unsafe fn cleanup() {
+
+}
diff --git a/ctr-std/src/sys/redox/stdio.rs b/ctr-std/src/sys/redox/stdio.rs
new file mode 100644
index 0000000..7a4d11b
--- /dev/null
+++ b/ctr-std/src/sys/redox/stdio.rs
@@ -0,0 +1,81 @@
+// Copyright 2016 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 io;
+use sys::{cvt, syscall};
+use sys::fd::FileDesc;
+
+pub struct Stdin(());
+pub struct Stdout(());
+pub struct Stderr(());
+
+impl Stdin {
+ pub fn new() -> io::Result<Stdin> { Ok(Stdin(())) }
+
+ pub fn read(&self, data: &mut [u8]) -> io::Result<usize> {
+ let fd = FileDesc::new(0);
+ let ret = fd.read(data);
+ fd.into_raw();
+ ret
+ }
+}
+
+impl Stdout {
+ pub fn new() -> io::Result<Stdout> { Ok(Stdout(())) }
+
+ pub fn write(&self, data: &[u8]) -> io::Result<usize> {
+ let fd = FileDesc::new(1);
+ let ret = fd.write(data);
+ fd.into_raw();
+ ret
+ }
+
+ pub fn flush(&self) -> io::Result<()> {
+ cvt(syscall::fsync(1)).and(Ok(()))
+ }
+}
+
+impl Stderr {
+ pub fn new() -> io::Result<Stderr> { Ok(Stderr(())) }
+
+ pub fn write(&self, data: &[u8]) -> io::Result<usize> {
+ let fd = FileDesc::new(2);
+ let ret = fd.write(data);
+ fd.into_raw();
+ ret
+ }
+
+ pub fn flush(&self) -> io::Result<()> {
+ cvt(syscall::fsync(2)).and(Ok(()))
+ }
+}
+
+// FIXME: right now this raw stderr handle is used in a few places because
+// std::io::stderr_raw isn't exposed, but once that's exposed this impl
+// should go away
+impl io::Write for Stderr {
+ fn write(&mut self, data: &[u8]) -> io::Result<usize> {
+ Stderr::write(self, data)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ Stderr::flush(self)
+ }
+}
+
+pub fn is_ebadf(err: &io::Error) -> bool {
+ err.raw_os_error() == Some(::sys::syscall::EBADF as i32)
+}
+
+pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE;
+
+pub fn stderr_prints_nothing() -> bool {
+ false
+}
diff --git a/ctr-std/src/sys/redox/syscall/arch/arm.rs b/ctr-std/src/sys/redox/syscall/arch/arm.rs
new file mode 100644
index 0000000..9fb3961
--- /dev/null
+++ b/ctr-std/src/sys/redox/syscall/arch/arm.rs
@@ -0,0 +1,83 @@
+// Copyright 2016 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 super::error::{Error, Result};
+
+pub unsafe fn syscall0(mut a: usize) -> Result<usize> {
+ asm!("swi $$0"
+ : "={r0}"(a)
+ : "{r7}"(a)
+ : "memory"
+ : "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall1(mut a: usize, b: usize) -> Result<usize> {
+ asm!("swi $$0"
+ : "={r0}"(a)
+ : "{r7}"(a), "{r0}"(b)
+ : "memory"
+ : "volatile");
+
+ Error::demux(a)
+}
+
+// Clobbers all registers - special for clone
+pub unsafe fn syscall1_clobber(mut a: usize, b: usize) -> Result<usize> {
+ asm!("swi $$0"
+ : "={r0}"(a)
+ : "{r7}"(a), "{r0}"(b)
+ : "memory", "r0", "r1", "r2", "r3", "r4"
+ : "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall2(mut a: usize, b: usize, c: usize) -> Result<usize> {
+ asm!("swi $$0"
+ : "={r0}"(a)
+ : "{r7}"(a), "{r0}"(b), "{r1}"(c)
+ : "memory"
+ : "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall3(mut a: usize, b: usize, c: usize, d: usize) -> Result<usize> {
+ asm!("swi $$0"
+ : "={r0}"(a)
+ : "{r7}"(a), "{r0}"(b), "{r1}"(c), "{r2}"(d)
+ : "memory"
+ : "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall4(mut a: usize, b: usize, c: usize, d: usize, e: usize) -> Result<usize> {
+ asm!("swi $$0"
+ : "={r0}"(a)
+ : "{r7}"(a), "{r0}"(b), "{r1}"(c), "{r2}"(d), "{r3}"(e)
+ : "memory"
+ : "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall5(mut a: usize, b: usize, c: usize, d: usize, e: usize, f: usize)
+ -> Result<usize> {
+ asm!("swi $$0"
+ : "={r0}"(a)
+ : "{r7}"(a), "{r0}"(b), "{r1}"(c), "{r2}"(d), "{r3}"(e), "{r4}"(f)
+ : "memory"
+ : "volatile");
+
+ Error::demux(a)
+}
diff --git a/ctr-std/src/sys/redox/syscall/arch/x86.rs b/ctr-std/src/sys/redox/syscall/arch/x86.rs
new file mode 100644
index 0000000..724a6b9
--- /dev/null
+++ b/ctr-std/src/sys/redox/syscall/arch/x86.rs
@@ -0,0 +1,83 @@
+// Copyright 2016 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 super::error::{Error, Result};
+
+pub unsafe fn syscall0(mut a: usize) -> Result<usize> {
+ asm!("int 0x80"
+ : "={eax}"(a)
+ : "{eax}"(a)
+ : "memory"
+ : "intel", "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall1(mut a: usize, b: usize) -> Result<usize> {
+ asm!("int 0x80"
+ : "={eax}"(a)
+ : "{eax}"(a), "{ebx}"(b)
+ : "memory"
+ : "intel", "volatile");
+
+ Error::demux(a)
+}
+
+// Clobbers all registers - special for clone
+pub unsafe fn syscall1_clobber(mut a: usize, b: usize) -> Result<usize> {
+ asm!("int 0x80"
+ : "={eax}"(a)
+ : "{eax}"(a), "{ebx}"(b)
+ : "memory", "ebx", "ecx", "edx", "esi", "edi"
+ : "intel", "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall2(mut a: usize, b: usize, c: usize) -> Result<usize> {
+ asm!("int 0x80"
+ : "={eax}"(a)
+ : "{eax}"(a), "{ebx}"(b), "{ecx}"(c)
+ : "memory"
+ : "intel", "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall3(mut a: usize, b: usize, c: usize, d: usize) -> Result<usize> {
+ asm!("int 0x80"
+ : "={eax}"(a)
+ : "{eax}"(a), "{ebx}"(b), "{ecx}"(c), "{edx}"(d)
+ : "memory"
+ : "intel", "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall4(mut a: usize, b: usize, c: usize, d: usize, e: usize) -> Result<usize> {
+ asm!("int 0x80"
+ : "={eax}"(a)
+ : "{eax}"(a), "{ebx}"(b), "{ecx}"(c), "{edx}"(d), "{esi}"(e)
+ : "memory"
+ : "intel", "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall5(mut a: usize, b: usize, c: usize, d: usize, e: usize, f: usize)
+ -> Result<usize> {
+ asm!("int 0x80"
+ : "={eax}"(a)
+ : "{eax}"(a), "{ebx}"(b), "{ecx}"(c), "{edx}"(d), "{esi}"(e), "{edi}"(f)
+ : "memory"
+ : "intel", "volatile");
+
+ Error::demux(a)
+}
diff --git a/ctr-std/src/sys/redox/syscall/arch/x86_64.rs b/ctr-std/src/sys/redox/syscall/arch/x86_64.rs
new file mode 100644
index 0000000..a321c31
--- /dev/null
+++ b/ctr-std/src/sys/redox/syscall/arch/x86_64.rs
@@ -0,0 +1,84 @@
+// Copyright 2016 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 super::error::{Error, Result};
+
+pub unsafe fn syscall0(mut a: usize) -> Result<usize> {
+ asm!("int 0x80"
+ : "={rax}"(a)
+ : "{rax}"(a)
+ : "memory"
+ : "intel", "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall1(mut a: usize, b: usize) -> Result<usize> {
+ asm!("int 0x80"
+ : "={rax}"(a)
+ : "{rax}"(a), "{rbx}"(b)
+ : "memory"
+ : "intel", "volatile");
+
+ Error::demux(a)
+}
+
+// Clobbers all registers - special for clone
+pub unsafe fn syscall1_clobber(mut a: usize, b: usize) -> Result<usize> {
+ asm!("int 0x80"
+ : "={rax}"(a)
+ : "{rax}"(a), "{rbx}"(b)
+ : "memory", "rbx", "rcx", "rdx", "rsi", "rdi", "r8",
+ "r9", "r10", "r11", "r12", "r13", "r14", "r15"
+ : "intel", "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall2(mut a: usize, b: usize, c: usize) -> Result<usize> {
+ asm!("int 0x80"
+ : "={rax}"(a)
+ : "{rax}"(a), "{rbx}"(b), "{rcx}"(c)
+ : "memory"
+ : "intel", "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall3(mut a: usize, b: usize, c: usize, d: usize) -> Result<usize> {
+ asm!("int 0x80"
+ : "={rax}"(a)
+ : "{rax}"(a), "{rbx}"(b), "{rcx}"(c), "{rdx}"(d)
+ : "memory"
+ : "intel", "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall4(mut a: usize, b: usize, c: usize, d: usize, e: usize) -> Result<usize> {
+ asm!("int 0x80"
+ : "={rax}"(a)
+ : "{rax}"(a), "{rbx}"(b), "{rcx}"(c), "{rdx}"(d), "{rsi}"(e)
+ : "memory"
+ : "intel", "volatile");
+
+ Error::demux(a)
+}
+
+pub unsafe fn syscall5(mut a: usize, b: usize, c: usize, d: usize, e: usize, f: usize)
+ -> Result<usize> {
+ asm!("int 0x80"
+ : "={rax}"(a)
+ : "{rax}"(a), "{rbx}"(b), "{rcx}"(c), "{rdx}"(d), "{rsi}"(e), "{rdi}"(f)
+ : "memory"
+ : "intel", "volatile");
+
+ Error::demux(a)
+}
diff --git a/ctr-std/src/sys/redox/syscall/call.rs b/ctr-std/src/sys/redox/syscall/call.rs
new file mode 100644
index 0000000..f9a8bd6
--- /dev/null
+++ b/ctr-std/src/sys/redox/syscall/call.rs
@@ -0,0 +1,363 @@
+// Copyright 2016 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 super::arch::*;
+use super::data::{SigAction, Stat, StatVfs, TimeSpec};
+use super::error::Result;
+use super::number::*;
+
+use core::{mem, ptr};
+
+// Signal restorer
+extern "C" fn restorer() -> ! {
+ sigreturn().unwrap();
+ unreachable!();
+}
+
+/// Set the end of the process's heap
+///
+/// When `addr` is `0`, this function will return the current break.
+///
+/// When `addr` is nonzero, this function will attempt to set the end of the process's
+/// heap to `addr` and return the new program break. The new program break should be
+/// checked by the allocator, it may not be exactly `addr`, as it may be aligned to a page
+/// boundary.
+///
+/// On error, `Err(ENOMEM)` will be returned indicating that no memory is available
+pub unsafe fn brk(addr: usize) -> Result<usize> {
+ syscall1(SYS_BRK, addr)
+}
+
+/// Change the process's working directory
+///
+/// This function will attempt to set the process's working directory to `path`, which can be
+/// either a relative, scheme relative, or absolute path.
+///
+/// On success, `Ok(0)` will be returned. On error, one of the following errors will be returned.
+///
+/// # Errors
+///
+/// * `EACCES` - permission is denied for one of the components of `path`, or `path`
+/// * `EFAULT` - `path` does not point to the process's addressible memory
+/// * `EIO` - an I/O error occurred
+/// * `ENOENT` - `path` does not exit
+/// * `ENOTDIR` - `path` is not a directory
+pub fn chdir<T: AsRef<[u8]>>(path: T) -> Result<usize> {
+ unsafe { syscall2(SYS_CHDIR, path.as_ref().as_ptr() as usize, path.as_ref().len()) }
+}
+
+pub fn chmod<T: AsRef<[u8]>>(path: T, mode: usize) -> Result<usize> {
+ unsafe { syscall3(SYS_CHMOD, path.as_ref().as_ptr() as usize, path.as_ref().len(), mode) }
+}
+
+/// Produce a fork of the current process, or a new process thread
+pub unsafe fn clone(flags: usize) -> Result<usize> {
+ syscall1_clobber(SYS_CLONE, flags)
+}
+
+/// Close a file
+pub fn close(fd: usize) -> Result<usize> {
+ unsafe { syscall1(SYS_CLOSE, fd) }
+}
+
+/// Get the current system time
+pub fn clock_gettime(clock: usize, tp: &mut TimeSpec) -> Result<usize> {
+ unsafe { syscall2(SYS_CLOCK_GETTIME, clock, tp as *mut TimeSpec as usize) }
+}
+
+/// Copy and transform a file descriptor
+pub fn dup(fd: usize, buf: &[u8]) -> Result<usize> {
+ unsafe { syscall3(SYS_DUP, fd, buf.as_ptr() as usize, buf.len()) }
+}
+
+/// Copy and transform a file descriptor
+pub fn dup2(fd: usize, newfd: usize, buf: &[u8]) -> Result<usize> {
+ unsafe { syscall4(SYS_DUP2, fd, newfd, buf.as_ptr() as usize, buf.len()) }
+}
+
+/// Replace the current process with a new executable
+pub fn execve<T: AsRef<[u8]>>(path: T, args: &[[usize; 2]]) -> Result<usize> {
+ unsafe { syscall4(SYS_EXECVE, path.as_ref().as_ptr() as usize,
+ path.as_ref().len(), args.as_ptr() as usize, args.len()) }
+}
+
+/// Exit the current process
+pub fn exit(status: usize) -> Result<usize> {
+ unsafe { syscall1(SYS_EXIT, status) }
+}
+
+/// Change file permissions
+pub fn fchmod(fd: usize, mode: u16) -> Result<usize> {
+ unsafe { syscall2(SYS_FCHMOD, fd, mode as usize) }
+
+}
+
+/// Change file ownership
+pub fn fchown(fd: usize, uid: u32, gid: u32) -> Result<usize> {
+ unsafe { syscall3(SYS_FCHOWN, fd, uid as usize, gid as usize) }
+
+}
+
+/// Change file descriptor flags
+pub fn fcntl(fd: usize, cmd: usize, arg: usize) -> Result<usize> {
+ unsafe { syscall3(SYS_FCNTL, fd, cmd, arg) }
+}
+
+/// Register a file for event-based I/O
+pub fn fevent(fd: usize, flags: usize) -> Result<usize> {
+ unsafe { syscall2(SYS_FEVENT, fd, flags) }
+}
+
+/// Map a file into memory
+pub unsafe fn fmap(fd: usize, offset: usize, size: usize) -> Result<usize> {
+ syscall3(SYS_FMAP, fd, offset, size)
+}
+
+/// Unmap a memory-mapped file
+pub unsafe fn funmap(addr: usize) -> Result<usize> {
+ syscall1(SYS_FUNMAP, addr)
+}
+
+/// Retrieve the canonical path of a file
+pub fn fpath(fd: usize, buf: &mut [u8]) -> Result<usize> {
+ unsafe { syscall3(SYS_FPATH, fd, buf.as_mut_ptr() as usize, buf.len()) }
+}
+
+/// Rename a file
+pub fn frename<T: AsRef<[u8]>>(fd: usize, path: T) -> Result<usize> {
+ unsafe { syscall3(SYS_FRENAME, fd, path.as_ref().as_ptr() as usize, path.as_ref().len()) }
+}
+
+/// Get metadata about a file
+pub fn fstat(fd: usize, stat: &mut Stat) -> Result<usize> {
+ unsafe { syscall3(SYS_FSTAT, fd, stat as *mut Stat as usize, mem::size_of::<Stat>()) }
+}
+
+/// Get metadata about a filesystem
+pub fn fstatvfs(fd: usize, stat: &mut StatVfs) -> Result<usize> {
+ unsafe { syscall3(SYS_FSTATVFS, fd, stat as *mut StatVfs as usize, mem::size_of::<StatVfs>()) }
+}
+
+/// Sync a file descriptor to its underlying medium
+pub fn fsync(fd: usize) -> Result<usize> {
+ unsafe { syscall1(SYS_FSYNC, fd) }
+}
+
+/// Truncate or extend a file to a specified length
+pub fn ftruncate(fd: usize, len: usize) -> Result<usize> {
+ unsafe { syscall2(SYS_FTRUNCATE, fd, len) }
+}
+
+// Change modify and/or access times
+pub fn futimens(fd: usize, times: &[TimeSpec]) -> Result<usize> {
+ unsafe { syscall3(SYS_FUTIMENS, fd, times.as_ptr() as usize,
+ times.len() * mem::size_of::<TimeSpec>()) }
+}
+
+/// Fast userspace mutex
+pub unsafe fn futex(addr: *mut i32, op: usize, val: i32, val2: usize, addr2: *mut i32)
+ -> Result<usize> {
+ syscall5(SYS_FUTEX, addr as usize, op, (val as isize) as usize, val2, addr2 as usize)
+}
+
+/// Get the current working directory
+pub fn getcwd(buf: &mut [u8]) -> Result<usize> {
+ unsafe { syscall2(SYS_GETCWD, buf.as_mut_ptr() as usize, buf.len()) }
+}
+
+/// Get the effective group ID
+pub fn getegid() -> Result<usize> {
+ unsafe { syscall0(SYS_GETEGID) }
+}
+
+/// Get the effective namespace
+pub fn getens() -> Result<usize> {
+ unsafe { syscall0(SYS_GETENS) }
+}
+
+/// Get the effective user ID
+pub fn geteuid() -> Result<usize> {
+ unsafe { syscall0(SYS_GETEUID) }
+}
+
+/// Get the current group ID
+pub fn getgid() -> Result<usize> {
+ unsafe { syscall0(SYS_GETGID) }
+}
+
+/// Get the current namespace
+pub fn getns() -> Result<usize> {
+ unsafe { syscall0(SYS_GETNS) }
+}
+
+/// Get the current process ID
+pub fn getpid() -> Result<usize> {
+ unsafe { syscall0(SYS_GETPID) }
+}
+
+/// Get the process group ID
+pub fn getpgid(pid: usize) -> Result<usize> {
+ unsafe { syscall1(SYS_GETPGID, pid) }
+}
+
+/// Get the parent process ID
+pub fn getppid() -> Result<usize> {
+ unsafe { syscall0(SYS_GETPPID) }
+}
+
+/// Get the current user ID
+pub fn getuid() -> Result<usize> {
+ unsafe { syscall0(SYS_GETUID) }
+}
+
+/// Set the I/O privilege level
+pub unsafe fn iopl(level: usize) -> Result<usize> {
+ syscall1(SYS_IOPL, level)
+}
+
+/// Send a signal `sig` to the process identified by `pid`
+pub fn kill(pid: usize, sig: usize) -> Result<usize> {
+ unsafe { syscall2(SYS_KILL, pid, sig) }
+}
+
+/// Create a link to a file
+pub unsafe fn link(old: *const u8, new: *const u8) -> Result<usize> {
+ syscall2(SYS_LINK, old as usize, new as usize)
+}
+
+/// Seek to `offset` bytes in a file descriptor
+pub fn lseek(fd: usize, offset: isize, whence: usize) -> Result<usize> {
+ unsafe { syscall3(SYS_LSEEK, fd, offset as usize, whence) }
+}
+
+/// Make a new scheme namespace
+pub fn mkns(schemes: &[[usize; 2]]) -> Result<usize> {
+ unsafe { syscall2(SYS_MKNS, schemes.as_ptr() as usize, schemes.len()) }
+}
+
+/// Sleep for the time specified in `req`
+pub fn nanosleep(req: &TimeSpec, rem: &mut TimeSpec) -> Result<usize> {
+ unsafe { syscall2(SYS_NANOSLEEP, req as *const TimeSpec as usize,
+ rem as *mut TimeSpec as usize) }
+}
+
+/// Open a file
+pub fn open<T: AsRef<[u8]>>(path: T, flags: usize) -> Result<usize> {
+ unsafe { syscall3(SYS_OPEN, path.as_ref().as_ptr() as usize, path.as_ref().len(), flags) }
+}
+
+/// Allocate pages, linearly in physical memory
+pub unsafe fn physalloc(size: usize) -> Result<usize> {
+ syscall1(SYS_PHYSALLOC, size)
+}
+
+/// Free physically allocated pages
+pub unsafe fn physfree(physical_address: usize, size: usize) -> Result<usize> {
+ syscall2(SYS_PHYSFREE, physical_address, size)
+}
+
+/// Map physical memory to virtual memory
+pub unsafe fn physmap(physical_address: usize, size: usize, flags: usize) -> Result<usize> {
+ syscall3(SYS_PHYSMAP, physical_address, size, flags)
+}
+
+/// Unmap previously mapped physical memory
+pub unsafe fn physunmap(virtual_address: usize) -> Result<usize> {
+ syscall1(SYS_PHYSUNMAP, virtual_address)
+}
+
+/// Create a pair of file descriptors referencing the read and write ends of a pipe
+pub fn pipe2(fds: &mut [usize; 2], flags: usize) -> Result<usize> {
+ unsafe { syscall2(SYS_PIPE2, fds.as_ptr() as usize, flags) }
+}
+
+/// Read from a file descriptor into a buffer
+pub fn read(fd: usize, buf: &mut [u8]) -> Result<usize> {
+ unsafe { syscall3(SYS_READ, fd, buf.as_mut_ptr() as usize, buf.len()) }
+}
+
+/// Remove a directory
+pub fn rmdir<T: AsRef<[u8]>>(path: T) -> Result<usize> {
+ unsafe { syscall2(SYS_RMDIR, path.as_ref().as_ptr() as usize, path.as_ref().len()) }
+}
+
+/// Set the process group ID
+pub fn setpgid(pid: usize, pgid: usize) -> Result<usize> {
+ unsafe { syscall2(SYS_SETPGID, pid, pgid) }
+}
+
+/// Set the current process group IDs
+pub fn setregid(rgid: usize, egid: usize) -> Result<usize> {
+ unsafe { syscall2(SYS_SETREGID, rgid, egid) }
+}
+
+/// Make a new scheme namespace
+pub fn setrens(rns: usize, ens: usize) -> Result<usize> {
+ unsafe { syscall2(SYS_SETRENS, rns, ens) }
+}
+
+/// Set the current process user IDs
+pub fn setreuid(ruid: usize, euid: usize) -> Result<usize> {
+ unsafe { syscall2(SYS_SETREUID, ruid, euid) }
+}
+
+/// Set up a signal handler
+pub fn sigaction(sig: usize, act: Option<&SigAction>, oldact: Option<&mut SigAction>)
+-> Result<usize> {
+ unsafe { syscall4(SYS_SIGACTION, sig,
+ act.map(|x| x as *const _).unwrap_or_else(ptr::null) as usize,
+ oldact.map(|x| x as *mut _).unwrap_or_else(ptr::null_mut) as usize,
+ restorer as usize) }
+}
+
+// Return from signal handler
+pub fn sigreturn() -> Result<usize> {
+ unsafe { syscall0(SYS_SIGRETURN) }
+}
+
+/// Remove a file
+pub fn unlink<T: AsRef<[u8]>>(path: T) -> Result<usize> {
+ unsafe { syscall2(SYS_UNLINK, path.as_ref().as_ptr() as usize, path.as_ref().len()) }
+}
+
+/// Convert a virtual address to a physical one
+pub unsafe fn virttophys(virtual_address: usize) -> Result<usize> {
+ syscall1(SYS_VIRTTOPHYS, virtual_address)
+}
+
+/// Check if a child process has exited or received a signal
+pub fn waitpid(pid: usize, status: &mut usize, options: usize) -> Result<usize> {
+ unsafe { syscall3(SYS_WAITPID, pid, status as *mut usize as usize, options) }
+}
+
+/// Write a buffer to a file descriptor
+///
+/// The kernel will attempt to write the bytes in `buf` to the file descriptor `fd`, returning
+/// either an `Err`, explained below, or `Ok(count)` where `count` is the number of bytes which
+/// were written.
+///
+/// # Errors
+///
+/// * `EAGAIN` - the file descriptor was opened with `O_NONBLOCK` and writing would block
+/// * `EBADF` - the file descriptor is not valid or is not open for writing
+/// * `EFAULT` - `buf` does not point to the process's addressible memory
+/// * `EIO` - an I/O error occurred
+/// * `ENOSPC` - the device containing the file descriptor has no room for data
+/// * `EPIPE` - the file descriptor refers to a pipe or socket whose reading end is closed
+pub fn write(fd: usize, buf: &[u8]) -> Result<usize> {
+ unsafe { syscall3(SYS_WRITE, fd, buf.as_ptr() as usize, buf.len()) }
+}
+
+/// Yield the process's time slice to the kernel
+///
+/// This function will return Ok(0) on success
+pub fn sched_yield() -> Result<usize> {
+ unsafe { syscall0(SYS_YIELD) }
+}
diff --git a/ctr-std/src/sys/redox/syscall/data.rs b/ctr-std/src/sys/redox/syscall/data.rs
new file mode 100644
index 0000000..2e784eb
--- /dev/null
+++ b/ctr-std/src/sys/redox/syscall/data.rs
@@ -0,0 +1,201 @@
+// Copyright 2016 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 core::ops::{Deref, DerefMut};
+use core::{mem, slice};
+
+#[derive(Copy, Clone, Debug, Default)]
+pub struct Event {
+ pub id: usize,
+ pub flags: usize,
+ pub data: usize
+}
+
+impl Deref for Event {
+ type Target = [u8];
+ fn deref(&self) -> &[u8] {
+ unsafe {
+ slice::from_raw_parts(
+ self as *const Event as *const u8,
+ mem::size_of::<Event>()
+ ) as &[u8]
+ }
+ }
+}
+
+impl DerefMut for Event {
+ fn deref_mut(&mut self) -> &mut [u8] {
+ unsafe {
+ slice::from_raw_parts_mut(
+ self as *mut Event as *mut u8,
+ mem::size_of::<Event>()
+ ) as &mut [u8]
+ }
+ }
+}
+
+#[derive(Copy, Clone, Debug, Default)]
+#[repr(C)]
+pub struct Packet {
+ pub id: u64,
+ pub pid: usize,
+ pub uid: u32,
+ pub gid: u32,
+ pub a: usize,
+ pub b: usize,
+ pub c: usize,
+ pub d: usize
+}
+
+impl Deref for Packet {
+ type Target = [u8];
+ fn deref(&self) -> &[u8] {
+ unsafe {
+ slice::from_raw_parts(
+ self as *const Packet as *const u8,
+ mem::size_of::<Packet>()
+ ) as &[u8]
+ }
+ }
+}
+
+impl DerefMut for Packet {
+ fn deref_mut(&mut self) -> &mut [u8] {
+ unsafe {
+ slice::from_raw_parts_mut(
+ self as *mut Packet as *mut u8,
+ mem::size_of::<Packet>()
+ ) as &mut [u8]
+ }
+ }
+}
+
+#[derive(Copy, Clone, Debug)]
+#[repr(C)]
+pub struct SigAction {
+ pub sa_handler: extern "C" fn(usize),
+ pub sa_mask: [u64; 2],
+ pub sa_flags: usize,
+}
+
+impl Default for SigAction {
+ fn default() -> Self {
+ Self {
+ sa_handler: unsafe { mem::transmute(0usize) },
+ sa_mask: [0; 2],
+ sa_flags: 0,
+ }
+ }
+}
+
+#[derive(Copy, Clone, Debug, Default)]
+#[repr(C)]
+pub struct Stat {
+ pub st_dev: u64,
+ pub st_ino: u64,
+ pub st_mode: u16,
+ pub st_nlink: u32,
+ pub st_uid: u32,
+ pub st_gid: u32,
+ pub st_size: u64,
+ pub st_blksize: u32,
+ pub st_blocks: u64,
+ pub st_mtime: u64,
+ pub st_mtime_nsec: u32,
+ pub st_atime: u64,
+ pub st_atime_nsec: u32,
+ pub st_ctime: u64,
+ pub st_ctime_nsec: u32,
+}
+
+impl Deref for Stat {
+ type Target = [u8];
+ fn deref(&self) -> &[u8] {
+ unsafe {
+ slice::from_raw_parts(
+ self as *const Stat as *const u8,
+ mem::size_of::<Stat>()
+ ) as &[u8]
+ }
+ }
+}
+
+impl DerefMut for Stat {
+ fn deref_mut(&mut self) -> &mut [u8] {
+ unsafe {
+ slice::from_raw_parts_mut(
+ self as *mut Stat as *mut u8,
+ mem::size_of::<Stat>()
+ ) as &mut [u8]
+ }
+ }
+}
+
+#[derive(Copy, Clone, Debug, Default)]
+#[repr(C)]
+pub struct StatVfs {
+ pub f_bsize: u32,
+ pub f_blocks: u64,
+ pub f_bfree: u64,
+ pub f_bavail: u64,
+}
+
+impl Deref for StatVfs {
+ type Target = [u8];
+ fn deref(&self) -> &[u8] {
+ unsafe {
+ slice::from_raw_parts(
+ self as *const StatVfs as *const u8,
+ mem::size_of::<StatVfs>()
+ ) as &[u8]
+ }
+ }
+}
+
+impl DerefMut for StatVfs {
+ fn deref_mut(&mut self) -> &mut [u8] {
+ unsafe {
+ slice::from_raw_parts_mut(
+ self as *mut StatVfs as *mut u8,
+ mem::size_of::<StatVfs>()
+ ) as &mut [u8]
+ }
+ }
+}
+
+#[derive(Copy, Clone, Debug, Default)]
+#[repr(C)]
+pub struct TimeSpec {
+ pub tv_sec: i64,
+ pub tv_nsec: i32,
+}
+
+impl Deref for TimeSpec {
+ type Target = [u8];
+ fn deref(&self) -> &[u8] {
+ unsafe {
+ slice::from_raw_parts(
+ self as *const TimeSpec as *const u8,
+ mem::size_of::<TimeSpec>()
+ ) as &[u8]
+ }
+ }
+}
+
+impl DerefMut for TimeSpec {
+ fn deref_mut(&mut self) -> &mut [u8] {
+ unsafe {
+ slice::from_raw_parts_mut(
+ self as *mut TimeSpec as *mut u8,
+ mem::size_of::<TimeSpec>()
+ ) as &mut [u8]
+ }
+ }
+}
diff --git a/ctr-std/src/sys/redox/syscall/error.rs b/ctr-std/src/sys/redox/syscall/error.rs
new file mode 100644
index 0000000..1ef7954
--- /dev/null
+++ b/ctr-std/src/sys/redox/syscall/error.rs
@@ -0,0 +1,325 @@
+// Copyright 2016 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 core::{fmt, result};
+
+#[derive(Eq, PartialEq)]
+pub struct Error {
+ pub errno: i32,
+}
+
+pub type Result<T> = result::Result<T, Error>;
+
+impl Error {
+ pub fn new(errno: i32) -> Error {
+ Error { errno: errno }
+ }
+
+ pub fn mux(result: Result<usize>) -> usize {
+ match result {
+ Ok(value) => value,
+ Err(error) => -error.errno as usize,
+ }
+ }
+
+ pub fn demux(value: usize) -> Result<usize> {
+ let errno = -(value as i32);
+ if errno >= 1 && errno < STR_ERROR.len() as i32 {
+ Err(Error::new(errno))
+ } else {
+ Ok(value)
+ }
+ }
+
+ pub fn text(&self) -> &str {
+ if let Some(description) = STR_ERROR.get(self.errno as usize) {
+ description
+ } else {
+ "Unknown Error"
+ }
+ }
+}
+
+impl fmt::Debug for Error {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.write_str(self.text())
+ }
+}
+
+impl fmt::Display for Error {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.write_str(self.text())
+ }
+}
+
+pub const EPERM: i32 = 1; /* Operation not permitted */
+pub const ENOENT: i32 = 2; /* No such file or directory */
+pub const ESRCH: i32 = 3; /* No such process */
+pub const EINTR: i32 = 4; /* Interrupted system call */
+pub const EIO: i32 = 5; /* I/O error */
+pub const ENXIO: i32 = 6; /* No such device or address */
+pub const E2BIG: i32 = 7; /* Argument list too long */
+pub const ENOEXEC: i32 = 8; /* Exec format error */
+pub const EBADF: i32 = 9; /* Bad file number */
+pub const ECHILD: i32 = 10; /* No child processes */
+pub const EAGAIN: i32 = 11; /* Try again */
+pub const ENOMEM: i32 = 12; /* Out of memory */
+pub const EACCES: i32 = 13; /* Permission denied */
+pub const EFAULT: i32 = 14; /* Bad address */
+pub const ENOTBLK: i32 = 15; /* Block device required */
+pub const EBUSY: i32 = 16; /* Device or resource busy */
+pub const EEXIST: i32 = 17; /* File exists */
+pub const EXDEV: i32 = 18; /* Cross-device link */
+pub const ENODEV: i32 = 19; /* No such device */
+pub const ENOTDIR: i32 = 20; /* Not a directory */
+pub const EISDIR: i32 = 21; /* Is a directory */
+pub const EINVAL: i32 = 22; /* Invalid argument */
+pub const ENFILE: i32 = 23; /* File table overflow */
+pub const EMFILE: i32 = 24; /* Too many open files */
+pub const ENOTTY: i32 = 25; /* Not a typewriter */
+pub const ETXTBSY: i32 = 26; /* Text file busy */
+pub const EFBIG: i32 = 27; /* File too large */
+pub const ENOSPC: i32 = 28; /* No space left on device */
+pub const ESPIPE: i32 = 29; /* Illegal seek */
+pub const EROFS: i32 = 30; /* Read-only file system */
+pub const EMLINK: i32 = 31; /* Too many links */
+pub const EPIPE: i32 = 32; /* Broken pipe */
+pub const EDOM: i32 = 33; /* Math argument out of domain of func */
+pub const ERANGE: i32 = 34; /* Math result not representable */
+pub const EDEADLK: i32 = 35; /* Resource deadlock would occur */
+pub const ENAMETOOLONG: i32 = 36; /* File name too long */
+pub const ENOLCK: i32 = 37; /* No record locks available */
+pub const ENOSYS: i32 = 38; /* Function not implemented */
+pub const ENOTEMPTY: i32 = 39; /* Directory not empty */
+pub const ELOOP: i32 = 40; /* Too many symbolic links encountered */
+pub const EWOULDBLOCK: i32 = 41; /* Operation would block */
+pub const ENOMSG: i32 = 42; /* No message of desired type */
+pub const EIDRM: i32 = 43; /* Identifier removed */
+pub const ECHRNG: i32 = 44; /* Channel number out of range */
+pub const EL2NSYNC: i32 = 45; /* Level 2 not synchronized */
+pub const EL3HLT: i32 = 46; /* Level 3 halted */
+pub const EL3RST: i32 = 47; /* Level 3 reset */
+pub const ELNRNG: i32 = 48; /* Link number out of range */
+pub const EUNATCH: i32 = 49; /* Protocol driver not attached */
+pub const ENOCSI: i32 = 50; /* No CSI structure available */
+pub const EL2HLT: i32 = 51; /* Level 2 halted */
+pub const EBADE: i32 = 52; /* Invalid exchange */
+pub const EBADR: i32 = 53; /* Invalid request descriptor */
+pub const EXFULL: i32 = 54; /* Exchange full */
+pub const ENOANO: i32 = 55; /* No anode */
+pub const EBADRQC: i32 = 56; /* Invalid request code */
+pub const EBADSLT: i32 = 57; /* Invalid slot */
+pub const EDEADLOCK: i32 = 58; /* Resource deadlock would occur */
+pub const EBFONT: i32 = 59; /* Bad font file format */
+pub const ENOSTR: i32 = 60; /* Device not a stream */
+pub const ENODATA: i32 = 61; /* No data available */
+pub const ETIME: i32 = 62; /* Timer expired */
+pub const ENOSR: i32 = 63; /* Out of streams resources */
+pub const ENONET: i32 = 64; /* Machine is not on the network */
+pub const ENOPKG: i32 = 65; /* Package not installed */
+pub const EREMOTE: i32 = 66; /* Object is remote */
+pub const ENOLINK: i32 = 67; /* Link has been severed */
+pub const EADV: i32 = 68; /* Advertise error */
+pub const ESRMNT: i32 = 69; /* Srmount error */
+pub const ECOMM: i32 = 70; /* Communication error on send */
+pub const EPROTO: i32 = 71; /* Protocol error */
+pub const EMULTIHOP: i32 = 72; /* Multihop attempted */
+pub const EDOTDOT: i32 = 73; /* RFS specific error */
+pub const EBADMSG: i32 = 74; /* Not a data message */
+pub const EOVERFLOW: i32 = 75; /* Value too large for defined data type */
+pub const ENOTUNIQ: i32 = 76; /* Name not unique on network */
+pub const EBADFD: i32 = 77; /* File descriptor in bad state */
+pub const EREMCHG: i32 = 78; /* Remote address changed */
+pub const ELIBACC: i32 = 79; /* Can not access a needed shared library */
+pub const ELIBBAD: i32 = 80; /* Accessing a corrupted shared library */
+pub const ELIBSCN: i32 = 81; /* .lib section in a.out corrupted */
+pub const ELIBMAX: i32 = 82; /* Attempting to link in too many shared libraries */
+pub const ELIBEXEC: i32 = 83; /* Cannot exec a shared library directly */
+pub const EILSEQ: i32 = 84; /* Illegal byte sequence */
+pub const ERESTART: i32 = 85; /* Interrupted system call should be restarted */
+pub const ESTRPIPE: i32 = 86; /* Streams pipe error */
+pub const EUSERS: i32 = 87; /* Too many users */
+pub const ENOTSOCK: i32 = 88; /* Socket operation on non-socket */
+pub const EDESTADDRREQ: i32 = 89; /* Destination address required */
+pub const EMSGSIZE: i32 = 90; /* Message too long */
+pub const EPROTOTYPE: i32 = 91; /* Protocol wrong type for socket */
+pub const ENOPROTOOPT: i32 = 92; /* Protocol not available */
+pub const EPROTONOSUPPORT: i32 = 93; /* Protocol not supported */
+pub const ESOCKTNOSUPPORT: i32 = 94; /* Socket type not supported */
+pub const EOPNOTSUPP: i32 = 95; /* Operation not supported on transport endpoint */
+pub const EPFNOSUPPORT: i32 = 96; /* Protocol family not supported */
+pub const EAFNOSUPPORT: i32 = 97; /* Address family not supported by protocol */
+pub const EADDRINUSE: i32 = 98; /* Address already in use */
+pub const EADDRNOTAVAIL: i32 = 99; /* Cannot assign requested address */
+pub const ENETDOWN: i32 = 100; /* Network is down */
+pub const ENETUNREACH: i32 = 101; /* Network is unreachable */
+pub const ENETRESET: i32 = 102; /* Network dropped connection because of reset */
+pub const ECONNABORTED: i32 = 103; /* Software caused connection abort */
+pub const ECONNRESET: i32 = 104; /* Connection reset by peer */
+pub const ENOBUFS: i32 = 105; /* No buffer space available */
+pub const EISCONN: i32 = 106; /* Transport endpoint is already connected */
+pub const ENOTCONN: i32 = 107; /* Transport endpoint is not connected */
+pub const ESHUTDOWN: i32 = 108; /* Cannot send after transport endpoint shutdown */
+pub const ETOOMANYREFS: i32 = 109; /* Too many references: cannot splice */
+pub const ETIMEDOUT: i32 = 110; /* Connection timed out */
+pub const ECONNREFUSED: i32 = 111; /* Connection refused */
+pub const EHOSTDOWN: i32 = 112; /* Host is down */
+pub const EHOSTUNREACH: i32 = 113; /* No route to host */
+pub const EALREADY: i32 = 114; /* Operation already in progress */
+pub const EINPROGRESS: i32 = 115; /* Operation now in progress */
+pub const ESTALE: i32 = 116; /* Stale NFS file handle */
+pub const EUCLEAN: i32 = 117; /* Structure needs cleaning */
+pub const ENOTNAM: i32 = 118; /* Not a XENIX named type file */
+pub const ENAVAIL: i32 = 119; /* No XENIX semaphores available */
+pub const EISNAM: i32 = 120; /* Is a named type file */
+pub const EREMOTEIO: i32 = 121; /* Remote I/O error */
+pub const EDQUOT: i32 = 122; /* Quota exceeded */
+pub const ENOMEDIUM: i32 = 123; /* No medium found */
+pub const EMEDIUMTYPE: i32 = 124; /* Wrong medium type */
+pub const ECANCELED: i32 = 125; /* Operation Canceled */
+pub const ENOKEY: i32 = 126; /* Required key not available */
+pub const EKEYEXPIRED: i32 = 127; /* Key has expired */
+pub const EKEYREVOKED: i32 = 128; /* Key has been revoked */
+pub const EKEYREJECTED: i32 = 129; /* Key was rejected by service */
+pub const EOWNERDEAD: i32 = 130; /* Owner died */
+pub const ENOTRECOVERABLE: i32 = 131; /* State not recoverable */
+
+pub static STR_ERROR: [&'static str; 132] = ["Success",
+ "Operation not permitted",
+ "No such file or directory",
+ "No such process",
+ "Interrupted system call",
+ "I/O error",
+ "No such device or address",
+ "Argument list too long",
+ "Exec format error",
+ "Bad file number",
+ "No child processes",
+ "Try again",
+ "Out of memory",
+ "Permission denied",
+ "Bad address",
+ "Block device required",
+ "Device or resource busy",
+ "File exists",
+ "Cross-device link",
+ "No such device",
+ "Not a directory",
+ "Is a directory",
+ "Invalid argument",
+ "File table overflow",
+ "Too many open files",
+ "Not a typewriter",
+ "Text file busy",
+ "File too large",
+ "No space left on device",
+ "Illegal seek",
+ "Read-only file system",
+ "Too many links",
+ "Broken pipe",
+ "Math argument out of domain of func",
+ "Math result not representable",
+ "Resource deadlock would occur",
+ "File name too long",
+ "No record locks available",
+ "Function not implemented",
+ "Directory not empty",
+ "Too many symbolic links encountered",
+ "Operation would block",
+ "No message of desired type",
+ "Identifier removed",
+ "Channel number out of range",
+ "Level 2 not synchronized",
+ "Level 3 halted",
+ "Level 3 reset",
+ "Link number out of range",
+ "Protocol driver not attached",
+ "No CSI structure available",
+ "Level 2 halted",
+ "Invalid exchange",
+ "Invalid request descriptor",
+ "Exchange full",
+ "No anode",
+ "Invalid request code",
+ "Invalid slot",
+ "Resource deadlock would occur",
+ "Bad font file format",
+ "Device not a stream",
+ "No data available",
+ "Timer expired",
+ "Out of streams resources",
+ "Machine is not on the network",
+ "Package not installed",
+ "Object is remote",
+ "Link has been severed",
+ "Advertise error",
+ "Srmount error",
+ "Communication error on send",
+ "Protocol error",
+ "Multihop attempted",
+ "RFS specific error",
+ "Not a data message",
+ "Value too large for defined data type",
+ "Name not unique on network",
+ "File descriptor in bad state",
+ "Remote address changed",
+ "Can not access a needed shared library",
+ "Accessing a corrupted shared library",
+ ".lib section in a.out corrupted",
+ "Attempting to link in too many shared libraries",
+ "Cannot exec a shared library directly",
+ "Illegal byte sequence",
+ "Interrupted system call should be restarted",
+ "Streams pipe error",
+ "Too many users",
+ "Socket operation on non-socket",
+ "Destination address required",
+ "Message too long",
+ "Protocol wrong type for socket",
+ "Protocol not available",
+ "Protocol not supported",
+ "Socket type not supported",
+ "Operation not supported on transport endpoint",
+ "Protocol family not supported",
+ "Address family not supported by protocol",
+ "Address already in use",
+ "Cannot assign requested address",
+ "Network is down",
+ "Network is unreachable",
+ "Network dropped connection because of reset",
+ "Software caused connection abort",
+ "Connection reset by peer",
+ "No buffer space available",
+ "Transport endpoint is already connected",
+ "Transport endpoint is not connected",
+ "Cannot send after transport endpoint shutdown",
+ "Too many references: cannot splice",
+ "Connection timed out",
+ "Connection refused",
+ "Host is down",
+ "No route to host",
+ "Operation already in progress",
+ "Operation now in progress",
+ "Stale NFS file handle",
+ "Structure needs cleaning",
+ "Not a XENIX named type file",
+ "No XENIX semaphores available",
+ "Is a named type file",
+ "Remote I/O error",
+ "Quota exceeded",
+ "No medium found",
+ "Wrong medium type",
+ "Operation Canceled",
+ "Required key not available",
+ "Key has expired",
+ "Key has been revoked",
+ "Key was rejected by service",
+ "Owner died",
+ "State not recoverable"];
diff --git a/ctr-std/src/sys/redox/syscall/flag.rs b/ctr-std/src/sys/redox/syscall/flag.rs
new file mode 100644
index 0000000..0f61b9f
--- /dev/null
+++ b/ctr-std/src/sys/redox/syscall/flag.rs
@@ -0,0 +1,116 @@
+// Copyright 2016 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.
+
+pub const CLONE_VM: usize = 0x100;
+pub const CLONE_FS: usize = 0x200;
+pub const CLONE_FILES: usize = 0x400;
+pub const CLONE_SIGHAND: usize = 0x800;
+pub const CLONE_VFORK: usize = 0x4000;
+pub const CLONE_THREAD: usize = 0x10000;
+
+pub const CLOCK_REALTIME: usize = 1;
+pub const CLOCK_MONOTONIC: usize = 4;
+
+pub const EVENT_NONE: usize = 0;
+pub const EVENT_READ: usize = 1;
+pub const EVENT_WRITE: usize = 2;
+
+pub const F_DUPFD: usize = 0;
+pub const F_GETFD: usize = 1;
+pub const F_SETFD: usize = 2;
+pub const F_GETFL: usize = 3;
+pub const F_SETFL: usize = 4;
+
+pub const FUTEX_WAIT: usize = 0;
+pub const FUTEX_WAKE: usize = 1;
+pub const FUTEX_REQUEUE: usize = 2;
+
+pub const MAP_WRITE: usize = 1;
+pub const MAP_WRITE_COMBINE: usize = 2;
+
+pub const MODE_TYPE: u16 = 0xF000;
+pub const MODE_DIR: u16 = 0x4000;
+pub const MODE_FILE: u16 = 0x8000;
+pub const MODE_SYMLINK: u16 = 0xA000;
+pub const MODE_FIFO: u16 = 0x1000;
+pub const MODE_CHR: u16 = 0x2000;
+
+pub const MODE_PERM: u16 = 0x0FFF;
+pub const MODE_SETUID: u16 = 0o4000;
+pub const MODE_SETGID: u16 = 0o2000;
+
+pub const O_RDONLY: usize = 0x0001_0000;
+pub const O_WRONLY: usize = 0x0002_0000;
+pub const O_RDWR: usize = 0x0003_0000;
+pub const O_NONBLOCK: usize = 0x0004_0000;
+pub const O_APPEND: usize = 0x0008_0000;
+pub const O_SHLOCK: usize = 0x0010_0000;
+pub const O_EXLOCK: usize = 0x0020_0000;
+pub const O_ASYNC: usize = 0x0040_0000;
+pub const O_FSYNC: usize = 0x0080_0000;
+pub const O_CLOEXEC: usize = 0x0100_0000;
+pub const O_CREAT: usize = 0x0200_0000;
+pub const O_TRUNC: usize = 0x0400_0000;
+pub const O_EXCL: usize = 0x0800_0000;
+pub const O_DIRECTORY: usize = 0x1000_0000;
+pub const O_STAT: usize = 0x2000_0000;
+pub const O_SYMLINK: usize = 0x4000_0000;
+pub const O_NOFOLLOW: usize = 0x8000_0000;
+pub const O_ACCMODE: usize = O_RDONLY | O_WRONLY | O_RDWR;
+
+pub const SEEK_SET: usize = 0;
+pub const SEEK_CUR: usize = 1;
+pub const SEEK_END: usize = 2;
+
+pub const SIGHUP: usize = 1;
+pub const SIGINT: usize = 2;
+pub const SIGQUIT: usize = 3;
+pub const SIGILL: usize = 4;
+pub const SIGTRAP: usize = 5;
+pub const SIGABRT: usize = 6;
+pub const SIGBUS: usize = 7;
+pub const SIGFPE: usize = 8;
+pub const SIGKILL: usize = 9;
+pub const SIGUSR1: usize = 10;
+pub const SIGSEGV: usize = 11;
+pub const SIGUSR2: usize = 12;
+pub const SIGPIPE: usize = 13;
+pub const SIGALRM: usize = 14;
+pub const SIGTERM: usize = 15;
+pub const SIGSTKFLT: usize= 16;
+pub const SIGCHLD: usize = 17;
+pub const SIGCONT: usize = 18;
+pub const SIGSTOP: usize = 19;
+pub const SIGTSTP: usize = 20;
+pub const SIGTTIN: usize = 21;
+pub const SIGTTOU: usize = 22;
+pub const SIGURG: usize = 23;
+pub const SIGXCPU: usize = 24;
+pub const SIGXFSZ: usize = 25;
+pub const SIGVTALRM: usize= 26;
+pub const SIGPROF: usize = 27;
+pub const SIGWINCH: usize = 28;
+pub const SIGIO: usize = 29;
+pub const SIGPWR: usize = 30;
+pub const SIGSYS: usize = 31;
+
+pub const SIG_DFL: usize = 0;
+pub const SIG_IGN: usize = 1;
+
+pub const SA_NOCLDSTOP: usize = 0x00000001;
+pub const SA_NOCLDWAIT: usize = 0x00000002;
+pub const SA_SIGINFO: usize = 0x00000004;
+pub const SA_RESTORER: usize = 0x04000000;
+pub const SA_ONSTACK: usize = 0x08000000;
+pub const SA_RESTART: usize = 0x10000000;
+pub const SA_NODEFER: usize = 0x40000000;
+pub const SA_RESETHAND: usize = 0x80000000;
+
+pub const WNOHANG: usize = 1;
diff --git a/ctr-std/src/sys/redox/syscall/mod.rs b/ctr-std/src/sys/redox/syscall/mod.rs
new file mode 100644
index 0000000..ce789c2
--- /dev/null
+++ b/ctr-std/src/sys/redox/syscall/mod.rs
@@ -0,0 +1,43 @@
+// Copyright 2016 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.
+
+pub use self::arch::*;
+pub use self::call::*;
+pub use self::data::*;
+pub use self::error::*;
+pub use self::flag::*;
+pub use self::number::*;
+
+#[cfg(target_arch = "arm")]
+#[path="arch/arm.rs"]
+mod arch;
+
+#[cfg(target_arch = "x86")]
+#[path="arch/x86.rs"]
+mod arch;
+
+#[cfg(target_arch = "x86_64")]
+#[path="arch/x86_64.rs"]
+mod arch;
+
+/// Function definitions
+pub mod call;
+
+/// Complex structures that are used for some system calls
+pub mod data;
+
+/// All errors that can be generated by a system call
+pub mod error;
+
+/// Flags used as an argument to many system calls
+pub mod flag;
+
+/// Call numbers used by each system call
+pub mod number;
diff --git a/ctr-std/src/sys/redox/syscall/number.rs b/ctr-std/src/sys/redox/syscall/number.rs
new file mode 100644
index 0000000..45cb40e
--- /dev/null
+++ b/ctr-std/src/sys/redox/syscall/number.rs
@@ -0,0 +1,83 @@
+// Copyright 2016 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.
+
+pub const SYS_CLASS: usize = 0xF000_0000;
+pub const SYS_CLASS_PATH: usize=0x1000_0000;
+pub const SYS_CLASS_FILE: usize=0x2000_0000;
+
+pub const SYS_ARG: usize = 0x0F00_0000;
+pub const SYS_ARG_SLICE: usize =0x0100_0000;
+pub const SYS_ARG_MSLICE: usize=0x0200_0000;
+pub const SYS_ARG_PATH: usize = 0x0300_0000;
+
+pub const SYS_RET: usize = 0x00F0_0000;
+pub const SYS_RET_FILE: usize = 0x0010_0000;
+
+pub const SYS_LINK: usize = SYS_CLASS_PATH | SYS_ARG_PATH | 9;
+pub const SYS_OPEN: usize = SYS_CLASS_PATH | SYS_RET_FILE | 5;
+pub const SYS_CHMOD: usize = SYS_CLASS_PATH | 15;
+pub const SYS_RMDIR: usize = SYS_CLASS_PATH | 84;
+pub const SYS_UNLINK: usize = SYS_CLASS_PATH | 10;
+
+pub const SYS_CLOSE: usize = SYS_CLASS_FILE | 6;
+pub const SYS_DUP: usize = SYS_CLASS_FILE | SYS_RET_FILE | 41;
+pub const SYS_DUP2: usize = SYS_CLASS_FILE | SYS_RET_FILE | 63;
+pub const SYS_READ: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 3;
+pub const SYS_WRITE: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 4;
+pub const SYS_LSEEK: usize = SYS_CLASS_FILE | 19;
+pub const SYS_FCHMOD: usize = SYS_CLASS_FILE | 94;
+pub const SYS_FCHOWN: usize = SYS_CLASS_FILE | 207;
+pub const SYS_FCNTL: usize = SYS_CLASS_FILE | 55;
+pub const SYS_FEVENT: usize = SYS_CLASS_FILE | 927;
+pub const SYS_FMAP: usize = SYS_CLASS_FILE | 90;
+pub const SYS_FUNMAP: usize = SYS_CLASS_FILE | 91;
+pub const SYS_FPATH: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 928;
+pub const SYS_FRENAME: usize = SYS_CLASS_FILE | SYS_ARG_PATH | 38;
+pub const SYS_FSTAT: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 28;
+pub const SYS_FSTATVFS: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 100;
+pub const SYS_FSYNC: usize = SYS_CLASS_FILE | 118;
+pub const SYS_FTRUNCATE: usize =SYS_CLASS_FILE | 93;
+pub const SYS_FUTIMENS: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 320;
+
+pub const SYS_BRK: usize = 45;
+pub const SYS_CHDIR: usize = 12;
+pub const SYS_CLOCK_GETTIME: usize = 265;
+pub const SYS_CLONE: usize = 120;
+pub const SYS_EXECVE: usize = 11;
+pub const SYS_EXIT: usize = 1;
+pub const SYS_FUTEX: usize = 240;
+pub const SYS_GETCWD: usize = 183;
+pub const SYS_GETEGID: usize = 202;
+pub const SYS_GETENS: usize = 951;
+pub const SYS_GETEUID: usize = 201;
+pub const SYS_GETGID: usize = 200;
+pub const SYS_GETNS: usize = 950;
+pub const SYS_GETPID: usize = 20;
+pub const SYS_GETPGID: usize = 132;
+pub const SYS_GETPPID: usize = 64;
+pub const SYS_GETUID: usize = 199;
+pub const SYS_IOPL: usize = 110;
+pub const SYS_KILL: usize = 37;
+pub const SYS_MKNS: usize = 984;
+pub const SYS_NANOSLEEP: usize =162;
+pub const SYS_PHYSALLOC: usize =945;
+pub const SYS_PHYSFREE: usize = 946;
+pub const SYS_PHYSMAP: usize = 947;
+pub const SYS_PHYSUNMAP: usize =948;
+pub const SYS_VIRTTOPHYS: usize=949;
+pub const SYS_PIPE2: usize = 331;
+pub const SYS_SETPGID: usize = 57;
+pub const SYS_SETREGID: usize = 204;
+pub const SYS_SETRENS: usize = 952;
+pub const SYS_SETREUID: usize = 203;
+pub const SYS_SIGACTION: usize =67;
+pub const SYS_SIGRETURN: usize =119;
+pub const SYS_WAITPID: usize = 7;
+pub const SYS_YIELD: usize = 158;
diff --git a/ctr-std/src/sys/redox/thread.rs b/ctr-std/src/sys/redox/thread.rs
new file mode 100644
index 0000000..110d46c
--- /dev/null
+++ b/ctr-std/src/sys/redox/thread.rs
@@ -0,0 +1,95 @@
+// Copyright 2016 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 boxed::FnBox;
+use ffi::CStr;
+use io;
+use mem;
+use sys_common::thread::start_thread;
+use sys::{cvt, syscall};
+use time::Duration;
+
+pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
+
+pub struct Thread {
+ id: usize,
+}
+
+// Some platforms may have pthread_t as a pointer in which case we still want
+// a thread to be Send/Sync
+unsafe impl Send for Thread {}
+unsafe impl Sync for Thread {}
+
+impl Thread {
+ pub unsafe fn new<'a>(_stack: usize, p: Box<FnBox() + 'a>) -> io::Result<Thread> {
+ let p = box p;
+
+ let id = cvt(syscall::clone(syscall::CLONE_VM | syscall::CLONE_FS | syscall::CLONE_FILES))?;
+ if id == 0 {
+ start_thread(&*p as *const _ as *mut _);
+ let _ = syscall::exit(0);
+ panic!("thread failed to exit");
+ } else {
+ mem::forget(p);
+ Ok(Thread { id: id })
+ }
+ }
+
+ pub fn yield_now() {
+ let ret = syscall::sched_yield().expect("failed to sched_yield");
+ debug_assert_eq!(ret, 0);
+ }
+
+ pub fn set_name(_name: &CStr) {
+
+ }
+
+ pub fn sleep(dur: Duration) {
+ let mut secs = dur.as_secs();
+ let mut nsecs = dur.subsec_nanos() as i32;
+
+ // If we're awoken with a signal then the return value will be -1 and
+ // nanosleep will fill in `ts` with the remaining time.
+ while secs > 0 || nsecs > 0 {
+ let req = syscall::TimeSpec {
+ tv_sec: secs as i64,
+ tv_nsec: nsecs,
+ };
+ secs -= req.tv_sec as u64;
+ let mut rem = syscall::TimeSpec::default();
+ if syscall::nanosleep(&req, &mut rem).is_err() {
+ secs += rem.tv_sec as u64;
+ nsecs = rem.tv_nsec;
+ } else {
+ nsecs = 0;
+ }
+ }
+ }
+
+ pub fn join(self) {
+ let mut status = 0;
+ syscall::waitpid(self.id, &mut status, 0).unwrap();
+ }
+
+ pub fn id(&self) -> usize { self.id }
+
+ pub fn into_id(self) -> usize {
+ let id = self.id;
+ mem::forget(self);
+ id
+ }
+}
+
+pub mod guard {
+ pub type Guard = !;
+ pub unsafe fn current() -> Option<Guard> { None }
+ pub unsafe fn init() -> Option<Guard> { None }
+ pub unsafe fn deinit() {}
+}
diff --git a/ctr-std/src/sys/redox/thread_local.rs b/ctr-std/src/sys/redox/thread_local.rs
new file mode 100644
index 0000000..cacd84e
--- /dev/null
+++ b/ctr-std/src/sys/redox/thread_local.rs
@@ -0,0 +1,71 @@
+// Copyright 2016 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(dead_code)] // not used on all platforms
+
+use collections::BTreeMap;
+use ptr;
+use sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
+
+pub type Key = usize;
+
+type Dtor = unsafe extern fn(*mut u8);
+
+static NEXT_KEY: AtomicUsize = ATOMIC_USIZE_INIT;
+
+static mut KEYS: *mut BTreeMap<Key, Option<Dtor>> = ptr::null_mut();
+
+#[thread_local]
+static mut LOCALS: *mut BTreeMap<Key, *mut u8> = ptr::null_mut();
+
+unsafe fn keys() -> &'static mut BTreeMap<Key, Option<Dtor>> {
+ if KEYS == ptr::null_mut() {
+ KEYS = Box::into_raw(Box::new(BTreeMap::new()));
+ }
+ &mut *KEYS
+}
+
+unsafe fn locals() -> &'static mut BTreeMap<Key, *mut u8> {
+ if LOCALS == ptr::null_mut() {
+ LOCALS = Box::into_raw(Box::new(BTreeMap::new()));
+ }
+ &mut *LOCALS
+}
+
+#[inline]
+pub unsafe fn create(dtor: Option<Dtor>) -> Key {
+ let key = NEXT_KEY.fetch_add(1, Ordering::SeqCst);
+ keys().insert(key, dtor);
+ key
+}
+
+#[inline]
+pub unsafe fn get(key: Key) -> *mut u8 {
+ if let Some(&entry) = locals().get(&key) {
+ entry
+ } else {
+ ptr::null_mut()
+ }
+}
+
+#[inline]
+pub unsafe fn set(key: Key, value: *mut u8) {
+ locals().insert(key, value);
+}
+
+#[inline]
+pub unsafe fn destroy(key: Key) {
+ keys().remove(&key);
+}
+
+#[inline]
+pub fn requires_synchronized_create() -> bool {
+ false
+}
diff --git a/ctr-std/src/sys/redox/time.rs b/ctr-std/src/sys/redox/time.rs
new file mode 100644
index 0000000..5c49111
--- /dev/null
+++ b/ctr-std/src/sys/redox/time.rs
@@ -0,0 +1,214 @@
+// Copyright 2016 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 cmp::Ordering;
+use fmt;
+use sys::{cvt, syscall};
+use time::Duration;
+use convert::TryInto;
+use core::hash::{Hash, Hasher};
+
+const NSEC_PER_SEC: u64 = 1_000_000_000;
+
+#[derive(Copy, Clone)]
+struct Timespec {
+ t: syscall::TimeSpec,
+}
+
+impl Timespec {
+ fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
+ if self >= other {
+ Ok(if self.t.tv_nsec >= other.t.tv_nsec {
+ Duration::new((self.t.tv_sec - other.t.tv_sec) as u64,
+ (self.t.tv_nsec - other.t.tv_nsec) as u32)
+ } else {
+ Duration::new((self.t.tv_sec - 1 - other.t.tv_sec) as u64,
+ self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) -
+ other.t.tv_nsec as u32)
+ })
+ } else {
+ match other.sub_timespec(self) {
+ Ok(d) => Err(d),
+ Err(d) => Ok(d),
+ }
+ }
+ }
+
+ fn add_duration(&self, other: &Duration) -> Timespec {
+ let mut secs = other
+ .as_secs()
+ .try_into() // <- target type would be `i64`
+ .ok()
+ .and_then(|secs| self.t.tv_sec.checked_add(secs))
+ .expect("overflow when adding duration to time");
+
+ // Nano calculations can't overflow because nanos are <1B which fit
+ // in a u32.
+ let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32;
+ if nsec >= NSEC_PER_SEC as u32 {
+ nsec -= NSEC_PER_SEC as u32;
+ secs = secs.checked_add(1).expect("overflow when adding \
+ duration to time");
+ }
+ Timespec {
+ t: syscall::TimeSpec {
+ tv_sec: secs,
+ tv_nsec: nsec as i32,
+ },
+ }
+ }
+
+ fn sub_duration(&self, other: &Duration) -> Timespec {
+ let mut secs = other
+ .as_secs()
+ .try_into() // <- target type would be `i64`
+ .ok()
+ .and_then(|secs| self.t.tv_sec.checked_sub(secs))
+ .expect("overflow when subtracting duration from time");
+
+ // Similar to above, nanos can't overflow.
+ let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32;
+ if nsec < 0 {
+ nsec += NSEC_PER_SEC as i32;
+ secs = secs.checked_sub(1).expect("overflow when subtracting \
+ duration from time");
+ }
+ Timespec {
+ t: syscall::TimeSpec {
+ tv_sec: secs,
+ tv_nsec: nsec as i32,
+ },
+ }
+ }
+}
+
+impl PartialEq for Timespec {
+ fn eq(&self, other: &Timespec) -> bool {
+ self.t.tv_sec == other.t.tv_sec && self.t.tv_nsec == other.t.tv_nsec
+ }
+}
+
+impl Eq for Timespec {}
+
+impl PartialOrd for Timespec {
+ fn partial_cmp(&self, other: &Timespec) -> Option<Ordering> {
+ Some(self.cmp(other))
+ }
+}
+
+impl Ord for Timespec {
+ fn cmp(&self, other: &Timespec) -> Ordering {
+ let me = (self.t.tv_sec, self.t.tv_nsec);
+ let other = (other.t.tv_sec, other.t.tv_nsec);
+ me.cmp(&other)
+ }
+}
+
+impl Hash for Timespec {
+ fn hash<H : Hasher>(&self, state: &mut H) {
+ self.t.tv_sec.hash(state);
+ self.t.tv_nsec.hash(state);
+ }
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct Instant {
+ t: Timespec,
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub struct SystemTime {
+ t: Timespec,
+}
+
+pub const UNIX_EPOCH: SystemTime = SystemTime {
+ t: Timespec {
+ t: syscall::TimeSpec {
+ tv_sec: 0,
+ tv_nsec: 0,
+ },
+ },
+};
+
+impl Instant {
+ pub fn now() -> Instant {
+ Instant { t: now(syscall::CLOCK_MONOTONIC) }
+ }
+
+ pub fn sub_instant(&self, other: &Instant) -> Duration {
+ self.t.sub_timespec(&other.t).unwrap_or_else(|_| {
+ panic!("specified instant was later than self")
+ })
+ }
+
+ pub fn add_duration(&self, other: &Duration) -> Instant {
+ Instant { t: self.t.add_duration(other) }
+ }
+
+ pub fn sub_duration(&self, other: &Duration) -> Instant {
+ Instant { t: self.t.sub_duration(other) }
+ }
+}
+
+impl fmt::Debug for Instant {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("Instant")
+ .field("tv_sec", &self.t.t.tv_sec)
+ .field("tv_nsec", &self.t.t.tv_nsec)
+ .finish()
+ }
+}
+
+impl SystemTime {
+ pub fn now() -> SystemTime {
+ SystemTime { t: now(syscall::CLOCK_REALTIME) }
+ }
+
+ pub fn sub_time(&self, other: &SystemTime)
+ -> Result<Duration, Duration> {
+ self.t.sub_timespec(&other.t)
+ }
+
+ pub fn add_duration(&self, other: &Duration) -> SystemTime {
+ SystemTime { t: self.t.add_duration(other) }
+ }
+
+ pub fn sub_duration(&self, other: &Duration) -> SystemTime {
+ SystemTime { t: self.t.sub_duration(other) }
+ }
+}
+
+impl From<syscall::TimeSpec> for SystemTime {
+ fn from(t: syscall::TimeSpec) -> SystemTime {
+ SystemTime { t: Timespec { t: t } }
+ }
+}
+
+impl fmt::Debug for SystemTime {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.debug_struct("SystemTime")
+ .field("tv_sec", &self.t.t.tv_sec)
+ .field("tv_nsec", &self.t.t.tv_nsec)
+ .finish()
+ }
+}
+
+pub type clock_t = usize;
+
+fn now(clock: clock_t) -> Timespec {
+ let mut t = Timespec {
+ t: syscall::TimeSpec {
+ tv_sec: 0,
+ tv_nsec: 0,
+ }
+ };
+ cvt(syscall::clock_gettime(clock, &mut t.t)).unwrap();
+ t
+}