Add redox system
This commit is contained in:
parent
07436946b6
commit
8b09e01fef
37 changed files with 4313 additions and 5 deletions
|
@ -316,13 +316,13 @@ extern crate rustc_unicode;
|
||||||
extern crate libc;
|
extern crate libc;
|
||||||
|
|
||||||
// We always need an unwinder currently for backtraces
|
// We always need an unwinder currently for backtraces
|
||||||
extern crate unwind;
|
//REDOX TODO extern crate unwind;
|
||||||
|
|
||||||
#[cfg(stage0)]
|
#[cfg(stage0)]
|
||||||
extern crate alloc_system;
|
extern crate alloc_system;
|
||||||
|
|
||||||
// compiler-rt intrinsics
|
// compiler-rt intrinsics
|
||||||
extern crate compiler_builtins;
|
//REDOX TODO extern crate compiler_builtins;
|
||||||
|
|
||||||
// Make std testable by not duplicating lang items and other globals. See #2912
|
// Make std testable by not duplicating lang items and other globals. See #2912
|
||||||
#[cfg(test)] extern crate std as realstd;
|
#[cfg(test)] extern crate std as realstd;
|
||||||
|
@ -456,6 +456,8 @@ mod memchr;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
#[path = "sys/common/mod.rs"] mod sys_common;
|
#[path = "sys/common/mod.rs"] mod sys_common;
|
||||||
|
|
||||||
|
#[cfg(redox)]
|
||||||
|
#[path = "sys/redox/mod.rs"] mod sys;
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
#[path = "sys/unix/mod.rs"] mod sys;
|
#[path = "sys/unix/mod.rs"] mod sys;
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
|
|
|
@ -13,6 +13,9 @@
|
||||||
#![stable(feature = "os", since = "1.0.0")]
|
#![stable(feature = "os", since = "1.0.0")]
|
||||||
#![allow(missing_docs, bad_style)]
|
#![allow(missing_docs, bad_style)]
|
||||||
|
|
||||||
|
#[cfg(redox)]
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
pub use sys::ext as unix;
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
pub use sys::ext as unix;
|
pub use sys::ext as unix;
|
||||||
|
|
|
@ -32,7 +32,6 @@ pub mod condvar;
|
||||||
pub mod io;
|
pub mod io;
|
||||||
pub mod memchr;
|
pub mod memchr;
|
||||||
pub mod mutex;
|
pub mod mutex;
|
||||||
pub mod net;
|
|
||||||
pub mod poison;
|
pub mod poison;
|
||||||
pub mod remutex;
|
pub mod remutex;
|
||||||
pub mod rwlock;
|
pub mod rwlock;
|
||||||
|
@ -42,6 +41,12 @@ pub mod thread_local;
|
||||||
pub mod util;
|
pub mod util;
|
||||||
pub mod wtf8;
|
pub mod wtf8;
|
||||||
|
|
||||||
|
#[cfg(redox)]
|
||||||
|
pub use sys::net;
|
||||||
|
|
||||||
|
#[cfg(not(redox))]
|
||||||
|
pub mod net;
|
||||||
|
|
||||||
#[cfg(any(not(cargobuild), feature = "backtrace"))]
|
#[cfg(any(not(cargobuild), feature = "backtrace"))]
|
||||||
#[cfg(any(all(unix, not(any(target_os = "macos", target_os = "ios", target_os = "emscripten"))),
|
#[cfg(any(all(unix, not(any(target_os = "macos", target_os = "ios", target_os = "emscripten"))),
|
||||||
all(windows, target_env = "gnu")))]
|
all(windows, target_env = "gnu")))]
|
||||||
|
|
|
@ -33,6 +33,12 @@ pub fn dumb_print(args: fmt::Arguments) {
|
||||||
let _ = Stderr::new().map(|mut stderr| stderr.write_fmt(args));
|
let _ = Stderr::new().map(|mut stderr| stderr.write_fmt(args));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// On Redox, use an illegal instruction
|
||||||
|
#[cfg(redox)]
|
||||||
|
unsafe fn abort_internal() -> ! {
|
||||||
|
::intrinsics::abort()
|
||||||
|
}
|
||||||
|
|
||||||
// On Unix-like platforms, libc::abort will unregister signal handlers
|
// On Unix-like platforms, libc::abort will unregister signal handlers
|
||||||
// including the SIGABRT handler, preventing the abort from being blocked, and
|
// including the SIGABRT handler, preventing the abort from being blocked, and
|
||||||
// fclose streams, with the side effect of flushing them so libc bufferred
|
// fclose streams, with the side effect of flushing them so libc bufferred
|
||||||
|
|
105
src/libstd/sys/redox/args.rs
Normal file
105
src/libstd/sys/redox/args.rs
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
// Copyright 2012-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.
|
||||||
|
|
||||||
|
//! Global initialization and retreival 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 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) }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
8
src/libstd/sys/redox/backtrace.rs
Normal file
8
src/libstd/sys/redox/backtrace.rs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
use libc;
|
||||||
|
use io;
|
||||||
|
use sys_common::backtrace::output;
|
||||||
|
|
||||||
|
#[inline(never)]
|
||||||
|
pub fn write(w: &mut io::Write) -> io::Result<()> {
|
||||||
|
output(w, 0, 0 as *mut libc::c_void, None)
|
||||||
|
}
|
88
src/libstd/sys/redox/condvar.rs
Normal file
88
src/libstd/sys/redox/condvar.rs
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
use cell::UnsafeCell;
|
||||||
|
use intrinsics::{atomic_cxchg, atomic_xadd, atomic_xchg};
|
||||||
|
use ptr;
|
||||||
|
use time::Duration;
|
||||||
|
|
||||||
|
use super::mutex::{mutex_lock, mutex_unlock, Mutex};
|
||||||
|
|
||||||
|
use libc::{futex, 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn init(&self) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn wait(&self, mutex: &Mutex) {
|
||||||
|
unsafe {
|
||||||
|
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 _ = futex(seq, FUTEX_WAIT, *seq, 0, ptr::null_mut());
|
||||||
|
|
||||||
|
while atomic_xchg(*lock, 2) != 0 {
|
||||||
|
let _ = futex(*lock, FUTEX_WAIT, 2, 0, ptr::null_mut());
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_lock(*lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn destroy(&self) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Send for Condvar {}
|
||||||
|
|
||||||
|
unsafe impl Sync for Condvar {}
|
19
src/libstd/sys/redox/env.rs
Normal file
19
src/libstd/sys/redox/env.rs
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
// Copyright 2012-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 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 = "";
|
||||||
|
}
|
61
src/libstd/sys/redox/ext/ffi.rs
Normal file
61
src/libstd/sys/redox/ext/ffi.rs
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
//! Unix-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};
|
||||||
|
|
||||||
|
/// Unix-specific extensions to `OsString`.
|
||||||
|
#[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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unix-specific extensions to `OsStr`.
|
||||||
|
#[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
|
||||||
|
}
|
||||||
|
}
|
300
src/libstd/sys/redox/ext/fs.rs
Normal file
300
src/libstd/sys/redox/ext/fs.rs
Normal file
|
@ -0,0 +1,300 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
//! Unix-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};
|
||||||
|
|
||||||
|
/// Unix-specific extensions to `Permissions`
|
||||||
|
#[stable(feature = "fs_ext", since = "1.1.0")]
|
||||||
|
pub trait PermissionsExt {
|
||||||
|
/// Returns the underlying raw `mode_t` bits that are the standard Unix
|
||||||
|
/// permissions for this file.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust,ignore
|
||||||
|
/// use std::fs::File;
|
||||||
|
/// use std::os::unix::fs::PermissionsExt;
|
||||||
|
///
|
||||||
|
/// let f = try!(File::create("foo.txt"));
|
||||||
|
/// let metadata = try!(f.metadata());
|
||||||
|
/// let permissions = metadata.permissions();
|
||||||
|
///
|
||||||
|
/// println!("permissions: {}", permissions.mode());
|
||||||
|
/// ```
|
||||||
|
#[stable(feature = "fs_ext", since = "1.1.0")]
|
||||||
|
fn mode(&self) -> u32;
|
||||||
|
|
||||||
|
/// Sets the underlying raw bits for this set of permissions.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust,ignore
|
||||||
|
/// use std::fs::File;
|
||||||
|
/// use std::os::unix::fs::PermissionsExt;
|
||||||
|
///
|
||||||
|
/// let f = try!(File::create("foo.txt"));
|
||||||
|
/// let metadata = try!(f.metadata());
|
||||||
|
/// let mut permissions = metadata.permissions();
|
||||||
|
///
|
||||||
|
/// permissions.set_mode(0o644); // Read/write for owner and read for others.
|
||||||
|
/// assert_eq!(permissions.mode(), 0o644);
|
||||||
|
/// ```
|
||||||
|
#[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 Unix
|
||||||
|
/// permission bits.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```rust,ignore
|
||||||
|
/// use std::fs::Permissions;
|
||||||
|
/// use std::os::unix::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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unix-specific extensions to `OpenOptions`
|
||||||
|
#[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
|
||||||
|
///
|
||||||
|
/// ```rust,ignore
|
||||||
|
/// extern crate libc;
|
||||||
|
/// use std::fs::OpenOptions;
|
||||||
|
/// use std::os::unix::fs::OpenOptionsExt;
|
||||||
|
///
|
||||||
|
/// 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` agument 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
|
||||||
|
///
|
||||||
|
/// ```rust,ignore
|
||||||
|
/// extern crate libc;
|
||||||
|
/// use std::fs::OpenOptions;
|
||||||
|
/// use std::os::unix::fs::OpenOptionsExt;
|
||||||
|
///
|
||||||
|
/// let mut options = OpenOptions::new();
|
||||||
|
/// options.write(true);
|
||||||
|
/// if cfg!(unix) {
|
||||||
|
/// 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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")]
|
||||||
|
pub trait MetadataExt {
|
||||||
|
#[stable(feature = "metadata_ext", since = "1.1.0")]
|
||||||
|
fn mode(&self) -> u32;
|
||||||
|
#[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")]
|
||||||
|
impl MetadataExt for fs::Metadata {
|
||||||
|
fn mode(&self) -> u32 {
|
||||||
|
self.as_inner().as_inner().st_mode as u32
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
/// Add special unix types (block/char device, fifo and socket)
|
||||||
|
#[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 { self.as_inner().is(libc::S_IFBLK) }
|
||||||
|
fn is_char_device(&self) -> bool { self.as_inner().is(libc::S_IFCHR) }
|
||||||
|
fn is_fifo(&self) -> bool { self.as_inner().is(libc::S_IFIFO) }
|
||||||
|
fn is_socket(&self) -> bool { self.as_inner().is(libc::S_IFSOCK) }
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/// 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
|
||||||
|
///
|
||||||
|
/// ```
|
||||||
|
/// use std::os::unix::fs;
|
||||||
|
///
|
||||||
|
/// # fn foo() -> std::io::Result<()> {
|
||||||
|
/// try!(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())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[stable(feature = "dir_builder", since = "1.6.0")]
|
||||||
|
/// An extension trait for `fs::DirBuilder` for unix-specific options.
|
||||||
|
pub trait DirBuilderExt {
|
||||||
|
/// Sets the mode to create new directories with. This option defaults to
|
||||||
|
/// 0o777.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// ```ignore
|
||||||
|
/// use std::fs::DirBuilder;
|
||||||
|
/// use std::os::unix::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
|
||||||
|
}
|
||||||
|
}
|
147
src/libstd/sys/redox/ext/io.rs
Normal file
147
src/libstd/sys/redox/ext/io.rs
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
//! Unix-specific extensions to general I/O primitives
|
||||||
|
|
||||||
|
#![stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
|
||||||
|
use fs;
|
||||||
|
use os::raw;
|
||||||
|
use sys;
|
||||||
|
use sys_common::{AsInner, FromInner, IntoInner};
|
||||||
|
|
||||||
|
/// Raw file descriptors.
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
pub type RawFd = raw::c_int;
|
||||||
|
|
||||||
|
/// 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().socket().as_inner() }
|
||||||
|
}
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
impl AsRawFd for net::TcpListener {
|
||||||
|
fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() }
|
||||||
|
}
|
||||||
|
#[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
impl AsRawFd for net::UdpSocket {
|
||||||
|
fn as_raw_fd(&self) -> RawFd { *self.as_inner().socket().as_inner() }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[stable(feature = "from_raw_os", since = "1.1.0")]
|
||||||
|
impl FromRawFd for net::TcpStream {
|
||||||
|
unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream {
|
||||||
|
let socket = sys::net::Socket::from_inner(fd);
|
||||||
|
net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(socket))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[stable(feature = "from_raw_os", since = "1.1.0")]
|
||||||
|
impl FromRawFd for net::TcpListener {
|
||||||
|
unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener {
|
||||||
|
let socket = sys::net::Socket::from_inner(fd);
|
||||||
|
net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(socket))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[stable(feature = "from_raw_os", since = "1.1.0")]
|
||||||
|
impl FromRawFd for net::UdpSocket {
|
||||||
|
unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket {
|
||||||
|
let socket = sys::net::Socket::from_inner(fd);
|
||||||
|
net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(socket))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[stable(feature = "into_raw_os", since = "1.4.0")]
|
||||||
|
impl IntoRawFd for net::TcpStream {
|
||||||
|
fn into_raw_fd(self) -> RawFd {
|
||||||
|
self.into_inner().into_socket().into_inner()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[stable(feature = "into_raw_os", since = "1.4.0")]
|
||||||
|
impl IntoRawFd for net::TcpListener {
|
||||||
|
fn into_raw_fd(self) -> RawFd {
|
||||||
|
self.into_inner().into_socket().into_inner()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[stable(feature = "into_raw_os", since = "1.4.0")]
|
||||||
|
impl IntoRawFd for net::UdpSocket {
|
||||||
|
fn into_raw_fd(self) -> RawFd {
|
||||||
|
self.into_inner().into_socket().into_inner()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
50
src/libstd/sys/redox/ext/mod.rs
Normal file
50
src/libstd/sys/redox/ext/mod.rs
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
//! Experimental extensions to `std` for Unix platforms.
|
||||||
|
//!
|
||||||
|
//! For now, this module is limited to extracting file descriptors,
|
||||||
|
//! but its functionality will grow over time.
|
||||||
|
//!
|
||||||
|
//! # Example
|
||||||
|
//!
|
||||||
|
//! ```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")]
|
||||||
|
|
||||||
|
pub mod ffi;
|
||||||
|
pub mod fs;
|
||||||
|
pub mod io;
|
||||||
|
pub mod process;
|
||||||
|
|
||||||
|
/// 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::{PermissionsExt, OpenOptionsExt, MetadataExt};
|
||||||
|
#[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
|
||||||
|
pub use super::process::{CommandExt, ExitStatusExt};
|
||||||
|
}
|
183
src/libstd/sys/redox/ext/process.rs
Normal file
183
src/libstd/sys/redox/ext/process.rs
Normal file
|
@ -0,0 +1,183 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
//! Unix-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};
|
||||||
|
|
||||||
|
/// Unix-specific extensions to the `std::process::Command` builder
|
||||||
|
#[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 modificatons 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.
|
||||||
|
#[unstable(feature = "process_exec", issue = "31398")]
|
||||||
|
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 as usize);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn gid(&mut self, id: u32) -> &mut process::Command {
|
||||||
|
self.as_inner_mut().gid(id as usize);
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unix-specific extensions to `std::process::ExitStatus`
|
||||||
|
#[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()
|
||||||
|
}
|
||||||
|
}
|
117
src/libstd/sys/redox/fd.rs
Normal file
117
src/libstd/sys/redox/fd.rs
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
#![unstable(reason = "not public", issue = "0", feature = "fd")]
|
||||||
|
|
||||||
|
use io::{self, Read};
|
||||||
|
use libc::{self, c_int, c_void};
|
||||||
|
use mem;
|
||||||
|
use sys::cvt;
|
||||||
|
use sys_common::AsInner;
|
||||||
|
use sys_common::io::read_to_end_uninitialized;
|
||||||
|
|
||||||
|
pub struct FileDesc {
|
||||||
|
fd: c_int,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FileDesc {
|
||||||
|
pub fn new(fd: c_int) -> FileDesc {
|
||||||
|
FileDesc { fd: fd }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn raw(&self) -> c_int { self.fd }
|
||||||
|
|
||||||
|
/// Extracts the actual filedescriptor without closing it.
|
||||||
|
pub fn into_raw(self) -> c_int {
|
||||||
|
let fd = self.fd;
|
||||||
|
mem::forget(self);
|
||||||
|
fd
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||||
|
let ret = cvt(unsafe {
|
||||||
|
libc::read(self.fd,
|
||||||
|
buf.as_mut_ptr() as *mut c_void,
|
||||||
|
buf.len())
|
||||||
|
})?;
|
||||||
|
Ok(ret as usize)
|
||||||
|
}
|
||||||
|
|
||||||
|
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> {
|
||||||
|
let ret = cvt(unsafe {
|
||||||
|
libc::write(self.fd,
|
||||||
|
buf.as_ptr() as *const c_void,
|
||||||
|
buf.len())
|
||||||
|
})?;
|
||||||
|
Ok(ret as usize)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_cloexec(&self) -> io::Result<()> {
|
||||||
|
unimplemented!();
|
||||||
|
/*
|
||||||
|
unsafe {
|
||||||
|
let previous = cvt(libc::fcntl(self.fd, libc::F_GETFD, 0))?;
|
||||||
|
cvt(libc::fcntl(self.fd, libc::F_SETFD, previous | libc::FD_CLOEXEC))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_nonblocking(&self, _nonblocking: bool) -> io::Result<()> {
|
||||||
|
unimplemented!();
|
||||||
|
/*
|
||||||
|
unsafe {
|
||||||
|
let previous = cvt(libc::fcntl(self.fd, libc::F_GETFL, 0))?;
|
||||||
|
let new = if nonblocking {
|
||||||
|
previous | libc::O_NONBLOCK
|
||||||
|
} else {
|
||||||
|
previous & !libc::O_NONBLOCK
|
||||||
|
};
|
||||||
|
cvt(libc::fcntl(self.fd, libc::F_SETFL, new))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn duplicate(&self) -> io::Result<FileDesc> {
|
||||||
|
let new_fd = cvt(unsafe { libc::dup(self.fd) })?;
|
||||||
|
Ok(FileDesc::new(new_fd))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Read for &'a FileDesc {
|
||||||
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||||
|
(**self).read(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||||
|
unsafe { read_to_end_uninitialized(self, buf) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsInner<c_int> for FileDesc {
|
||||||
|
fn as_inner(&self) -> &c_int { &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 _ = unsafe { libc::close(self.fd) };
|
||||||
|
}
|
||||||
|
}
|
554
src/libstd/sys/redox/fs.rs
Normal file
554
src/libstd/sys/redox/fs.rs
Normal file
|
@ -0,0 +1,554 @@
|
||||||
|
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
use os::unix::prelude::*;
|
||||||
|
|
||||||
|
use ffi::{CString, CStr, OsString, OsStr};
|
||||||
|
use fmt;
|
||||||
|
use io::{self, Error, ErrorKind, SeekFrom};
|
||||||
|
use libc::{self, c_int, mode_t};
|
||||||
|
use mem;
|
||||||
|
use path::{Path, PathBuf};
|
||||||
|
use sync::Arc;
|
||||||
|
use sys::fd::FileDesc;
|
||||||
|
use sys::time::SystemTime;
|
||||||
|
use sys::{cvt, cvt_r};
|
||||||
|
use sys_common::{AsInner, FromInner};
|
||||||
|
|
||||||
|
use libc::{stat as stat64, fstat as fstat64, lstat as lstat64, off_t as off64_t,
|
||||||
|
ftruncate as ftruncate64, lseek as lseek64, open as open64};
|
||||||
|
|
||||||
|
pub struct File(FileDesc);
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct FileAttr {
|
||||||
|
stat: stat64,
|
||||||
|
}
|
||||||
|
|
||||||
|
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)]
|
||||||
|
pub struct OpenOptions {
|
||||||
|
// generic
|
||||||
|
read: bool,
|
||||||
|
write: bool,
|
||||||
|
append: bool,
|
||||||
|
truncate: bool,
|
||||||
|
create: bool,
|
||||||
|
create_new: bool,
|
||||||
|
// system-specific
|
||||||
|
custom_flags: i32,
|
||||||
|
mode: mode_t,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||||
|
pub struct FilePermissions { mode: mode_t }
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
|
||||||
|
pub struct FileType { mode: mode_t }
|
||||||
|
|
||||||
|
pub struct DirBuilder { mode: mode_t }
|
||||||
|
|
||||||
|
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 mode_t) & 0o777 }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn file_type(&self) -> FileType {
|
||||||
|
FileType { mode: self.stat.st_mode as mode_t }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FileAttr {
|
||||||
|
pub fn modified(&self) -> io::Result<SystemTime> {
|
||||||
|
Ok(SystemTime::from(libc::timespec {
|
||||||
|
tv_sec: self.stat.st_mtime as libc::time_t,
|
||||||
|
tv_nsec: self.stat.st_mtime_nsec as i32,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn accessed(&self) -> io::Result<SystemTime> {
|
||||||
|
Ok(SystemTime::from(libc::timespec {
|
||||||
|
tv_sec: self.stat.st_atime as libc::time_t,
|
||||||
|
tv_nsec: self.stat.st_atime_nsec as i32,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn created(&self) -> io::Result<SystemTime> {
|
||||||
|
Ok(SystemTime::from(libc::timespec {
|
||||||
|
tv_sec: self.stat.st_ctime as libc::time_t,
|
||||||
|
tv_nsec: self.stat.st_ctime_nsec as i32,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsInner<stat64> for FileAttr {
|
||||||
|
fn as_inner(&self) -> &stat64 { &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(libc::MODE_DIR) }
|
||||||
|
pub fn is_file(&self) -> bool { self.is(libc::MODE_FILE) }
|
||||||
|
pub fn is_symlink(&self) -> bool { false }
|
||||||
|
|
||||||
|
pub fn is(&self, mode: mode_t) -> bool { self.mode & (libc::MODE_DIR | libc::MODE_FILE) == mode }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromInner<u32> for FilePermissions {
|
||||||
|
fn from_inner(mode: u32) -> FilePermissions {
|
||||||
|
FilePermissions { mode: mode as mode_t }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
while self.i < self.data.len() {
|
||||||
|
let i = self.i;
|
||||||
|
self.i += 1;
|
||||||
|
if self.data[i] == b'\n' {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if start < self.i {
|
||||||
|
let ret = DirEntry {
|
||||||
|
name: self.data[start .. self.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> {
|
||||||
|
stat(&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 mode_t; }
|
||||||
|
|
||||||
|
fn get_access_mode(&self) -> io::Result<c_int> {
|
||||||
|
match (self.read, self.write, self.append) {
|
||||||
|
(true, false, false) => Ok(libc::O_RDONLY as c_int),
|
||||||
|
(false, true, false) => Ok(libc::O_WRONLY as c_int),
|
||||||
|
(true, true, false) => Ok(libc::O_RDWR as c_int),
|
||||||
|
(false, _, true) => Ok(libc::O_WRONLY as c_int | libc::O_APPEND as c_int),
|
||||||
|
(true, _, true) => Ok(libc::O_RDWR as c_int | libc::O_APPEND as c_int),
|
||||||
|
(false, false, false) => Err(Error::from_raw_os_error(libc::EINVAL)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_creation_mode(&self) -> io::Result<c_int> {
|
||||||
|
match (self.write, self.append) {
|
||||||
|
(true, false) => {}
|
||||||
|
(false, false) =>
|
||||||
|
if self.truncate || self.create || self.create_new {
|
||||||
|
return Err(Error::from_raw_os_error(libc::EINVAL));
|
||||||
|
},
|
||||||
|
(_, true) =>
|
||||||
|
if self.truncate && !self.create_new {
|
||||||
|
return Err(Error::from_raw_os_error(libc::EINVAL));
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(match (self.create, self.truncate, self.create_new) {
|
||||||
|
(false, false, false) => 0,
|
||||||
|
(true, false, false) => libc::O_CREAT as c_int,
|
||||||
|
(false, true, false) => libc::O_TRUNC as c_int,
|
||||||
|
(true, true, false) => libc::O_CREAT as c_int | libc::O_TRUNC as c_int,
|
||||||
|
(_, _, true) => libc::O_CREAT as c_int | libc::O_EXCL as c_int,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl File {
|
||||||
|
pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
|
||||||
|
let path = cstr(path)?;
|
||||||
|
File::open_c(&path, opts)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn open_c(path: &CStr, opts: &OpenOptions) -> io::Result<File> {
|
||||||
|
let flags = libc::O_CLOEXEC as i32 |
|
||||||
|
opts.get_access_mode()? |
|
||||||
|
opts.get_creation_mode()? |
|
||||||
|
(opts.custom_flags as usize & !libc::O_ACCMODE) as i32;
|
||||||
|
let fd = cvt_r(|| unsafe {
|
||||||
|
open64(path.as_ptr(), flags, opts.mode as mode_t)
|
||||||
|
})?;
|
||||||
|
let fd = FileDesc::new(fd);
|
||||||
|
|
||||||
|
Ok(File(fd))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn file_attr(&self) -> io::Result<FileAttr> {
|
||||||
|
let mut stat: stat64 = unsafe { mem::zeroed() };
|
||||||
|
cvt(unsafe {
|
||||||
|
fstat64(self.0.raw(), &mut stat)
|
||||||
|
})?;
|
||||||
|
Ok(FileAttr { stat: stat })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn fsync(&self) -> io::Result<()> {
|
||||||
|
cvt_r(|| unsafe { libc::fsync(self.0.raw()) })?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn datasync(&self) -> io::Result<()> {
|
||||||
|
cvt_r(|| unsafe { os_datasync(self.0.raw()) })?;
|
||||||
|
return Ok(());
|
||||||
|
|
||||||
|
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||||
|
unsafe fn os_datasync(fd: c_int) -> c_int {
|
||||||
|
libc::fcntl(fd, libc::F_FULLFSYNC)
|
||||||
|
}
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
unsafe fn os_datasync(fd: c_int) -> c_int { libc::fdatasync(fd) }
|
||||||
|
#[cfg(not(any(target_os = "macos",
|
||||||
|
target_os = "ios",
|
||||||
|
target_os = "linux")))]
|
||||||
|
unsafe fn os_datasync(fd: c_int) -> c_int { libc::fsync(fd) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn truncate(&self, size: u64) -> io::Result<()> {
|
||||||
|
#[cfg(target_os = "android")]
|
||||||
|
return ::sys::android::ftruncate64(self.0.raw(), size);
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "android"))]
|
||||||
|
return cvt_r(|| unsafe {
|
||||||
|
ftruncate64(self.0.raw(), size as off64_t)
|
||||||
|
}).map(|_| ());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
|
||||||
|
self.0.read(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||||
|
self.0.read_to_end(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) => (libc::SEEK_SET, off as i64),
|
||||||
|
SeekFrom::End(off) => (libc::SEEK_END, off),
|
||||||
|
SeekFrom::Current(off) => (libc::SEEK_CUR, off),
|
||||||
|
};
|
||||||
|
let n = cvt(unsafe { lseek64(self.0.raw(), pos as usize, whence) } as isize)?;
|
||||||
|
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> {
|
||||||
|
libc::dup_extra(*self.fd().as_inner() as usize, buf)
|
||||||
|
.map(|fd| File(FileDesc::new(fd as i32)))
|
||||||
|
.map_err(|err| Error::from_raw_os_error(err.errno))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn path(&self) -> io::Result<PathBuf> {
|
||||||
|
let mut buf: [u8; 4096] = [0; 4096];
|
||||||
|
match libc::fpath(*self.fd().as_inner() as usize, &mut buf) {
|
||||||
|
Ok(count) => Ok(PathBuf::from(unsafe { String::from_utf8_unchecked(Vec::from(&buf[0..count])) })),
|
||||||
|
Err(err) => Err(Error::from_raw_os_error(err.errno)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 p = cstr(p)?;
|
||||||
|
cvt(unsafe { libc::mkdir(p.as_ptr(), self.mode) })?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_mode(&mut self, mode: u32) {
|
||||||
|
self.mode = mode as mode_t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cstr(path: &Path) -> io::Result<CString> {
|
||||||
|
Ok(CString::new(path.as_os_str().as_bytes())?)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromInner<c_int> for File {
|
||||||
|
fn from_inner(fd: c_int) -> File {
|
||||||
|
File(FileDesc::new(fd))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for File {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
fn get_path(fd: c_int) -> Option<PathBuf> {
|
||||||
|
let mut p = PathBuf::from("/proc/self/fd");
|
||||||
|
p.push(&fd.to_string());
|
||||||
|
readlink(&p).ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "macos")]
|
||||||
|
fn get_path(fd: c_int) -> Option<PathBuf> {
|
||||||
|
// FIXME: The use of PATH_MAX is generally not encouraged, but it
|
||||||
|
// is inevitable in this case because OS X defines `fcntl` with
|
||||||
|
// `F_GETPATH` in terms of `MAXPATHLEN`, and there are no
|
||||||
|
// alternatives. If a better method is invented, it should be used
|
||||||
|
// instead.
|
||||||
|
let mut buf = vec![0;libc::PATH_MAX as usize];
|
||||||
|
let n = unsafe { libc::fcntl(fd, libc::F_GETPATH, buf.as_ptr()) };
|
||||||
|
if n == -1 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let l = buf.iter().position(|&c| c == 0).unwrap();
|
||||||
|
buf.truncate(l as usize);
|
||||||
|
buf.shrink_to_fit();
|
||||||
|
Some(PathBuf::from(OsString::from_vec(buf)))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
|
||||||
|
fn get_path(_fd: c_int) -> Option<PathBuf> {
|
||||||
|
// FIXME(#24570): implement this for other Unix platforms
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||||
|
fn get_mode(fd: c_int) -> Option<(bool, bool)> {
|
||||||
|
let mode = unsafe { libc::fcntl(fd, libc::F_GETFL) };
|
||||||
|
if mode == -1 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
match mode & libc::O_ACCMODE {
|
||||||
|
libc::O_RDONLY => Some((true, false)),
|
||||||
|
libc::O_RDWR => Some((true, true)),
|
||||||
|
libc::O_WRONLY => Some((false, true)),
|
||||||
|
_ => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(any(target_os = "linux", target_os = "macos")))]
|
||||||
|
fn get_mode(_fd: c_int) -> Option<(bool, bool)> {
|
||||||
|
// FIXME(#24570): implement this for other Unix platforms
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
let fd = self.0.raw();
|
||||||
|
let mut b = f.debug_struct("File");
|
||||||
|
b.field("fd", &fd);
|
||||||
|
if let Some(path) = get_path(fd) {
|
||||||
|
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 p = cstr(p)?;
|
||||||
|
unsafe {
|
||||||
|
let fd = FileDesc::new(cvt(libc::open(p.as_ptr(), 0, 0))?);
|
||||||
|
let mut data = Vec::new();
|
||||||
|
fd.read_to_end(&mut data)?;
|
||||||
|
Ok(ReadDir { data: data, i: 0, root: root })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unlink(p: &Path) -> io::Result<()> {
|
||||||
|
let p = cstr(p)?;
|
||||||
|
cvt(unsafe { libc::unlink(p.as_ptr()) })?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn rmdir(p: &Path) -> io::Result<()> {
|
||||||
|
let p = cstr(p)?;
|
||||||
|
cvt(unsafe { libc::rmdir(p.as_ptr()) })?;
|
||||||
|
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> {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn symlink(_src: &Path, _dst: &Path) -> io::Result<()> {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn stat(p: &Path) -> io::Result<FileAttr> {
|
||||||
|
let p = cstr(p)?;
|
||||||
|
let mut stat: stat64 = unsafe { mem::zeroed() };
|
||||||
|
cvt(unsafe {
|
||||||
|
stat64(p.as_ptr(), &mut stat as *mut _ as *mut _)
|
||||||
|
})?;
|
||||||
|
Ok(FileAttr { stat: stat })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn lstat(p: &Path) -> io::Result<FileAttr> {
|
||||||
|
let p = cstr(p)?;
|
||||||
|
let mut stat: stat64 = unsafe { mem::zeroed() };
|
||||||
|
cvt(unsafe {
|
||||||
|
lstat64(p.as_ptr(), &mut stat as *mut _ as *mut _)
|
||||||
|
})?;
|
||||||
|
Ok(FileAttr { stat: stat })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn canonicalize(_p: &Path) -> io::Result<PathBuf> {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
14
src/libstd/sys/redox/memchr.rs
Normal file
14
src/libstd/sys/redox/memchr.rs
Normal file
|
@ -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 sys_common::memchr::fallback::{memchr, memrchr};
|
111
src/libstd/sys/redox/mod.rs
Normal file
111
src/libstd/sys/redox/mod.rs
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
#![allow(dead_code, missing_docs, bad_style)]
|
||||||
|
|
||||||
|
use io::{self, ErrorKind};
|
||||||
|
use libc;
|
||||||
|
|
||||||
|
pub mod args;
|
||||||
|
pub mod backtrace;
|
||||||
|
pub mod condvar;
|
||||||
|
pub mod env;
|
||||||
|
pub mod ext;
|
||||||
|
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 thread;
|
||||||
|
pub mod thread_local;
|
||||||
|
pub mod time;
|
||||||
|
|
||||||
|
#[cfg(not(test))]
|
||||||
|
pub fn init() {
|
||||||
|
use alloc::oom;
|
||||||
|
|
||||||
|
oom::set_oom_handler(oom_handler);
|
||||||
|
|
||||||
|
// A nicer handler for out-of-memory situations than the default one. This
|
||||||
|
// one prints a message to stderr before aborting. It is critical that this
|
||||||
|
// code does not allocate any memory since we are in an OOM situation. Any
|
||||||
|
// errors are ignored while printing since there's nothing we can do about
|
||||||
|
// them and we are about to exit anyways.
|
||||||
|
fn oom_handler() -> ! {
|
||||||
|
use intrinsics;
|
||||||
|
let msg = "fatal runtime error: out of memory\n";
|
||||||
|
unsafe {
|
||||||
|
libc::write(libc::STDERR_FILENO,
|
||||||
|
msg.as_ptr() as *const libc::c_void,
|
||||||
|
msg.len());
|
||||||
|
intrinsics::abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decode_error_kind(errno: i32) -> ErrorKind {
|
||||||
|
match errno as libc::c_int {
|
||||||
|
libc::ECONNREFUSED => ErrorKind::ConnectionRefused,
|
||||||
|
libc::ECONNRESET => ErrorKind::ConnectionReset,
|
||||||
|
libc::EPERM | libc::EACCES => ErrorKind::PermissionDenied,
|
||||||
|
libc::EPIPE => ErrorKind::BrokenPipe,
|
||||||
|
libc::ENOTCONN => ErrorKind::NotConnected,
|
||||||
|
libc::ECONNABORTED => ErrorKind::ConnectionAborted,
|
||||||
|
libc::EADDRNOTAVAIL => ErrorKind::AddrNotAvailable,
|
||||||
|
libc::EADDRINUSE => ErrorKind::AddrInUse,
|
||||||
|
libc::ENOENT => ErrorKind::NotFound,
|
||||||
|
libc::EINTR => ErrorKind::Interrupted,
|
||||||
|
libc::EINVAL => ErrorKind::InvalidInput,
|
||||||
|
libc::ETIMEDOUT => ErrorKind::TimedOut,
|
||||||
|
libc::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 == libc::EAGAIN || x == libc::EWOULDBLOCK =>
|
||||||
|
ErrorKind::WouldBlock,
|
||||||
|
|
||||||
|
_ => ErrorKind::Other,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub trait IsMinusOne {
|
||||||
|
fn is_minus_one(&self) -> bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro_rules! impl_is_minus_one {
|
||||||
|
($($t:ident)*) => ($(impl IsMinusOne for $t {
|
||||||
|
fn is_minus_one(&self) -> bool {
|
||||||
|
*self == -1
|
||||||
|
}
|
||||||
|
})*)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl_is_minus_one! { i8 i16 i32 i64 isize }
|
||||||
|
|
||||||
|
pub fn cvt<T: IsMinusOne>(t: T) -> io::Result<T> {
|
||||||
|
if t.is_minus_one() {
|
||||||
|
Err(io::Error::last_os_error())
|
||||||
|
} else {
|
||||||
|
Ok(t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cvt_r<T, F>(mut f: F) -> io::Result<T>
|
||||||
|
where T: IsMinusOne,
|
||||||
|
F: FnMut() -> T
|
||||||
|
{
|
||||||
|
loop {
|
||||||
|
match cvt(f()) {
|
||||||
|
Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
|
||||||
|
other => return other,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
125
src/libstd/sys/redox/mutex.rs
Normal file
125
src/libstd/sys/redox/mutex.rs
Normal file
|
@ -0,0 +1,125 @@
|
||||||
|
use cell::UnsafeCell;
|
||||||
|
use intrinsics::{atomic_cxchg, atomic_xchg};
|
||||||
|
use ptr;
|
||||||
|
|
||||||
|
use libc::{futex, 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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn init(&self) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Try to lock the mutex
|
||||||
|
pub unsafe fn try_lock(&self) -> bool {
|
||||||
|
mutex_try_lock(self.lock.get())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Lock the mutex
|
||||||
|
pub unsafe fn lock(&self) {
|
||||||
|
mutex_lock(self.lock.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unlock the mutex
|
||||||
|
pub unsafe fn unlock(&self) {
|
||||||
|
mutex_unlock(self.lock.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn destroy(&self) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Send for Mutex {}
|
||||||
|
|
||||||
|
unsafe impl Sync for Mutex {}
|
||||||
|
|
||||||
|
pub struct ReentrantMutex {
|
||||||
|
pub lock: UnsafeCell<i32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ReentrantMutex {
|
||||||
|
pub const fn uninitialized() -> Self {
|
||||||
|
ReentrantMutex {
|
||||||
|
lock: UnsafeCell::new(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn init(&mut self) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Try to lock the mutex
|
||||||
|
pub unsafe fn try_lock(&self) -> bool {
|
||||||
|
mutex_try_lock(self.lock.get())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Lock the mutex
|
||||||
|
pub unsafe fn lock(&self) {
|
||||||
|
mutex_lock(self.lock.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Unlock the mutex
|
||||||
|
pub unsafe fn unlock(&self) {
|
||||||
|
mutex_unlock(self.lock.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn destroy(&self) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe impl Send for ReentrantMutex {}
|
||||||
|
|
||||||
|
unsafe impl Sync for ReentrantMutex {}
|
12
src/libstd/sys/redox/net/dns/answer.rs
Normal file
12
src/libstd/sys/redox/net/dns/answer.rs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
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>
|
||||||
|
}
|
207
src/libstd/sys/redox/net/dns/mod.rs
Normal file
207
src/libstd/sys/redox/net/dns/mod.rs
Normal file
|
@ -0,0 +1,207 @@
|
||||||
|
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 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();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let name_len = pop_u8!();
|
||||||
|
if name_len == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ! name.is_empty() {
|
||||||
|
name.push('.');
|
||||||
|
}
|
||||||
|
for _name_i in 0..name_len {
|
||||||
|
name.push(pop_u8!() as char);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
let name_ind = 0b11000000;
|
||||||
|
let name_test = pop_u8!();
|
||||||
|
i -= 1;
|
||||||
|
|
||||||
|
answers.push(DnsAnswer {
|
||||||
|
name: if name_test & name_ind == name_ind {
|
||||||
|
let name_off = pop_n16!() - ((name_ind as u16) << 8);
|
||||||
|
let old_i = i;
|
||||||
|
i = name_off as usize;
|
||||||
|
let name = pop_name!();
|
||||||
|
i = old_i;
|
||||||
|
name
|
||||||
|
} else {
|
||||||
|
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: transaction_id,
|
||||||
|
flags: flags,
|
||||||
|
queries: queries,
|
||||||
|
answers: answers,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
8
src/libstd/sys/redox/net/dns/query.rs
Normal file
8
src/libstd/sys/redox/net/dns/query.rs
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
use string::String;
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct DnsQuery {
|
||||||
|
pub name: String,
|
||||||
|
pub q_type: u16,
|
||||||
|
pub q_class: u16
|
||||||
|
}
|
91
src/libstd/sys/redox/net/mod.rs
Normal file
91
src/libstd/sys/redox/net/mod.rs
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
use fs::File;
|
||||||
|
use io::{Error, Result, Read};
|
||||||
|
use iter::Iterator;
|
||||||
|
use net::{Ipv4Addr, SocketAddr, SocketAddrV4};
|
||||||
|
use str::FromStr;
|
||||||
|
use string::{String, ToString};
|
||||||
|
use libc::EINVAL;
|
||||||
|
use time;
|
||||||
|
use vec::{IntoIter, Vec};
|
||||||
|
|
||||||
|
use self::dns::{Dns, DnsQuery};
|
||||||
|
|
||||||
|
pub extern crate libc as netc;
|
||||||
|
pub use self::tcp::{TcpStream, TcpListener};
|
||||||
|
pub use self::udp::UdpSocket;
|
||||||
|
|
||||||
|
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 tid = (time::SystemTime::now().duration_since(time::UNIX_EPOCH).unwrap().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 socket = UdpSocket::bind(&SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(ip[0], ip[1], ip[2], ip[3]), 0)))?;
|
||||||
|
socket.connect(&SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(dns[0], dns[1], dns[2], dns[3]), 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 {
|
||||||
|
addrs.push(SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(answer.data[0], answer.data[1], answer.data[2], answer.data[3]), 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))
|
||||||
|
}
|
160
src/libstd/sys/redox/net/tcp.rs
Normal file
160
src/libstd/sys/redox/net/tcp.rs
Normal file
|
@ -0,0 +1,160 @@
|
||||||
|
use io::{Error, ErrorKind, Result};
|
||||||
|
use net::{SocketAddr, Shutdown};
|
||||||
|
use path::Path;
|
||||||
|
use sys::fs::{File, OpenOptions};
|
||||||
|
use time::Duration;
|
||||||
|
use vec::Vec;
|
||||||
|
|
||||||
|
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 duplicate(&self) -> Result<TcpStream> {
|
||||||
|
Ok(TcpStream(self.0.dup(&[])?))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read(&self, buf: &mut [u8]) -> Result<usize> {
|
||||||
|
self.0.read(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> Result<usize> {
|
||||||
|
self.0.read_to_end(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 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> {
|
||||||
|
Err(Error::new(ErrorKind::Other, "TcpStream::nonblocking not implemented"))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn only_v6(&self) -> Result<bool> {
|
||||||
|
Err(Error::new(ErrorKind::Other, "TcpStream::only_v6 not implemented"))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ttl(&self) -> Result<u32> {
|
||||||
|
Err(Error::new(ErrorKind::Other, "TcpStream::ttl not implemented"))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_timeout(&self) -> Result<Option<Duration>> {
|
||||||
|
Err(Error::new(ErrorKind::Other, "TcpStream::read_timeout not implemented"))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_timeout(&self) -> Result<Option<Duration>> {
|
||||||
|
Err(Error::new(ErrorKind::Other, "TcpStream::write_timeout not implemented"))
|
||||||
|
}
|
||||||
|
|
||||||
|
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<()> {
|
||||||
|
Err(Error::new(ErrorKind::Other, "TcpStream::set_nonblocking not implemented"))
|
||||||
|
}
|
||||||
|
|
||||||
|
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<()> {
|
||||||
|
Err(Error::new(ErrorKind::Other, "TcpStream::set_ttl not implemented"))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_read_timeout(&self, _dur: Option<Duration>) -> Result<()> {
|
||||||
|
Err(Error::new(ErrorKind::Other, "TcpStream::set_read_timeout not implemented"))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_write_timeout(&self, _dur: Option<Duration>) -> Result<()> {
|
||||||
|
Err(Error::new(ErrorKind::Other, "TcpStream::set_write_timeout not implemented"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[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> {
|
||||||
|
Err(Error::new(ErrorKind::Other, "TcpListener::ttl not implemented"))
|
||||||
|
}
|
||||||
|
|
||||||
|
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<()> {
|
||||||
|
Err(Error::new(ErrorKind::Other, "TcpListener::set_ttl not implemented"))
|
||||||
|
}
|
||||||
|
}
|
163
src/libstd/sys/redox/net/udp.rs
Normal file
163
src/libstd/sys/redox/net/udp.rs
Normal file
|
@ -0,0 +1,163 @@
|
||||||
|
use cell::UnsafeCell;
|
||||||
|
use io::{Error, ErrorKind, Result};
|
||||||
|
use net::{SocketAddr, Ipv4Addr, Ipv6Addr};
|
||||||
|
use path::Path;
|
||||||
|
use sys::fs::{File, OpenOptions};
|
||||||
|
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 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> {
|
||||||
|
Err(Error::new(ErrorKind::Other, "UdpSocket::nonblocking not implemented"))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn only_v6(&self) -> Result<bool> {
|
||||||
|
Err(Error::new(ErrorKind::Other, "UdpSocket::only_v6 not implemented"))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ttl(&self) -> Result<u32> {
|
||||||
|
Err(Error::new(ErrorKind::Other, "UdpSocket::ttl not implemented"))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_timeout(&self) -> Result<Option<Duration>> {
|
||||||
|
Err(Error::new(ErrorKind::Other, "UdpSocket::read_timeout not implemented"))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_timeout(&self) -> Result<Option<Duration>> {
|
||||||
|
Err(Error::new(ErrorKind::Other, "UdpSocket::write_timeout not implemented"))
|
||||||
|
}
|
||||||
|
|
||||||
|
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<()> {
|
||||||
|
Err(Error::new(ErrorKind::Other, "UdpSocket::set_nonblocking not implemented"))
|
||||||
|
}
|
||||||
|
|
||||||
|
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<()> {
|
||||||
|
Err(Error::new(ErrorKind::Other, "UdpSocket::set_ttl not implemented"))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_read_timeout(&self, _dur: Option<Duration>) -> Result<()> {
|
||||||
|
Err(Error::new(ErrorKind::Other, "UdpSocket::set_read_timeout not implemented"))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_write_timeout(&self, _dur: Option<Duration>) -> Result<()> {
|
||||||
|
Err(Error::new(ErrorKind::Other, "UdpSocket::set_write_timeout not implemented"))
|
||||||
|
}
|
||||||
|
|
||||||
|
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"))
|
||||||
|
}
|
||||||
|
}
|
246
src/libstd/sys/redox/os.rs
Normal file
246
src/libstd/sys/redox/os.rs
Normal file
|
@ -0,0 +1,246 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
//! 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::{CString, CStr, OsString, OsStr};
|
||||||
|
use fmt;
|
||||||
|
use io;
|
||||||
|
use iter;
|
||||||
|
use libc::{self, c_int, c_char, c_void};
|
||||||
|
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;
|
||||||
|
use sys::fd;
|
||||||
|
use vec;
|
||||||
|
|
||||||
|
const TMPBUF_SZ: usize = 128;
|
||||||
|
static ENV_LOCK: Mutex = Mutex::new();
|
||||||
|
|
||||||
|
|
||||||
|
extern {
|
||||||
|
#[cfg(not(target_os = "dragonfly"))]
|
||||||
|
#[cfg_attr(any(target_os = "linux", target_os = "emscripten", target_os = "fuchsia"),
|
||||||
|
link_name = "__errno_location")]
|
||||||
|
#[cfg_attr(any(target_os = "bitrig",
|
||||||
|
target_os = "netbsd",
|
||||||
|
target_os = "openbsd",
|
||||||
|
target_os = "android",
|
||||||
|
target_env = "newlib"),
|
||||||
|
link_name = "__errno")]
|
||||||
|
#[cfg_attr(target_os = "solaris", link_name = "___errno")]
|
||||||
|
#[cfg_attr(any(target_os = "macos",
|
||||||
|
target_os = "ios",
|
||||||
|
target_os = "freebsd"),
|
||||||
|
link_name = "__error")]
|
||||||
|
#[cfg_attr(target_os = "haiku", link_name = "_errnop")]
|
||||||
|
fn errno_location() -> *mut c_int;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the platform-specific value of errno
|
||||||
|
#[cfg(not(target_os = "dragonfly"))]
|
||||||
|
pub fn errno() -> i32 {
|
||||||
|
unsafe {
|
||||||
|
(*errno_location()) as i32
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets the platform-specific value of errno
|
||||||
|
#[cfg(target_os = "solaris")] // only needed for readdir so far
|
||||||
|
pub fn set_errno(e: i32) {
|
||||||
|
unsafe {
|
||||||
|
*errno_location() = e as c_int
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "dragonfly")]
|
||||||
|
pub fn errno() -> i32 {
|
||||||
|
extern {
|
||||||
|
#[thread_local]
|
||||||
|
static errno: c_int;
|
||||||
|
}
|
||||||
|
|
||||||
|
errno as i32
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets a detailed string description for the given error number.
|
||||||
|
pub fn error_string(errno: i32) -> String {
|
||||||
|
extern {
|
||||||
|
#[cfg_attr(any(target_os = "linux", target_env = "newlib"),
|
||||||
|
link_name = "__xpg_strerror_r")]
|
||||||
|
fn strerror_r(errnum: c_int, buf: *mut c_char,
|
||||||
|
buflen: libc::size_t) -> c_int;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut buf = [0 as c_char; TMPBUF_SZ];
|
||||||
|
|
||||||
|
let p = buf.as_mut_ptr();
|
||||||
|
unsafe {
|
||||||
|
if strerror_r(errno as c_int, p, buf.len()) < 0 {
|
||||||
|
panic!("strerror_r failure");
|
||||||
|
}
|
||||||
|
|
||||||
|
let p = p as *const _;
|
||||||
|
str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap().to_owned()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getcwd() -> io::Result<PathBuf> {
|
||||||
|
let mut buf = Vec::with_capacity(512);
|
||||||
|
loop {
|
||||||
|
unsafe {
|
||||||
|
let ptr = buf.as_mut_ptr() as *mut libc::c_char;
|
||||||
|
if !libc::getcwd(ptr, buf.capacity()).is_null() {
|
||||||
|
let len = CStr::from_ptr(buf.as_ptr() as *const libc::c_char).to_bytes().len();
|
||||||
|
buf.set_len(len);
|
||||||
|
buf.shrink_to_fit();
|
||||||
|
return Ok(PathBuf::from(OsString::from_vec(buf)));
|
||||||
|
} else {
|
||||||
|
let error = io::Error::last_os_error();
|
||||||
|
if error.raw_os_error() != Some(libc::ERANGE) {
|
||||||
|
return Err(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trigger the internal buffer resizing logic of `Vec` by requiring
|
||||||
|
// more space than the current capacity.
|
||||||
|
let cap = buf.capacity();
|
||||||
|
buf.set_len(cap);
|
||||||
|
buf.reserve(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn chdir(p: &path::Path) -> io::Result<()> {
|
||||||
|
let p: &OsStr = p.as_ref();
|
||||||
|
let p = CString::new(p.as_bytes())?;
|
||||||
|
unsafe {
|
||||||
|
match libc::chdir(p.as_ptr()) == (0 as c_int) {
|
||||||
|
true => Ok(()),
|
||||||
|
false => Err(io::Error::last_os_error()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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_colon(b: &u8) -> bool { *b == b':' }
|
||||||
|
let unparsed = unparsed.as_bytes();
|
||||||
|
SplitPaths {
|
||||||
|
iter: unparsed.split(is_colon 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 io::ErrorKind;
|
||||||
|
Err(io::Error::new(ErrorKind::Other, "Not yet implemented on redox"))
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn getenv(_k: &OsStr) -> io::Result<Option<OsString>> {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setenv(_k: &OsStr, _v: &OsStr) -> io::Result<()> {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unsetenv(_n: &OsStr) -> io::Result<()> {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
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) -> ! {
|
||||||
|
unsafe { libc::exit(code as c_int) }
|
||||||
|
}
|
119
src/libstd/sys/redox/os_str.rs
Normal file
119
src/libstd/sys/redox/os_str.rs
Normal file
|
@ -0,0 +1,119 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
/// The underlying OsString/OsStr implementation on Unix systems: just
|
||||||
|
/// a `Vec<u8>`/`[u8]`.
|
||||||
|
|
||||||
|
use borrow::Cow;
|
||||||
|
use fmt::{self, Debug};
|
||||||
|
use str;
|
||||||
|
use mem;
|
||||||
|
use sys_common::{AsInner, IntoInner};
|
||||||
|
|
||||||
|
#[derive(Clone, Hash)]
|
||||||
|
pub struct Buf {
|
||||||
|
pub inner: Vec<u8>
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Slice {
|
||||||
|
pub inner: [u8]
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Slice {
|
||||||
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||||
|
self.to_string_lossy().fmt(formatter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Debug for Buf {
|
||||||
|
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
|
||||||
|
self.as_slice().fmt(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)
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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() }
|
||||||
|
}
|
||||||
|
}
|
29
src/libstd/sys/redox/path.rs
Normal file
29
src/libstd/sys/redox/path.rs
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
use path::Prefix;
|
||||||
|
use ffi::OsStr;
|
||||||
|
|
||||||
|
#[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(_: &OsStr) -> Option<Prefix> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const MAIN_SEP_STR: &'static str = "/";
|
||||||
|
pub const MAIN_SEP: char = '/';
|
105
src/libstd/sys/redox/pipe.rs
Normal file
105
src/libstd/sys/redox/pipe.rs
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
use io;
|
||||||
|
use libc::{self, c_int};
|
||||||
|
use sys::fd::FileDesc;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Anonymous pipes
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
pub struct AnonPipe(FileDesc);
|
||||||
|
|
||||||
|
pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
|
||||||
|
let mut fds = [0; 2];
|
||||||
|
|
||||||
|
libc::pipe2(&mut fds, libc::O_CLOEXEC).map_err(|err| io::Error::from_raw_os_error(err.errno))?;
|
||||||
|
|
||||||
|
let fd0 = FileDesc::new(fds[0] as c_int);
|
||||||
|
let fd1 = FileDesc::new(fds[1] as c_int);
|
||||||
|
Ok((AnonPipe::from_fd(fd0)?, AnonPipe::from_fd(fd1)?))
|
||||||
|
}
|
||||||
|
|
||||||
|
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 read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||||
|
self.0.read_to_end(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<()> {
|
||||||
|
unimplemented!();
|
||||||
|
/*
|
||||||
|
// 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)?;
|
||||||
|
|
||||||
|
let max = cmp::max(p1.raw(), p2.raw());
|
||||||
|
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(|_| ());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
593
src/libstd/sys/redox/process.rs
Normal file
593
src/libstd/sys/redox/process.rs
Normal file
|
@ -0,0 +1,593 @@
|
||||||
|
// 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 os::unix::prelude::*;
|
||||||
|
|
||||||
|
use collections::hash_map::HashMap;
|
||||||
|
use env;
|
||||||
|
use ffi::{OsStr, CString, CStr};
|
||||||
|
use fmt;
|
||||||
|
use io::{self, Error, ErrorKind};
|
||||||
|
use libc::{self, pid_t, c_int, gid_t, uid_t};
|
||||||
|
use sys::fd::FileDesc;
|
||||||
|
use sys::fs::{File, OpenOptions};
|
||||||
|
use sys::pipe::{self, AnonPipe};
|
||||||
|
use sys::{self, cvt, cvt_r};
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// 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: HashMap<String, String>,
|
||||||
|
|
||||||
|
cwd: Option<CString>,
|
||||||
|
uid: Option<uid_t>,
|
||||||
|
gid: Option<gid_t>,
|
||||||
|
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(c_int),
|
||||||
|
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: HashMap::new(),
|
||||||
|
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 self, key: &OsStr, val: &OsStr) {
|
||||||
|
self.env.insert(key.to_str().unwrap().to_owned(), val.to_str().unwrap().to_owned());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn env_remove(&mut self, key: &OsStr) {
|
||||||
|
self.env.remove(key.to_str().unwrap());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn env_clear(&mut self) {
|
||||||
|
self.env.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cwd(&mut self, dir: &OsStr) {
|
||||||
|
self.cwd = Some(os2c(dir, &mut self.saw_nul));
|
||||||
|
}
|
||||||
|
pub fn uid(&mut self, id: uid_t) {
|
||||||
|
self.uid = Some(id);
|
||||||
|
}
|
||||||
|
pub fn gid(&mut self, id: gid_t) {
|
||||||
|
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) = sys::pipe::anon_pipe()?;
|
||||||
|
|
||||||
|
let pid = unsafe {
|
||||||
|
match cvt(libc::fork() as isize)? {
|
||||||
|
0 => {
|
||||||
|
drop(input);
|
||||||
|
let err = self.do_exec(theirs);
|
||||||
|
let errno = err.raw_os_error().unwrap_or(libc::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());
|
||||||
|
libc::_exit(1)
|
||||||
|
}
|
||||||
|
n => n as pid_t,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
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 OSX 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 libc::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() {
|
||||||
|
libc::close(libc::STDERR_FILENO);
|
||||||
|
t!(cvt(libc::dup(fd)));
|
||||||
|
libc::close(fd);
|
||||||
|
}
|
||||||
|
if let Some(fd) = stdio.stdout.fd() {
|
||||||
|
libc::close(libc::STDOUT_FILENO);
|
||||||
|
t!(cvt(libc::dup(fd)));
|
||||||
|
libc::close(fd);
|
||||||
|
}
|
||||||
|
if let Some(fd) = stdio.stdin.fd() {
|
||||||
|
libc::close(libc::STDIN_FILENO);
|
||||||
|
t!(cvt(libc::dup(fd)));
|
||||||
|
libc::close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(u) = self.gid {
|
||||||
|
t!(cvt(libc::setgid(u as gid_t)));
|
||||||
|
}
|
||||||
|
if let Some(u) = self.uid {
|
||||||
|
t!(cvt(libc::setuid(u as uid_t)));
|
||||||
|
}
|
||||||
|
if let Some(ref cwd) = self.cwd {
|
||||||
|
t!(cvt(libc::chdir(cwd.as_ptr())));
|
||||||
|
}
|
||||||
|
|
||||||
|
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()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (key, val) in self.env.iter() {
|
||||||
|
env::set_var(key, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Err(err) = libc::exec(&self.program, &args) {
|
||||||
|
io::Error::from_raw_os_error(err.errno as i32)
|
||||||
|
} else {
|
||||||
|
panic!("return from exec without err");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn os2c(s: &OsStr, saw_nul: &mut bool) -> CString {
|
||||||
|
CString::new(s.as_bytes()).unwrap_or_else(|_e| {
|
||||||
|
*saw_nul = true;
|
||||||
|
CString::new("<string-with-nul>").unwrap()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
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() >= 0 && fd.raw() <= libc::STDERR_FILENO {
|
||||||
|
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 path = unsafe {
|
||||||
|
CStr::from_ptr("/dev/null\0".as_ptr() as *const _)
|
||||||
|
};
|
||||||
|
let fd = File::open_c(&path, &opts)?;
|
||||||
|
Ok((ChildStdio::Owned(fd.into_fd()), None))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ChildStdio {
|
||||||
|
fn fd(&self) -> Option<c_int> {
|
||||||
|
match *self {
|
||||||
|
ChildStdio::Inherit => None,
|
||||||
|
ChildStdio::Explicit(fd) => Some(fd),
|
||||||
|
ChildStdio::Owned(ref fd) => Some(fd.raw()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pair_to_key(key: &OsStr, value: &OsStr, saw_nul: &mut bool) -> CString {
|
||||||
|
let (key, value) = (key.as_bytes(), value.as_bytes());
|
||||||
|
let mut v = Vec::with_capacity(key.len() + value.len() + 1);
|
||||||
|
v.extend(key);
|
||||||
|
v.push(b'=');
|
||||||
|
v.extend(value);
|
||||||
|
CString::new(v).unwrap_or_else(|_e| {
|
||||||
|
*saw_nul = true;
|
||||||
|
CString::new("foo=bar").unwrap()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
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(c_int);
|
||||||
|
|
||||||
|
impl ExitStatus {
|
||||||
|
fn exited(&self) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn success(&self) -> bool {
|
||||||
|
self.code() == Some(0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn code(&self) -> Option<i32> {
|
||||||
|
if self.exited() {
|
||||||
|
Some(self.0)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn signal(&self) -> Option<i32> {
|
||||||
|
if !self.exited() {
|
||||||
|
Some(self.0)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<c_int> for ExitStatus {
|
||||||
|
fn from(a: c_int) -> 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The unique id of the process (this should never be negative).
|
||||||
|
pub struct Process {
|
||||||
|
pid: pid_t,
|
||||||
|
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(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(|_| ())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn wait(&mut self) -> io::Result<ExitStatus> {
|
||||||
|
if let Some(status) = self.status {
|
||||||
|
return Ok(status)
|
||||||
|
}
|
||||||
|
let mut status = 0;
|
||||||
|
cvt_r(|| unsafe { libc::waitpid(self.pid, &mut status, 0) })?;
|
||||||
|
self.status = Some(ExitStatus(status as i32));
|
||||||
|
Ok(ExitStatus(status as i32))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(all(test, not(target_os = "emscripten")))]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
use ffi::OsStr;
|
||||||
|
use mem;
|
||||||
|
use ptr;
|
||||||
|
use libc;
|
||||||
|
use sys::cvt;
|
||||||
|
|
||||||
|
macro_rules! t {
|
||||||
|
($e:expr) => {
|
||||||
|
match $e {
|
||||||
|
Ok(t) => t,
|
||||||
|
Err(e) => panic!("received error for `{}`: {}", stringify!($e), e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "android"))]
|
||||||
|
extern {
|
||||||
|
#[cfg_attr(target_os = "netbsd", link_name = "__sigaddset14")]
|
||||||
|
fn sigaddset(set: *mut libc::sigset_t, signum: libc::c_int) -> libc::c_int;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "android")]
|
||||||
|
unsafe fn sigaddset(set: *mut libc::sigset_t, signum: libc::c_int) -> libc::c_int {
|
||||||
|
use slice;
|
||||||
|
|
||||||
|
let raw = slice::from_raw_parts_mut(set as *mut u8, mem::size_of::<libc::sigset_t>());
|
||||||
|
let bit = (signum - 1) as usize;
|
||||||
|
raw[bit / 8] |= 1 << (bit % 8);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// See #14232 for more information, but it appears that signal delivery to a
|
||||||
|
// newly spawned process may just be raced in the OSX, so to prevent this
|
||||||
|
// test from being flaky we ignore it on OSX.
|
||||||
|
#[test]
|
||||||
|
#[cfg_attr(target_os = "macos", ignore)]
|
||||||
|
#[cfg_attr(target_os = "nacl", ignore)] // no signals on NaCl.
|
||||||
|
fn test_process_mask() {
|
||||||
|
unsafe {
|
||||||
|
// Test to make sure that a signal mask does not get inherited.
|
||||||
|
let mut cmd = Command::new(OsStr::new("cat"));
|
||||||
|
|
||||||
|
let mut set: libc::sigset_t = mem::uninitialized();
|
||||||
|
let mut old_set: libc::sigset_t = mem::uninitialized();
|
||||||
|
t!(cvt(libc::sigemptyset(&mut set)));
|
||||||
|
t!(cvt(sigaddset(&mut set, libc::SIGINT)));
|
||||||
|
t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, &set, &mut old_set)));
|
||||||
|
|
||||||
|
cmd.stdin(Stdio::MakePipe);
|
||||||
|
cmd.stdout(Stdio::MakePipe);
|
||||||
|
|
||||||
|
let (mut cat, mut pipes) = t!(cmd.spawn(Stdio::Null, true));
|
||||||
|
let stdin_write = pipes.stdin.take().unwrap();
|
||||||
|
let stdout_read = pipes.stdout.take().unwrap();
|
||||||
|
|
||||||
|
t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, &old_set,
|
||||||
|
ptr::null_mut())));
|
||||||
|
|
||||||
|
t!(cvt(libc::kill(cat.id() as libc::pid_t, libc::SIGINT)));
|
||||||
|
// We need to wait until SIGINT is definitely delivered. The
|
||||||
|
// easiest way is to write something to cat, and try to read it
|
||||||
|
// back: if SIGINT is unmasked, it'll get delivered when cat is
|
||||||
|
// next scheduled.
|
||||||
|
let _ = stdin_write.write(b"Hello");
|
||||||
|
drop(stdin_write);
|
||||||
|
|
||||||
|
// Either EOF or failure (EPIPE) is okay.
|
||||||
|
let mut buf = [0; 5];
|
||||||
|
if let Ok(ret) = stdout_read.read(&mut buf) {
|
||||||
|
assert!(ret == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
t!(cat.wait());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
40
src/libstd/sys/redox/rand.rs
Normal file
40
src/libstd/sys/redox/rand.rs
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
// Copyright 2013-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 fs::File;
|
||||||
|
use io;
|
||||||
|
use rand::Rng;
|
||||||
|
use rand::reader::ReaderRng;
|
||||||
|
|
||||||
|
pub struct OsRng {
|
||||||
|
inner: ReaderRng<File>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OsRng {
|
||||||
|
/// Create a new `OsRng`.
|
||||||
|
pub fn new() -> io::Result<OsRng> {
|
||||||
|
let reader = File::open("rand:")?;
|
||||||
|
let reader_rng = ReaderRng::new(reader);
|
||||||
|
|
||||||
|
Ok(OsRng { inner: reader_rng })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Rng for OsRng {
|
||||||
|
fn next_u32(&mut self) -> u32 {
|
||||||
|
self.inner.next_u32()
|
||||||
|
}
|
||||||
|
fn next_u64(&mut self) -> u64 {
|
||||||
|
self.inner.next_u64()
|
||||||
|
}
|
||||||
|
fn fill_bytes(&mut self, v: &mut [u8]) {
|
||||||
|
self.inner.fill_bytes(v)
|
||||||
|
}
|
||||||
|
}
|
55
src/libstd/sys/redox/rwlock.rs
Normal file
55
src/libstd/sys/redox/rwlock.rs
Normal file
|
@ -0,0 +1,55 @@
|
||||||
|
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
pub struct RWLock;
|
||||||
|
|
||||||
|
unsafe impl Send for RWLock {}
|
||||||
|
unsafe impl Sync for RWLock {}
|
||||||
|
|
||||||
|
impl RWLock {
|
||||||
|
pub const fn new() -> RWLock {
|
||||||
|
RWLock
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn read(&self) {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn try_read(&self) -> bool {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn write(&self) {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn try_write(&self) -> bool {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn read_unlock(&self) {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn write_unlock(&self) {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn destroy(&self) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
27
src/libstd/sys/redox/stack_overflow.rs
Normal file
27
src/libstd/sys/redox/stack_overflow.rs
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
#![cfg_attr(test, allow(dead_code))]
|
||||||
|
|
||||||
|
pub struct Handler;
|
||||||
|
|
||||||
|
impl Handler {
|
||||||
|
pub unsafe fn new() -> Handler {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn init() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pub unsafe fn cleanup() {
|
||||||
|
unimplemented!();
|
||||||
|
}
|
69
src/libstd/sys/redox/stdio.rs
Normal file
69
src/libstd/sys/redox/stdio.rs
Normal file
|
@ -0,0 +1,69 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
use io;
|
||||||
|
use libc;
|
||||||
|
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(libc::STDIN_FILENO);
|
||||||
|
let ret = fd.read(data);
|
||||||
|
fd.into_raw();
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
|
||||||
|
let fd = FileDesc::new(libc::STDIN_FILENO);
|
||||||
|
let ret = fd.read_to_end(buf);
|
||||||
|
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(libc::STDOUT_FILENO);
|
||||||
|
let ret = fd.write(data);
|
||||||
|
fd.into_raw();
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Stderr {
|
||||||
|
pub fn new() -> io::Result<Stderr> { Ok(Stderr(())) }
|
||||||
|
|
||||||
|
pub fn write(&self, data: &[u8]) -> io::Result<usize> {
|
||||||
|
let fd = FileDesc::new(libc::STDERR_FILENO);
|
||||||
|
let ret = fd.write(data);
|
||||||
|
fd.into_raw();
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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<()> { Ok(()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const EBADF_ERR: i32 = ::libc::EBADF;
|
94
src/libstd/sys/redox/thread.rs
Normal file
94
src/libstd/sys/redox/thread.rs
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
// 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 alloc::boxed::FnBox;
|
||||||
|
use cmp;
|
||||||
|
use ffi::CStr;
|
||||||
|
use io;
|
||||||
|
use libc;
|
||||||
|
use mem;
|
||||||
|
use sys::os;
|
||||||
|
use sys_common::thread::start_thread;
|
||||||
|
use time::Duration;
|
||||||
|
|
||||||
|
pub struct Thread {
|
||||||
|
id: libc::pid_t,
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
|
start_thread(&*p as *const _ as *mut _);
|
||||||
|
|
||||||
|
unimplemented!();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn yield_now() {
|
||||||
|
let ret = unsafe { libc::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.
|
||||||
|
unsafe {
|
||||||
|
while secs > 0 || nsecs > 0 {
|
||||||
|
let mut ts = libc::timespec {
|
||||||
|
tv_sec: cmp::min(libc::time_t::max_value() as u64, secs) as libc::time_t,
|
||||||
|
tv_nsec: nsecs,
|
||||||
|
};
|
||||||
|
secs -= ts.tv_sec as u64;
|
||||||
|
if libc::nanosleep(&ts, &mut ts) == -1 {
|
||||||
|
assert_eq!(os::errno(), libc::EINTR);
|
||||||
|
secs += ts.tv_sec as u64;
|
||||||
|
nsecs = ts.tv_nsec;
|
||||||
|
} else {
|
||||||
|
nsecs = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn join(self) {
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn id(&self) -> libc::pid_t { self.id }
|
||||||
|
|
||||||
|
pub fn into_id(self) -> libc::pid_t {
|
||||||
|
let id = self.id;
|
||||||
|
mem::forget(self);
|
||||||
|
id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for Thread {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
panic!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod guard {
|
||||||
|
pub unsafe fn current() -> Option<usize> { None }
|
||||||
|
pub unsafe fn init() -> Option<usize> { None }
|
||||||
|
}
|
41
src/libstd/sys/redox/thread_local.rs
Normal file
41
src/libstd/sys/redox/thread_local.rs
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
#![allow(dead_code)] // not used on all platforms
|
||||||
|
|
||||||
|
pub type Key = usize;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn create(_dtor: Option<unsafe extern fn(*mut u8)>) -> Key {
|
||||||
|
panic!("pthread key create not supported");
|
||||||
|
//let mut key = 0;
|
||||||
|
//assert_eq!(libc::pthread_key_create(&mut key, mem::transmute(dtor)), 0);
|
||||||
|
//key
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn set(_key: Key, _value: *mut u8) {
|
||||||
|
panic!("pthread key set not supported");
|
||||||
|
//let r = libc::pthread_setspecific(key, value as *mut _);
|
||||||
|
//debug_assert_eq!(r, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn get(_key: Key) -> *mut u8 {
|
||||||
|
panic!("pthread key get not supported");
|
||||||
|
//libc::pthread_getspecific(key) as *mut u8
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
pub unsafe fn destroy(_key: Key) {
|
||||||
|
panic!("pthread key destroy not supported");
|
||||||
|
//let r = libc::pthread_key_delete(key);
|
||||||
|
//debug_assert_eq!(r, 0);
|
||||||
|
}
|
351
src/libstd/sys/redox/time.rs
Normal file
351
src/libstd/sys/redox/time.rs
Normal file
|
@ -0,0 +1,351 @@
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
use cmp::Ordering;
|
||||||
|
use libc;
|
||||||
|
use time::Duration;
|
||||||
|
|
||||||
|
pub use self::inner::{Instant, SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
|
const NSEC_PER_SEC: u64 = 1_000_000_000;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
struct Timespec {
|
||||||
|
t: libc::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 secs = (self.t.tv_sec as i64).checked_add(other.as_secs() as i64);
|
||||||
|
let mut secs = 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: libc::timespec {
|
||||||
|
tv_sec: secs as libc::time_t,
|
||||||
|
tv_nsec: nsec as i32,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sub_duration(&self, other: &Duration) -> Timespec {
|
||||||
|
let secs = (self.t.tv_sec as i64).checked_sub(other.as_secs() as i64);
|
||||||
|
let mut secs = 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: libc::timespec {
|
||||||
|
tv_sec: secs as libc::time_t,
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||||
|
mod inner {
|
||||||
|
use fmt;
|
||||||
|
use libc;
|
||||||
|
use sync::Once;
|
||||||
|
use sys::cvt;
|
||||||
|
use sys_common::mul_div_u64;
|
||||||
|
use time::Duration;
|
||||||
|
|
||||||
|
use super::NSEC_PER_SEC;
|
||||||
|
use super::Timespec;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
||||||
|
pub struct Instant {
|
||||||
|
t: u64
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub struct SystemTime {
|
||||||
|
t: Timespec,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const UNIX_EPOCH: SystemTime = SystemTime {
|
||||||
|
t: Timespec {
|
||||||
|
t: libc::timespec {
|
||||||
|
tv_sec: 0,
|
||||||
|
tv_nsec: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
impl Instant {
|
||||||
|
pub fn now() -> Instant {
|
||||||
|
Instant { t: unsafe { libc::mach_absolute_time() } }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sub_instant(&self, other: &Instant) -> Duration {
|
||||||
|
let info = info();
|
||||||
|
let diff = self.t.checked_sub(other.t)
|
||||||
|
.expect("second instant is later than self");
|
||||||
|
let nanos = mul_div_u64(diff, info.numer as u64, info.denom as u64);
|
||||||
|
Duration::new(nanos / NSEC_PER_SEC, (nanos % NSEC_PER_SEC) as u32)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_duration(&self, other: &Duration) -> Instant {
|
||||||
|
Instant {
|
||||||
|
t: self.t.checked_add(dur2intervals(other))
|
||||||
|
.expect("overflow when adding duration to instant"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sub_duration(&self, other: &Duration) -> Instant {
|
||||||
|
Instant {
|
||||||
|
t: self.t.checked_sub(dur2intervals(other))
|
||||||
|
.expect("overflow when adding duration to instant"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SystemTime {
|
||||||
|
pub fn now() -> SystemTime {
|
||||||
|
use ptr;
|
||||||
|
|
||||||
|
let mut s = libc::timeval {
|
||||||
|
tv_sec: 0,
|
||||||
|
tv_usec: 0,
|
||||||
|
};
|
||||||
|
cvt(unsafe {
|
||||||
|
libc::gettimeofday(&mut s, ptr::null_mut())
|
||||||
|
}).unwrap();
|
||||||
|
return SystemTime::from(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
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<libc::timeval> for SystemTime {
|
||||||
|
fn from(t: libc::timeval) -> SystemTime {
|
||||||
|
SystemTime::from(libc::timespec {
|
||||||
|
tv_sec: t.tv_sec,
|
||||||
|
tv_nsec: (t.tv_usec * 1000) as libc::c_long,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<libc::timespec> for SystemTime {
|
||||||
|
fn from(t: libc::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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn dur2intervals(dur: &Duration) -> u64 {
|
||||||
|
let info = info();
|
||||||
|
let nanos = dur.as_secs().checked_mul(NSEC_PER_SEC).and_then(|nanos| {
|
||||||
|
nanos.checked_add(dur.subsec_nanos() as u64)
|
||||||
|
}).expect("overflow converting duration to nanoseconds");
|
||||||
|
mul_div_u64(nanos, info.denom as u64, info.numer as u64)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn info() -> &'static libc::mach_timebase_info {
|
||||||
|
static mut INFO: libc::mach_timebase_info = libc::mach_timebase_info {
|
||||||
|
numer: 0,
|
||||||
|
denom: 0,
|
||||||
|
};
|
||||||
|
static ONCE: Once = Once::new();
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
ONCE.call_once(|| {
|
||||||
|
libc::mach_timebase_info(&mut INFO);
|
||||||
|
});
|
||||||
|
&INFO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(any(target_os = "macos", target_os = "ios")))]
|
||||||
|
mod inner {
|
||||||
|
use fmt;
|
||||||
|
use libc;
|
||||||
|
use sys::cvt;
|
||||||
|
use time::Duration;
|
||||||
|
|
||||||
|
use super::Timespec;
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub struct Instant {
|
||||||
|
t: Timespec,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
|
pub struct SystemTime {
|
||||||
|
t: Timespec,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const UNIX_EPOCH: SystemTime = SystemTime {
|
||||||
|
t: Timespec {
|
||||||
|
t: libc::timespec {
|
||||||
|
tv_sec: 0,
|
||||||
|
tv_nsec: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
impl Instant {
|
||||||
|
pub fn now() -> Instant {
|
||||||
|
Instant { t: now(libc::CLOCK_MONOTONIC) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sub_instant(&self, other: &Instant) -> Duration {
|
||||||
|
self.t.sub_timespec(&other.t).unwrap_or_else(|_| {
|
||||||
|
panic!("other was less than the current instant")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
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(libc::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<libc::timespec> for SystemTime {
|
||||||
|
fn from(t: libc::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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(any(target_os = "dragonfly", target_os = "redox")))]
|
||||||
|
pub type clock_t = libc::c_int;
|
||||||
|
#[cfg(target_os = "dragonfly")]
|
||||||
|
pub type clock_t = libc::c_ulong;
|
||||||
|
#[cfg(target_os = "redox")]
|
||||||
|
pub type clock_t = usize;
|
||||||
|
|
||||||
|
fn now(clock: clock_t) -> Timespec {
|
||||||
|
let mut t = Timespec {
|
||||||
|
t: libc::timespec {
|
||||||
|
tv_sec: 0,
|
||||||
|
tv_nsec: 0,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
cvt(unsafe {
|
||||||
|
libc::clock_gettime(clock, &mut t.t)
|
||||||
|
}).unwrap();
|
||||||
|
t
|
||||||
|
}
|
||||||
|
}
|
|
@ -358,7 +358,7 @@ pub mod elf {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(target_os = "linux", target_os = "fuchsia"))]
|
#[cfg(any(target_os = "linux", target_os = "fuchsia", target_os = "redox"))]
|
||||||
unsafe fn register_dtor_fallback(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
|
unsafe fn register_dtor_fallback(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
|
||||||
// The fallback implementation uses a vanilla OS-based TLS key to track
|
// 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
|
// the list of destructors that need to be run for this thread. The key
|
||||||
|
@ -437,7 +437,7 @@ pub mod elf {
|
||||||
|
|
||||||
// Just use the thread_local fallback implementation, at least until there's
|
// Just use the thread_local fallback implementation, at least until there's
|
||||||
// a more direct implementation.
|
// a more direct implementation.
|
||||||
#[cfg(target_os = "fuchsia")]
|
#[cfg(any(target_os = "fuchsia", target_os = "redox"))]
|
||||||
unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
|
unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
|
||||||
register_dtor_fallback(t, dtor);
|
register_dtor_fallback(t, dtor);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue