From 8b09e01fef9912e7c3eef997c40f9f4f91d09e4c Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 27 Oct 2016 20:57:49 -0600 Subject: [PATCH 01/34] Add redox system --- src/libstd/lib.rs | 6 +- src/libstd/os/mod.rs | 3 + src/libstd/sys/common/mod.rs | 7 +- src/libstd/sys/common/util.rs | 6 + src/libstd/sys/redox/args.rs | 105 +++++ src/libstd/sys/redox/backtrace.rs | 8 + src/libstd/sys/redox/condvar.rs | 88 ++++ src/libstd/sys/redox/env.rs | 19 + src/libstd/sys/redox/ext/ffi.rs | 61 +++ src/libstd/sys/redox/ext/fs.rs | 300 +++++++++++++ src/libstd/sys/redox/ext/io.rs | 147 ++++++ src/libstd/sys/redox/ext/mod.rs | 50 +++ src/libstd/sys/redox/ext/process.rs | 183 ++++++++ src/libstd/sys/redox/fd.rs | 117 +++++ src/libstd/sys/redox/fs.rs | 554 +++++++++++++++++++++++ src/libstd/sys/redox/memchr.rs | 14 + src/libstd/sys/redox/mod.rs | 111 +++++ src/libstd/sys/redox/mutex.rs | 125 ++++++ src/libstd/sys/redox/net/dns/answer.rs | 12 + src/libstd/sys/redox/net/dns/mod.rs | 207 +++++++++ src/libstd/sys/redox/net/dns/query.rs | 8 + src/libstd/sys/redox/net/mod.rs | 91 ++++ src/libstd/sys/redox/net/tcp.rs | 160 +++++++ src/libstd/sys/redox/net/udp.rs | 163 +++++++ src/libstd/sys/redox/os.rs | 246 ++++++++++ src/libstd/sys/redox/os_str.rs | 119 +++++ src/libstd/sys/redox/path.rs | 29 ++ src/libstd/sys/redox/pipe.rs | 105 +++++ src/libstd/sys/redox/process.rs | 593 +++++++++++++++++++++++++ src/libstd/sys/redox/rand.rs | 40 ++ src/libstd/sys/redox/rwlock.rs | 55 +++ src/libstd/sys/redox/stack_overflow.rs | 27 ++ src/libstd/sys/redox/stdio.rs | 69 +++ src/libstd/sys/redox/thread.rs | 94 ++++ src/libstd/sys/redox/thread_local.rs | 41 ++ src/libstd/sys/redox/time.rs | 351 +++++++++++++++ src/libstd/thread/local.rs | 4 +- 37 files changed, 4313 insertions(+), 5 deletions(-) create mode 100644 src/libstd/sys/redox/args.rs create mode 100644 src/libstd/sys/redox/backtrace.rs create mode 100644 src/libstd/sys/redox/condvar.rs create mode 100644 src/libstd/sys/redox/env.rs create mode 100644 src/libstd/sys/redox/ext/ffi.rs create mode 100644 src/libstd/sys/redox/ext/fs.rs create mode 100644 src/libstd/sys/redox/ext/io.rs create mode 100644 src/libstd/sys/redox/ext/mod.rs create mode 100644 src/libstd/sys/redox/ext/process.rs create mode 100644 src/libstd/sys/redox/fd.rs create mode 100644 src/libstd/sys/redox/fs.rs create mode 100644 src/libstd/sys/redox/memchr.rs create mode 100644 src/libstd/sys/redox/mod.rs create mode 100644 src/libstd/sys/redox/mutex.rs create mode 100644 src/libstd/sys/redox/net/dns/answer.rs create mode 100644 src/libstd/sys/redox/net/dns/mod.rs create mode 100644 src/libstd/sys/redox/net/dns/query.rs create mode 100644 src/libstd/sys/redox/net/mod.rs create mode 100644 src/libstd/sys/redox/net/tcp.rs create mode 100644 src/libstd/sys/redox/net/udp.rs create mode 100644 src/libstd/sys/redox/os.rs create mode 100644 src/libstd/sys/redox/os_str.rs create mode 100644 src/libstd/sys/redox/path.rs create mode 100644 src/libstd/sys/redox/pipe.rs create mode 100644 src/libstd/sys/redox/process.rs create mode 100644 src/libstd/sys/redox/rand.rs create mode 100644 src/libstd/sys/redox/rwlock.rs create mode 100644 src/libstd/sys/redox/stack_overflow.rs create mode 100644 src/libstd/sys/redox/stdio.rs create mode 100644 src/libstd/sys/redox/thread.rs create mode 100644 src/libstd/sys/redox/thread_local.rs create mode 100644 src/libstd/sys/redox/time.rs diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 71e0ab0388f5b..bcd03d2856a70 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -316,13 +316,13 @@ extern crate rustc_unicode; extern crate libc; // We always need an unwinder currently for backtraces -extern crate unwind; +//REDOX TODO extern crate unwind; #[cfg(stage0)] extern crate alloc_system; // 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 #[cfg(test)] extern crate std as realstd; @@ -456,6 +456,8 @@ mod memchr; #[macro_use] #[path = "sys/common/mod.rs"] mod sys_common; +#[cfg(redox)] +#[path = "sys/redox/mod.rs"] mod sys; #[cfg(unix)] #[path = "sys/unix/mod.rs"] mod sys; #[cfg(windows)] diff --git a/src/libstd/os/mod.rs b/src/libstd/os/mod.rs index 366a167415684..744ee6c22e5bf 100644 --- a/src/libstd/os/mod.rs +++ b/src/libstd/os/mod.rs @@ -13,6 +13,9 @@ #![stable(feature = "os", since = "1.0.0")] #![allow(missing_docs, bad_style)] +#[cfg(redox)] +#[stable(feature = "rust1", since = "1.0.0")] +pub use sys::ext as unix; #[cfg(unix)] #[stable(feature = "rust1", since = "1.0.0")] pub use sys::ext as unix; diff --git a/src/libstd/sys/common/mod.rs b/src/libstd/sys/common/mod.rs index 2845f895f1869..274f3c10d9c35 100644 --- a/src/libstd/sys/common/mod.rs +++ b/src/libstd/sys/common/mod.rs @@ -32,7 +32,6 @@ pub mod condvar; pub mod io; pub mod memchr; pub mod mutex; -pub mod net; pub mod poison; pub mod remutex; pub mod rwlock; @@ -42,6 +41,12 @@ pub mod thread_local; pub mod util; pub mod wtf8; +#[cfg(redox)] +pub use sys::net; + +#[cfg(not(redox))] +pub mod net; + #[cfg(any(not(cargobuild), feature = "backtrace"))] #[cfg(any(all(unix, not(any(target_os = "macos", target_os = "ios", target_os = "emscripten"))), all(windows, target_env = "gnu")))] diff --git a/src/libstd/sys/common/util.rs b/src/libstd/sys/common/util.rs index b5d0357633875..dda0abb4c0cb2 100644 --- a/src/libstd/sys/common/util.rs +++ b/src/libstd/sys/common/util.rs @@ -33,6 +33,12 @@ pub fn dumb_print(args: fmt::Arguments) { 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 // including the SIGABRT handler, preventing the abort from being blocked, and // fclose streams, with the side effect of flushing them so libc bufferred diff --git a/src/libstd/sys/redox/args.rs b/src/libstd/sys/redox/args.rs new file mode 100644 index 0000000000000..9123364598948 --- /dev/null +++ b/src/libstd/sys/redox/args.rs @@ -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 or the MIT license +// , 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, + _dont_send_or_sync_me: PhantomData<*mut ()>, +} + +impl Iterator for Args { + type Item = OsString; + fn next(&mut self) -> Option { self.iter.next() } + fn size_hint(&self) -> (usize, Option) { 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 { 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 = bytes.into_iter().map(|v| { + OsStringExt::from_vec(v) + }).collect(); + Args { iter: v.into_iter(), _dont_send_or_sync_me: PhantomData } + } + + fn clone() -> Option>> { + 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>>> { + unsafe { mem::transmute(&GLOBAL_ARGS_PTR) } + } + +} diff --git a/src/libstd/sys/redox/backtrace.rs b/src/libstd/sys/redox/backtrace.rs new file mode 100644 index 0000000000000..63e427694ae6a --- /dev/null +++ b/src/libstd/sys/redox/backtrace.rs @@ -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) +} diff --git a/src/libstd/sys/redox/condvar.rs b/src/libstd/sys/redox/condvar.rs new file mode 100644 index 0000000000000..2a6685bc12245 --- /dev/null +++ b/src/libstd/sys/redox/condvar.rs @@ -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 +} + +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 {} diff --git a/src/libstd/sys/redox/env.rs b/src/libstd/sys/redox/env.rs new file mode 100644 index 0000000000000..51fd2d079738f --- /dev/null +++ b/src/libstd/sys/redox/env.rs @@ -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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub mod os { + pub const FAMILY: &'static str = "redox"; + pub const OS: &'static str = "redox"; + pub const DLL_PREFIX: &'static str = "lib"; + pub const DLL_SUFFIX: &'static str = ".so"; + pub const DLL_EXTENSION: &'static str = "so"; + pub const EXE_SUFFIX: &'static str = ""; + pub const EXE_EXTENSION: &'static str = ""; +} diff --git a/src/libstd/sys/redox/ext/ffi.rs b/src/libstd/sys/redox/ext/ffi.rs new file mode 100644 index 0000000000000..d59b4fc0b70b8 --- /dev/null +++ b/src/libstd/sys/redox/ext/ffi.rs @@ -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 or the MIT license +// , 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) -> Self; + + /// Yields the underlying byte vector of this `OsString`. + #[stable(feature = "rust1", since = "1.0.0")] + fn into_vec(self) -> Vec; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl OsStringExt for OsString { + fn from_vec(vec: Vec) -> OsString { + FromInner::from_inner(Buf { inner: vec }) + } + fn into_vec(self) -> Vec { + 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 + } +} diff --git a/src/libstd/sys/redox/ext/fs.rs b/src/libstd/sys/redox/ext/fs.rs new file mode 100644 index 0000000000000..45ad7c092de18 --- /dev/null +++ b/src/libstd/sys/redox/ext/fs.rs @@ -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 or the MIT license +// , 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, Q: AsRef>(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 + } +} diff --git a/src/libstd/sys/redox/ext/io.rs b/src/libstd/sys/redox/ext/io.rs new file mode 100644 index 0000000000000..bffd4f66a2803 --- /dev/null +++ b/src/libstd/sys/redox/ext/io.rs @@ -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 or the MIT license +// , 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() + } +} +*/ diff --git a/src/libstd/sys/redox/ext/mod.rs b/src/libstd/sys/redox/ext/mod.rs new file mode 100644 index 0000000000000..7ba166e89320f --- /dev/null +++ b/src/libstd/sys/redox/ext/mod.rs @@ -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 or the MIT license +// , 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}; +} diff --git a/src/libstd/sys/redox/ext/process.rs b/src/libstd/sys/redox/ext/process.rs new file mode 100644 index 0000000000000..f8e6b2cf4709d --- /dev/null +++ b/src/libstd/sys/redox/ext/process.rs @@ -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 or the MIT license +// , 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(&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(&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; +} + +#[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 { + self.as_inner().signal() + } +} + +#[stable(feature = "process_extensions", since = "1.2.0")] +impl FromRawFd for process::Stdio { + unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio { + let fd = sys::fd::FileDesc::new(fd); + let io = sys::process::Stdio::Fd(fd); + process::Stdio::from_inner(io) + } +} + +#[stable(feature = "process_extensions", since = "1.2.0")] +impl AsRawFd for process::ChildStdin { + fn as_raw_fd(&self) -> RawFd { + self.as_inner().fd().raw() + } +} + +#[stable(feature = "process_extensions", since = "1.2.0")] +impl AsRawFd for process::ChildStdout { + fn as_raw_fd(&self) -> RawFd { + self.as_inner().fd().raw() + } +} + +#[stable(feature = "process_extensions", since = "1.2.0")] +impl AsRawFd for process::ChildStderr { + fn as_raw_fd(&self) -> RawFd { + self.as_inner().fd().raw() + } +} + +#[stable(feature = "into_raw_os", since = "1.4.0")] +impl IntoRawFd for process::ChildStdin { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_fd().into_raw() + } +} + +#[stable(feature = "into_raw_os", since = "1.4.0")] +impl IntoRawFd for process::ChildStdout { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_fd().into_raw() + } +} + +#[stable(feature = "into_raw_os", since = "1.4.0")] +impl IntoRawFd for process::ChildStderr { + fn into_raw_fd(self) -> RawFd { + self.into_inner().into_fd().into_raw() + } +} diff --git a/src/libstd/sys/redox/fd.rs b/src/libstd/sys/redox/fd.rs new file mode 100644 index 0000000000000..99ae089b5c048 --- /dev/null +++ b/src/libstd/sys/redox/fd.rs @@ -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 or the MIT license +// , 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 { + 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) -> io::Result { + let mut me = self; + (&mut me).read_to_end(buf) + } + + pub fn write(&self, buf: &[u8]) -> io::Result { + 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 { + 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 { + (**self).read(buf) + } + + fn read_to_end(&mut self, buf: &mut Vec) -> io::Result { + unsafe { read_to_end_uninitialized(self, buf) } + } +} + +impl AsInner 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) }; + } +} diff --git a/src/libstd/sys/redox/fs.rs b/src/libstd/sys/redox/fs.rs new file mode 100644 index 0000000000000..56b1bf95ae813 --- /dev/null +++ b/src/libstd/sys/redox/fs.rs @@ -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 or the MIT license +// , 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, + i: usize, + root: Arc, +} + +struct Dir(FileDesc); + +unsafe impl Send for Dir {} +unsafe impl Sync for Dir {} + +pub struct DirEntry { + root: Arc, + 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 { + 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 { + 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 { + 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 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 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; + + fn next(&mut self) -> Option> { + 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 { + lstat(&self.path()) + } + + pub fn file_type(&self) -> io::Result { + 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 { + 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 { + 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 { + let path = cstr(path)?; + File::open_c(&path, opts) + } + + pub fn open_c(path: &CStr, opts: &OpenOptions) -> io::Result { + 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 { + 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 { + self.0.read(buf) + } + + pub fn read_to_end(&self, buf: &mut Vec) -> io::Result { + self.0.read_to_end(buf) + } + + pub fn write(&self, buf: &[u8]) -> io::Result { + self.0.write(buf) + } + + pub fn flush(&self) -> io::Result<()> { Ok(()) } + + pub fn seek(&self, pos: SeekFrom) -> io::Result { + 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 { + self.0.duplicate().map(File) + } + + pub fn dup(&self, buf: &[u8]) -> io::Result { + 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 { + 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 { + Ok(CString::new(path.as_os_str().as_bytes())?) +} + +impl FromInner 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 { + 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 { + // 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 { + // 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 { + 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 { + 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 { + 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 { + 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 { + unimplemented!(); +} + +pub fn copy(from: &Path, to: &Path) -> io::Result { + use fs::{File, set_permissions}; + if !from.is_file() { + return Err(Error::new(ErrorKind::InvalidInput, + "the source path is not an existing regular file")) + } + + let mut reader = File::open(from)?; + let mut writer = File::create(to)?; + let perm = reader.metadata()?.permissions(); + + let ret = io::copy(&mut reader, &mut writer)?; + set_permissions(to, perm)?; + Ok(ret) +} diff --git a/src/libstd/sys/redox/memchr.rs b/src/libstd/sys/redox/memchr.rs new file mode 100644 index 0000000000000..4c314b7a47258 --- /dev/null +++ b/src/libstd/sys/redox/memchr.rs @@ -0,0 +1,14 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , 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}; diff --git a/src/libstd/sys/redox/mod.rs b/src/libstd/sys/redox/mod.rs new file mode 100644 index 0000000000000..108ebb0800e4e --- /dev/null +++ b/src/libstd/sys/redox/mod.rs @@ -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: T) -> io::Result { + if t.is_minus_one() { + Err(io::Error::last_os_error()) + } else { + Ok(t) + } +} + +pub fn cvt_r(mut f: F) -> io::Result + where T: IsMinusOne, + F: FnMut() -> T +{ + loop { + match cvt(f()) { + Err(ref e) if e.kind() == ErrorKind::Interrupted => {} + other => return other, + } + } +} diff --git a/src/libstd/sys/redox/mutex.rs b/src/libstd/sys/redox/mutex.rs new file mode 100644 index 0000000000000..5723443785a0d --- /dev/null +++ b/src/libstd/sys/redox/mutex.rs @@ -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, +} + +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, +} + +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 {} diff --git a/src/libstd/sys/redox/net/dns/answer.rs b/src/libstd/sys/redox/net/dns/answer.rs new file mode 100644 index 0000000000000..c0450c11ed6b9 --- /dev/null +++ b/src/libstd/sys/redox/net/dns/answer.rs @@ -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 +} diff --git a/src/libstd/sys/redox/net/dns/mod.rs b/src/libstd/sys/redox/net/dns/mod.rs new file mode 100644 index 0000000000000..4397b71b93914 --- /dev/null +++ b/src/libstd/sys/redox/net/dns/mod.rs @@ -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 for n16 { + fn from(value: u16) -> Self { + n16 { + inner: value.to_be() + } + } +} + +#[unstable(feature = "n16", issue="0")] +impl From 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, + pub answers: Vec +} + +impl Dns { + pub fn compile(&self) -> Vec { + 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 { + 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, + }) + } +} diff --git a/src/libstd/sys/redox/net/dns/query.rs b/src/libstd/sys/redox/net/dns/query.rs new file mode 100644 index 0000000000000..dcb554d82debb --- /dev/null +++ b/src/libstd/sys/redox/net/dns/query.rs @@ -0,0 +1,8 @@ +use string::String; + +#[derive(Clone, Debug)] +pub struct DnsQuery { + pub name: String, + pub q_type: u16, + pub q_class: u16 +} diff --git a/src/libstd/sys/redox/net/mod.rs b/src/libstd/sys/redox/net/mod.rs new file mode 100644 index 0000000000000..1c8fde546efb4 --- /dev/null +++ b/src/libstd/sys/redox/net/mod.rs @@ -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); + +impl Iterator for LookupHost { + type Item = SocketAddr; + fn next(&mut self) -> Option { + self.0.next() + } +} + +pub fn lookup_host(host: &str) -> Result { + let mut ip_string = String::new(); + File::open("/etc/net/ip")?.read_to_string(&mut ip_string)?; + let ip: Vec = ip_string.trim().split(".").map(|part| part.parse::().unwrap_or(0)).collect(); + + let mut dns_string = String::new(); + File::open("/etc/net/dns")?.read_to_string(&mut dns_string)?; + let dns: Vec = dns_string.trim().split(".").map(|part| part.parse::().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::().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::().unwrap_or(0); + SocketAddr::V4(SocketAddrV4::new(host, port)) +} diff --git a/src/libstd/sys/redox/net/tcp.rs b/src/libstd/sys/redox/net/tcp.rs new file mode 100644 index 0000000000000..351c534c036df --- /dev/null +++ b/src/libstd/sys/redox/net/tcp.rs @@ -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 { + 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 { + Ok(TcpStream(self.0.dup(&[])?)) + } + + pub fn read(&self, buf: &mut [u8]) -> Result { + self.0.read(buf) + } + + pub fn read_to_end(&self, buf: &mut Vec) -> Result { + self.0.read_to_end(buf) + } + + pub fn write(&self, buf: &[u8]) -> Result { + self.0.write(buf) + } + + pub fn take_error(&self) -> Result> { + Ok(None) + } + + pub fn peer_addr(&self) -> Result { + let path = self.0.path()?; + Ok(path_to_peer_addr(path.to_str().unwrap_or(""))) + } + + pub fn socket_addr(&self) -> Result { + 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 { + Err(Error::new(ErrorKind::Other, "TcpStream::nodelay not implemented")) + } + + pub fn nonblocking(&self) -> Result { + Err(Error::new(ErrorKind::Other, "TcpStream::nonblocking not implemented")) + } + + pub fn only_v6(&self) -> Result { + Err(Error::new(ErrorKind::Other, "TcpStream::only_v6 not implemented")) + } + + pub fn ttl(&self) -> Result { + Err(Error::new(ErrorKind::Other, "TcpStream::ttl not implemented")) + } + + pub fn read_timeout(&self) -> Result> { + Err(Error::new(ErrorKind::Other, "TcpStream::read_timeout not implemented")) + } + + pub fn write_timeout(&self) -> Result> { + 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) -> Result<()> { + Err(Error::new(ErrorKind::Other, "TcpStream::set_read_timeout not implemented")) + } + + pub fn set_write_timeout(&self, _dur: Option) -> 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 { + 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 { + Ok(TcpListener(self.0.dup(&[])?)) + } + + pub fn take_error(&self) -> Result> { + Ok(None) + } + + pub fn socket_addr(&self) -> Result { + let path = self.0.path()?; + Ok(path_to_local_addr(path.to_str().unwrap_or(""))) + } + + pub fn nonblocking(&self) -> Result { + Err(Error::new(ErrorKind::Other, "TcpListener::nonblocking not implemented")) + } + + pub fn only_v6(&self) -> Result { + Err(Error::new(ErrorKind::Other, "TcpListener::only_v6 not implemented")) + } + + pub fn ttl(&self) -> Result { + 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")) + } +} diff --git a/src/libstd/sys/redox/net/udp.rs b/src/libstd/sys/redox/net/udp.rs new file mode 100644 index 0000000000000..a259db6a4c047 --- /dev/null +++ b/src/libstd/sys/redox/net/udp.rs @@ -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>); + +impl UdpSocket { + pub fn bind(addr: &SocketAddr) -> Result { + 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 { + unsafe { &mut *(self.1.get()) } + } + + pub fn connect(&self, addr: &SocketAddr) -> Result<()> { + unsafe { *self.1.get() = Some(*addr) }; + Ok(()) + } + + pub fn duplicate(&self) -> Result { + 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 { + 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 { + let to = self.0.dup(format!("{}", addr).as_bytes())?; + to.write(buf) + } + + pub fn send(&self, buf: &[u8]) -> Result { + 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> { + Ok(None) + } + + pub fn socket_addr(&self) -> Result { + let path = self.0.path()?; + Ok(path_to_local_addr(path.to_str().unwrap_or(""))) + } + + pub fn broadcast(&self) -> Result { + Err(Error::new(ErrorKind::Other, "UdpSocket::broadcast not implemented")) + } + + pub fn multicast_loop_v4(&self) -> Result { + Err(Error::new(ErrorKind::Other, "UdpSocket::multicast_loop_v4 not implemented")) + } + + pub fn multicast_loop_v6(&self) -> Result { + Err(Error::new(ErrorKind::Other, "UdpSocket::multicast_loop_v6 not implemented")) + } + + pub fn multicast_ttl_v4(&self) -> Result { + Err(Error::new(ErrorKind::Other, "UdpSocket::multicast_ttl_v4 not implemented")) + } + + pub fn nonblocking(&self) -> Result { + Err(Error::new(ErrorKind::Other, "UdpSocket::nonblocking not implemented")) + } + + pub fn only_v6(&self) -> Result { + Err(Error::new(ErrorKind::Other, "UdpSocket::only_v6 not implemented")) + } + + pub fn ttl(&self) -> Result { + Err(Error::new(ErrorKind::Other, "UdpSocket::ttl not implemented")) + } + + pub fn read_timeout(&self) -> Result> { + Err(Error::new(ErrorKind::Other, "UdpSocket::read_timeout not implemented")) + } + + pub fn write_timeout(&self) -> Result> { + 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) -> Result<()> { + Err(Error::new(ErrorKind::Other, "UdpSocket::set_read_timeout not implemented")) + } + + pub fn set_write_timeout(&self, _dur: Option) -> 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")) + } +} diff --git a/src/libstd/sys/redox/os.rs b/src/libstd/sys/redox/os.rs new file mode 100644 index 0000000000000..a2262369e9263 --- /dev/null +++ b/src/libstd/sys/redox/os.rs @@ -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 or the MIT license +// , 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 { + 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 bool>, + fn(&'a [u8]) -> PathBuf>, +} + +pub fn split_paths(unparsed: &OsStr) -> SplitPaths { + fn bytes_to_path(b: &[u8]) -> PathBuf { + PathBuf::from(::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 { self.iter.next() } + fn size_hint(&self) -> (usize, Option) { self.iter.size_hint() } +} + +#[derive(Debug)] +pub struct JoinPathsError; + +pub fn join_paths(paths: I) -> Result + where I: Iterator, T: AsRef +{ + 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 { + 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) { 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> { + 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 { + return ::env::var_os("HOME").map(PathBuf::from); +} + +pub fn exit(code: i32) -> ! { + unsafe { libc::exit(code as c_int) } +} diff --git a/src/libstd/sys/redox/os_str.rs b/src/libstd/sys/redox/os_str.rs new file mode 100644 index 0000000000000..5a733c0cb8763 --- /dev/null +++ b/src/libstd/sys/redox/os_str.rs @@ -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 or the MIT license +// , 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]`. + +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 +} + +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> for Buf { + fn into_inner(self) -> Vec { + 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::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 { + String::from_utf8_lossy(&self.inner) + } + + pub fn to_owned(&self) -> Buf { + Buf { inner: self.inner.to_vec() } + } +} diff --git a/src/libstd/sys/redox/path.rs b/src/libstd/sys/redox/path.rs new file mode 100644 index 0000000000000..bf9af7a4353a8 --- /dev/null +++ b/src/libstd/sys/redox/path.rs @@ -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 or the MIT license +// , 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 { + None +} + +pub const MAIN_SEP_STR: &'static str = "/"; +pub const MAIN_SEP: char = '/'; diff --git a/src/libstd/sys/redox/pipe.rs b/src/libstd/sys/redox/pipe.rs new file mode 100644 index 0000000000000..f77f1e0dc688f --- /dev/null +++ b/src/libstd/sys/redox/pipe.rs @@ -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 or the MIT license +// , 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 { + fd.set_cloexec()?; + Ok(AnonPipe(fd)) + } + + pub fn read(&self, buf: &mut [u8]) -> io::Result { + self.0.read(buf) + } + + pub fn read_to_end(&self, buf: &mut Vec) -> io::Result { + self.0.read_to_end(buf) + } + + pub fn write(&self, buf: &[u8]) -> io::Result { + 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, + _p2: AnonPipe, + _v2: &mut Vec) -> 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| { + match fd.read_to_end(dst) { + Ok(_) => Ok(true), + Err(e) => { + if e.raw_os_error() == Some(libc::EWOULDBLOCK) || + e.raw_os_error() == Some(libc::EAGAIN) { + Ok(false) + } else { + Err(e) + } + } + } + }; + if read(&p1, v1)? { + p2.set_nonblocking(false)?; + return p2.read_to_end(v2).map(|_| ()); + } + if read(&p2, v2)? { + p1.set_nonblocking(false)?; + return p1.read_to_end(v1).map(|_| ()); + } + } + */ +} diff --git a/src/libstd/sys/redox/process.rs b/src/libstd/sys/redox/process.rs new file mode 100644 index 0000000000000..b025623fc9f77 --- /dev/null +++ b/src/libstd/sys/redox/process.rs @@ -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 or the MIT license +// , 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, + env: HashMap, + + cwd: Option, + uid: Option, + gid: Option, + saw_nul: bool, + closures: Vec io::Result<()> + Send + Sync>>, + stdin: Option, + stdout: Option, + stderr: Option, +} + +// passed back to std::process with the pipes connected to the child, if any +// were requested +pub struct StdioPipes { + pub stdin: Option, + pub stdout: Option, + pub stderr: Option, +} + +// 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 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("").unwrap() + }) +} + +impl Stdio { + fn to_child_stdio(&self, readable: bool) + -> io::Result<(ChildStdio, Option)> { + 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 { + 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 { + if self.exited() { + Some(self.0) + } else { + None + } + } + + pub fn signal(&self) -> Option { + if !self.exited() { + Some(self.0) + } else { + None + } + } +} + +impl From 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, +} + +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 { + 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::()); + 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()); + } + } +} diff --git a/src/libstd/sys/redox/rand.rs b/src/libstd/sys/redox/rand.rs new file mode 100644 index 0000000000000..6ea9a3fb1057f --- /dev/null +++ b/src/libstd/sys/redox/rand.rs @@ -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 or the MIT license +// , 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, +} + +impl OsRng { + /// Create a new `OsRng`. + pub fn new() -> io::Result { + 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) + } +} diff --git a/src/libstd/sys/redox/rwlock.rs b/src/libstd/sys/redox/rwlock.rs new file mode 100644 index 0000000000000..c2de1d50685f2 --- /dev/null +++ b/src/libstd/sys/redox/rwlock.rs @@ -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 or the MIT license +// , 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) { + + } +} diff --git a/src/libstd/sys/redox/stack_overflow.rs b/src/libstd/sys/redox/stack_overflow.rs new file mode 100644 index 0000000000000..c8595d38b21c7 --- /dev/null +++ b/src/libstd/sys/redox/stack_overflow.rs @@ -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 or the MIT license +// , 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!(); +} diff --git a/src/libstd/sys/redox/stdio.rs b/src/libstd/sys/redox/stdio.rs new file mode 100644 index 0000000000000..0ed9de36c73dc --- /dev/null +++ b/src/libstd/sys/redox/stdio.rs @@ -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 or the MIT license +// , 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 { Ok(Stdin(())) } + + pub fn read(&self, data: &mut [u8]) -> io::Result { + 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) -> io::Result { + 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 { Ok(Stdout(())) } + + pub fn write(&self, data: &[u8]) -> io::Result { + let fd = FileDesc::new(libc::STDOUT_FILENO); + let ret = fd.write(data); + fd.into_raw(); + ret + } +} + +impl Stderr { + pub fn new() -> io::Result { Ok(Stderr(())) } + + pub fn write(&self, data: &[u8]) -> io::Result { + 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 { + Stderr::write(self, data) + } + fn flush(&mut self) -> io::Result<()> { Ok(()) } +} + +pub const EBADF_ERR: i32 = ::libc::EBADF; diff --git a/src/libstd/sys/redox/thread.rs b/src/libstd/sys/redox/thread.rs new file mode 100644 index 0000000000000..eaf908dc53ec4 --- /dev/null +++ b/src/libstd/sys/redox/thread.rs @@ -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 or the MIT license +// , 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) -> io::Result { + 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 { None } + pub unsafe fn init() -> Option { None } +} diff --git a/src/libstd/sys/redox/thread_local.rs b/src/libstd/sys/redox/thread_local.rs new file mode 100644 index 0000000000000..2639ef013dee3 --- /dev/null +++ b/src/libstd/sys/redox/thread_local.rs @@ -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 or the MIT license +// , 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) -> 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); +} diff --git a/src/libstd/sys/redox/time.rs b/src/libstd/sys/redox/time.rs new file mode 100644 index 0000000000000..5caaf20fdf80a --- /dev/null +++ b/src/libstd/sys/redox/time.rs @@ -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 or the MIT license +// , 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 { + 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 { + 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 { + 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 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 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 { + 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 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 + } +} diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index 54d3f7930456c..a1ae2c1cb423a 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -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)) { // 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 @@ -437,7 +437,7 @@ pub mod elf { // Just use the thread_local fallback implementation, at least until there's // 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)) { register_dtor_fallback(t, dtor); } From a5de9bb591c9752d39c87339fd8f5ff49ea4b2da Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 28 Oct 2016 14:17:34 -0600 Subject: [PATCH 02/34] Remove unsafe libc layer --- src/libstd/fs.rs | 10 ++ src/libstd/sys/redox/ext/io.rs | 3 +- src/libstd/sys/redox/fd.rs | 32 ++-- src/libstd/sys/redox/fs.rs | 186 +++++---------------- src/libstd/sys/redox/mod.rs | 39 +---- src/libstd/sys/redox/os.rs | 102 ++---------- src/libstd/sys/redox/pipe.rs | 6 +- src/libstd/sys/redox/process.rs | 137 ++++----------- src/libstd/sys/redox/thread.rs | 29 ++-- src/libstd/sys/redox/time.rs | 286 ++++++++------------------------ 10 files changed, 193 insertions(+), 637 deletions(-) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index df5741d00a2c1..5845963d31a10 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -348,6 +348,16 @@ impl File { inner: self.inner.duplicate()? }) } + + /// Get the path that this file points to. + /// + /// This function is only implemented on Redox, but could be + /// implemented on other operating systems using readlink + #[cfg(redox)] + #[stable(feature = "rust1", since = "1.14.0")] + pub fn path(&self) -> io::Result { + self.inner.path() + } } impl AsInner for File { diff --git a/src/libstd/sys/redox/ext/io.rs b/src/libstd/sys/redox/ext/io.rs index bffd4f66a2803..4f39f3b4f33f7 100644 --- a/src/libstd/sys/redox/ext/io.rs +++ b/src/libstd/sys/redox/ext/io.rs @@ -13,13 +13,12 @@ #![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; +pub type RawFd = usize; /// A trait to extract the raw unix file descriptor from an underlying /// object. diff --git a/src/libstd/sys/redox/fd.rs b/src/libstd/sys/redox/fd.rs index 99ae089b5c048..4c4dae7cd418b 100644 --- a/src/libstd/sys/redox/fd.rs +++ b/src/libstd/sys/redox/fd.rs @@ -11,37 +11,32 @@ #![unstable(reason = "not public", issue = "0", feature = "fd")] use io::{self, Read}; -use libc::{self, c_int, c_void}; +use libc; use mem; use sys::cvt; use sys_common::AsInner; use sys_common::io::read_to_end_uninitialized; pub struct FileDesc { - fd: c_int, + fd: usize, } impl FileDesc { - pub fn new(fd: c_int) -> FileDesc { + pub fn new(fd: usize) -> FileDesc { FileDesc { fd: fd } } - pub fn raw(&self) -> c_int { self.fd } + pub fn raw(&self) -> usize { self.fd } /// Extracts the actual filedescriptor without closing it. - pub fn into_raw(self) -> c_int { + pub fn into_raw(self) -> usize { let fd = self.fd; mem::forget(self); fd } pub fn read(&self, buf: &mut [u8]) -> io::Result { - let ret = cvt(unsafe { - libc::read(self.fd, - buf.as_mut_ptr() as *mut c_void, - buf.len()) - })?; - Ok(ret as usize) + cvt(libc::read(self.fd, buf)) } pub fn read_to_end(&self, buf: &mut Vec) -> io::Result { @@ -50,12 +45,7 @@ impl FileDesc { } pub fn write(&self, buf: &[u8]) -> io::Result { - let ret = cvt(unsafe { - libc::write(self.fd, - buf.as_ptr() as *const c_void, - buf.len()) - })?; - Ok(ret as usize) + cvt(libc::write(self.fd, buf)) } pub fn set_cloexec(&self) -> io::Result<()> { @@ -86,7 +76,7 @@ impl FileDesc { } pub fn duplicate(&self) -> io::Result { - let new_fd = cvt(unsafe { libc::dup(self.fd) })?; + let new_fd = cvt(libc::dup(self.fd, &[]))?; Ok(FileDesc::new(new_fd)) } } @@ -101,8 +91,8 @@ impl<'a> Read for &'a FileDesc { } } -impl AsInner for FileDesc { - fn as_inner(&self) -> &c_int { &self.fd } +impl AsInner for FileDesc { + fn as_inner(&self) -> &usize { &self.fd } } impl Drop for FileDesc { @@ -112,6 +102,6 @@ impl Drop for FileDesc { // 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) }; + let _ = libc::close(self.fd); } } diff --git a/src/libstd/sys/redox/fs.rs b/src/libstd/sys/redox/fs.rs index 56b1bf95ae813..ca1a7963f8e6e 100644 --- a/src/libstd/sys/redox/fs.rs +++ b/src/libstd/sys/redox/fs.rs @@ -10,26 +10,24 @@ use os::unix::prelude::*; -use ffi::{CString, CStr, OsString, OsStr}; +use ffi::{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::cvt; 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}; +use libc::{stat, fstat, fsync, ftruncate, lseek, open}; pub struct File(FileDesc); #[derive(Clone)] pub struct FileAttr { - stat: stat64, + stat: stat, } pub struct ReadDir { @@ -104,8 +102,8 @@ impl FileAttr { } } -impl AsInner for FileAttr { - fn as_inner(&self) -> &stat64 { &self.stat } +impl AsInner for FileAttr { + fn as_inner(&self) -> &stat { &self.stat } } impl FilePermissions { @@ -254,60 +252,32 @@ impl OpenOptions { impl File { pub fn open(path: &Path, opts: &OpenOptions) -> io::Result { - let path = cstr(path)?; - File::open_c(&path, opts) - } - - pub fn open_c(path: &CStr, opts: &OpenOptions) -> io::Result { - 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)) + let flags = libc::O_CLOEXEC | + opts.get_access_mode()? as usize | + opts.get_creation_mode()? as usize | + (opts.custom_flags as usize & !libc::O_ACCMODE); + let fd = cvt(open(path.to_str().unwrap(), flags | opts.mode as usize))?; + Ok(File(FileDesc::new(fd))) } pub fn file_attr(&self) -> io::Result { - let mut stat: stat64 = unsafe { mem::zeroed() }; - cvt(unsafe { - fstat64(self.0.raw(), &mut stat) - })?; + let mut stat: stat = stat::default(); + cvt(fstat(self.0.raw(), &mut stat))?; Ok(FileAttr { stat: stat }) } pub fn fsync(&self) -> io::Result<()> { - cvt_r(|| unsafe { libc::fsync(self.0.raw()) })?; + cvt(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) } + self.fsync() } 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(|_| ()); + cvt(ftruncate(self.0.raw(), size as usize))?; + Ok(()) } pub fn read(&self, buf: &mut [u8]) -> io::Result { @@ -332,7 +302,7 @@ impl File { 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)?; + let n = cvt(lseek(self.0.raw(), pos as isize, whence))?; Ok(n as u64) } @@ -341,9 +311,8 @@ impl File { } pub fn dup(&self, buf: &[u8]) -> io::Result { - 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)) + let fd = cvt(libc::dup(*self.fd().as_inner() as usize, buf))?; + Ok(File(FileDesc::new(fd))) } pub fn path(&self) -> io::Result { @@ -365,8 +334,7 @@ impl DirBuilder { } pub fn mkdir(&self, p: &Path) -> io::Result<()> { - let p = cstr(p)?; - cvt(unsafe { libc::mkdir(p.as_ptr(), self.mode) })?; + cvt(libc::mkdir(p.to_str().unwrap(), self.mode))?; Ok(()) } @@ -375,96 +343,39 @@ impl DirBuilder { } } -fn cstr(path: &Path) -> io::Result { - Ok(CString::new(path.as_os_str().as_bytes())?) -} - -impl FromInner for File { - fn from_inner(fd: c_int) -> File { +impl FromInner for File { + fn from_inner(fd: usize) -> File { File(FileDesc::new(fd)) } } impl fmt::Debug for File { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - #[cfg(target_os = "linux")] - fn get_path(fd: c_int) -> Option { - 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 { - // 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 { - // 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("fd", &self.0.raw()); + if let Ok(path) = self.path() { b.field("path", &path); } + /* if let Some((read, write)) = get_mode(fd) { b.field("read", &read).field("write", &write); } + */ b.finish() } } pub fn readdir(p: &Path) -> io::Result { 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 }) - } + let options = OpenOptions::new(); + let fd = File::open(p, &options)?; + 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()) })?; + cvt(libc::unlink(p.to_str().unwrap()))?; Ok(()) } @@ -477,8 +388,7 @@ pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> { } pub fn rmdir(p: &Path) -> io::Result<()> { - let p = cstr(p)?; - cvt(unsafe { libc::rmdir(p.as_ptr()) })?; + cvt(libc::rmdir(p.to_str().unwrap()))?; Ok(()) } @@ -503,8 +413,8 @@ fn remove_dir_all_recursive(path: &Path) -> io::Result<()> { rmdir(path) } -pub fn readlink(_p: &Path) -> io::Result { - unimplemented!(); +pub fn readlink(p: &Path) -> io::Result { + canonicalize(p) } pub fn symlink(_src: &Path, _dst: &Path) -> io::Result<()> { @@ -516,25 +426,21 @@ pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> { } pub fn stat(p: &Path) -> io::Result { - let p = cstr(p)?; - let mut stat: stat64 = unsafe { mem::zeroed() }; - cvt(unsafe { - stat64(p.as_ptr(), &mut stat as *mut _ as *mut _) - })?; + let mut stat: stat = stat::default(); + let options = OpenOptions::new(); + let file = File::open(p, &options)?; + cvt(fstat(file.0.raw(), &mut stat))?; Ok(FileAttr { stat: stat }) } pub fn lstat(p: &Path) -> io::Result { - 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 }) + stat(p) } -pub fn canonicalize(_p: &Path) -> io::Result { - unimplemented!(); +pub fn canonicalize(p: &Path) -> io::Result { + let options = OpenOptions::new(); + let file = File::open(p, &options)?; + file.path() } pub fn copy(from: &Path, to: &Path) -> io::Result { diff --git a/src/libstd/sys/redox/mod.rs b/src/libstd/sys/redox/mod.rs index 108ebb0800e4e..f7465d01fada3 100644 --- a/src/libstd/sys/redox/mod.rs +++ b/src/libstd/sys/redox/mod.rs @@ -41,9 +41,7 @@ pub fn init() { 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()); + let _ = libc::write(libc::STDERR_FILENO, msg.as_bytes()); intrinsics::abort(); } } @@ -75,37 +73,6 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind { } } -#[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: T) -> io::Result { - if t.is_minus_one() { - Err(io::Error::last_os_error()) - } else { - Ok(t) - } -} - -pub fn cvt_r(mut f: F) -> io::Result - where T: IsMinusOne, - F: FnMut() -> T -{ - loop { - match cvt(f()) { - Err(ref e) if e.kind() == ErrorKind::Interrupted => {} - other => return other, - } - } +pub fn cvt(result: Result) -> io::Result { + result.map_err(|err| io::Error::from_raw_os_error(err.errno as i32)) } diff --git a/src/libstd/sys/redox/os.rs b/src/libstd/sys/redox/os.rs index a2262369e9263..c2e419aeaaa5a 100644 --- a/src/libstd/sys/redox/os.rs +++ b/src/libstd/sys/redox/os.rs @@ -35,109 +35,28 @@ 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 + 0 } /// 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() + if let Some(string) = libc::STR_ERROR.get(errno as usize) { + string.to_string() + } else { + "unknown error".to_string() } } pub fn getcwd() -> io::Result { - 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); - } - } + let mut buf = [0; 4096]; + let count = cvt(libc::getcwd(&mut buf))?; + Ok(PathBuf::from(OsString::from_vec(buf[.. count].to_vec()))) } 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()), - } - } + cvt(libc::chdir(p.to_str().unwrap())).and(Ok(())) } pub struct SplitPaths<'a> { @@ -242,5 +161,6 @@ pub fn home_dir() -> Option { } pub fn exit(code: i32) -> ! { - unsafe { libc::exit(code as c_int) } + let _ = libc::exit(code as usize); + unreachable!(); } diff --git a/src/libstd/sys/redox/pipe.rs b/src/libstd/sys/redox/pipe.rs index f77f1e0dc688f..5902ba128e8d7 100644 --- a/src/libstd/sys/redox/pipe.rs +++ b/src/libstd/sys/redox/pipe.rs @@ -9,7 +9,7 @@ // except according to those terms. use io; -use libc::{self, c_int}; +use libc; use sys::fd::FileDesc; //////////////////////////////////////////////////////////////////////////////// @@ -23,8 +23,8 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { 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); + let fd0 = FileDesc::new(fds[0]); + let fd1 = FileDesc::new(fds[1]); Ok((AnonPipe::from_fd(fd0)?, AnonPipe::from_fd(fd1)?)) } diff --git a/src/libstd/sys/redox/process.rs b/src/libstd/sys/redox/process.rs index b025623fc9f77..921e3f056daba 100644 --- a/src/libstd/sys/redox/process.rs +++ b/src/libstd/sys/redox/process.rs @@ -12,14 +12,15 @@ use os::unix::prelude::*; use collections::hash_map::HashMap; use env; -use ffi::{OsStr, CString, CStr}; +use ffi::{OsStr, CString}; use fmt; use io::{self, Error, ErrorKind}; use libc::{self, pid_t, c_int, gid_t, uid_t}; +use path::Path; use sys::fd::FileDesc; use sys::fs::{File, OpenOptions}; use sys::pipe::{self, AnonPipe}; -use sys::{self, cvt, cvt_r}; +use sys::{self, cvt}; //////////////////////////////////////////////////////////////////////////////// // Command @@ -47,7 +48,7 @@ pub struct Command { args: Vec, env: HashMap, - cwd: Option, + cwd: Option, uid: Option, gid: Option, saw_nul: bool, @@ -75,7 +76,7 @@ struct ChildPipes { enum ChildStdio { Inherit, - Explicit(c_int), + Explicit(usize), Owned(FileDesc), } @@ -120,7 +121,7 @@ impl Command { } pub fn cwd(&mut self, dir: &OsStr) { - self.cwd = Some(os2c(dir, &mut self.saw_nul)); + self.cwd = Some(dir.to_str().unwrap().to_owned()); } pub fn uid(&mut self, id: uid_t) { self.uid = Some(id); @@ -157,7 +158,7 @@ impl Command { let (input, output) = sys::pipe::anon_pipe()?; let pid = unsafe { - match cvt(libc::fork() as isize)? { + match cvt(libc::clone(0))? { 0 => { drop(input); let err = self.do_exec(theirs); @@ -174,7 +175,8 @@ impl Command { // 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) + let _ = libc::exit(1); + unreachable!(); } n => n as pid_t, } @@ -271,29 +273,29 @@ impl Command { } if let Some(fd) = stdio.stderr.fd() { - libc::close(libc::STDERR_FILENO); - t!(cvt(libc::dup(fd))); - libc::close(fd); + let _ = libc::close(libc::STDERR_FILENO); + t!(cvt(libc::dup(fd, &[]))); + let _ = libc::close(fd); } if let Some(fd) = stdio.stdout.fd() { - libc::close(libc::STDOUT_FILENO); - t!(cvt(libc::dup(fd))); - libc::close(fd); + let _ = libc::close(libc::STDOUT_FILENO); + t!(cvt(libc::dup(fd, &[]))); + let _ = libc::close(fd); } if let Some(fd) = stdio.stdin.fd() { - libc::close(libc::STDIN_FILENO); - t!(cvt(libc::dup(fd))); - libc::close(fd); + let _ = libc::close(libc::STDIN_FILENO); + t!(cvt(libc::dup(fd, &[]))); + let _ = libc::close(fd); } - if let Some(u) = self.gid { - t!(cvt(libc::setgid(u as gid_t))); + if let Some(g) = self.gid { + t!(cvt(libc::setgid(g))); } if let Some(u) = self.uid { - t!(cvt(libc::setuid(u as uid_t))); + t!(cvt(libc::setuid(u))); } if let Some(ref cwd) = self.cwd { - t!(cvt(libc::chdir(cwd.as_ptr()))); + t!(cvt(libc::chdir(cwd))); } for callback in self.closures.iter_mut() { @@ -363,7 +365,7 @@ impl Stdio { // 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 { + if fd.raw() <= libc::STDERR_FILENO { Ok((ChildStdio::Owned(fd.duplicate()?), None)) } else { Ok((ChildStdio::Explicit(fd.raw()), None)) @@ -384,10 +386,7 @@ impl Stdio { 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)?; + let fd = File::open(&Path::new("null:"), &opts)?; Ok((ChildStdio::Owned(fd.into_fd()), None)) } } @@ -395,7 +394,7 @@ impl Stdio { } impl ChildStdio { - fn fd(&self) -> Option { + fn fd(&self) -> Option { match *self { ChildStdio::Inherit => None, ChildStdio::Explicit(fd) => Some(fd), @@ -496,7 +495,8 @@ impl Process { Err(Error::new(ErrorKind::InvalidInput, "invalid argument: can't kill an exited process")) } else { - cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(|_| ()) + cvt(libc::kill(self.pid, libc::SIGKILL))?; + Ok(()) } } @@ -505,89 +505,8 @@ impl Process { return Ok(status) } let mut status = 0; - cvt_r(|| unsafe { libc::waitpid(self.pid, &mut status, 0) })?; + cvt(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::()); - 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()); - } - } -} diff --git a/src/libstd/sys/redox/thread.rs b/src/libstd/sys/redox/thread.rs index eaf908dc53ec4..616da662d9ac1 100644 --- a/src/libstd/sys/redox/thread.rs +++ b/src/libstd/sys/redox/thread.rs @@ -14,7 +14,6 @@ use ffi::CStr; use io; use libc; use mem; -use sys::os; use sys_common::thread::start_thread; use time::Duration; @@ -42,7 +41,7 @@ impl Thread { } pub fn set_name(_name: &CStr) { - + unimplemented!(); } pub fn sleep(dur: Duration) { @@ -51,20 +50,18 @@ impl Thread { // 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; - } + while secs > 0 || nsecs > 0 { + let req = libc::timespec { + tv_sec: cmp::min(libc::time_t::max_value() as u64, secs) as libc::time_t, + tv_nsec: nsecs, + }; + secs -= req.tv_sec as u64; + let mut rem = libc::timespec::default(); + if libc::nanosleep(&req, &mut rem).is_err() { + secs += rem.tv_sec as u64; + nsecs = rem.tv_nsec; + } else { + nsecs = 0; } } } diff --git a/src/libstd/sys/redox/time.rs b/src/libstd/sys/redox/time.rs index 5caaf20fdf80a..4e1a82bcc9a09 100644 --- a/src/libstd/sys/redox/time.rs +++ b/src/libstd/sys/redox/time.rs @@ -9,11 +9,11 @@ // except according to those terms. use cmp::Ordering; +use fmt; use libc; +use sys::cvt; use time::Duration; -pub use self::inner::{Instant, SystemTime, UNIX_EPOCH}; - const NSEC_PER_SEC: u64 = 1_000_000_000; #[derive(Copy, Clone)] @@ -103,249 +103,97 @@ impl Ord for Timespec { } } -#[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 Instant { + t: Timespec, +} - #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] - pub struct SystemTime { - 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, - }, +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 Instant { + pub fn now() -> Instant { + Instant { t: now(libc::CLOCK_MONOTONIC) } } - 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 { - 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 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, - }) - } + 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") + }) } - impl From for SystemTime { - fn from(t: libc::timespec) -> SystemTime { - SystemTime { t: Timespec { t: t } } - } + pub fn add_duration(&self, other: &Duration) -> Instant { + Instant { t: self.t.add_duration(other) } } - 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 - } + pub fn sub_duration(&self, other: &Duration) -> Instant { + Instant { t: self.t.sub_duration(other) } } } -#[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, +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() } +} - #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] - pub struct SystemTime { - t: Timespec, +impl SystemTime { + pub fn now() -> SystemTime { + SystemTime { t: now(libc::CLOCK_REALTIME) } } - 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) } - } + pub fn sub_time(&self, other: &SystemTime) + -> Result { + self.t.sub_timespec(&other.t) } - 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() - } + pub fn add_duration(&self, other: &Duration) -> SystemTime { + SystemTime { t: self.t.add_duration(other) } } - impl SystemTime { - pub fn now() -> SystemTime { - SystemTime { t: now(libc::CLOCK_REALTIME) } - } - - pub fn sub_time(&self, other: &SystemTime) - -> Result { - 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) } - } + pub fn sub_duration(&self, other: &Duration) -> SystemTime { + SystemTime { t: self.t.sub_duration(other) } } +} - impl From for SystemTime { - fn from(t: libc::timespec) -> SystemTime { - SystemTime { t: Timespec { t: t } } - } +impl From 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() - } +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; +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 - } +fn now(clock: clock_t) -> Timespec { + let mut t = Timespec { + t: libc::timespec { + tv_sec: 0, + tv_nsec: 0, + } + }; + cvt(libc::clock_gettime(clock, &mut t.t)).unwrap(); + t } From 68fd7eebe255bd8bd2231db353a266c1bc1e911f Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 28 Oct 2016 15:12:30 -0600 Subject: [PATCH 03/34] Can import unwind now --- src/libstd/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index bcd03d2856a70..219f244be29cc 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -316,7 +316,7 @@ extern crate rustc_unicode; extern crate libc; // We always need an unwinder currently for backtraces -//REDOX TODO extern crate unwind; +extern crate unwind; #[cfg(stage0)] extern crate alloc_system; From b1b35dd1f20b011cb6807ee56c5829753351b977 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 29 Oct 2016 21:15:32 -0600 Subject: [PATCH 04/34] Implement env, reentrant mutex, and partially implement scoped thread locals. Better error messages for unsupported features --- src/libstd/sys/redox/condvar.rs | 16 +++++- src/libstd/sys/redox/fd.rs | 2 + src/libstd/sys/redox/fs.rs | 4 ++ src/libstd/sys/redox/mutex.rs | 69 ++++++++++++++++++++++---- src/libstd/sys/redox/os.rs | 45 ++++++++++++++--- src/libstd/sys/redox/pipe.rs | 1 + src/libstd/sys/redox/rwlock.rs | 24 +++++---- src/libstd/sys/redox/stack_overflow.rs | 4 +- src/libstd/sys/redox/thread.rs | 10 ++-- src/libstd/sys/redox/thread_local.rs | 48 ++++++++++++------ 10 files changed, 174 insertions(+), 49 deletions(-) diff --git a/src/libstd/sys/redox/condvar.rs b/src/libstd/sys/redox/condvar.rs index 2a6685bc12245..b5234be567dd5 100644 --- a/src/libstd/sys/redox/condvar.rs +++ b/src/libstd/sys/redox/condvar.rs @@ -20,11 +20,15 @@ impl Condvar { } } + #[inline] pub unsafe fn init(&self) { - + *self.lock.get() = ptr::null_mut(); + *self.seq.get() = 0; } + #[inline] pub fn notify_one(&self) { + ::sys_common::util::dumb_print(format_args!("condvar notify_one\n")); unsafe { let seq = self.seq.get(); @@ -34,7 +38,9 @@ impl Condvar { } } + #[inline] pub fn notify_all(&self) { + ::sys_common::util::dumb_print(format_args!("condvar notify_all\n")); unsafe { let lock = self.lock.get(); let seq = self.seq.get(); @@ -49,7 +55,9 @@ impl Condvar { } } + #[inline] pub fn wait(&self, mutex: &Mutex) { + ::sys_common::util::dumb_print(format_args!("condvar wait\n")); unsafe { let lock = self.lock.get(); let seq = self.seq.get(); @@ -74,12 +82,16 @@ impl Condvar { } } + #[inline] pub fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool { + ::sys_common::util::dumb_print(format_args!("condvar wait_timeout\n")); unimplemented!(); } + #[inline] pub unsafe fn destroy(&self) { - + *self.lock.get() = ptr::null_mut(); + *self.seq.get() = 0; } } diff --git a/src/libstd/sys/redox/fd.rs b/src/libstd/sys/redox/fd.rs index 4c4dae7cd418b..4a3c0fdb37e96 100644 --- a/src/libstd/sys/redox/fd.rs +++ b/src/libstd/sys/redox/fd.rs @@ -49,6 +49,7 @@ impl FileDesc { } pub fn set_cloexec(&self) -> io::Result<()> { + ::sys_common::util::dumb_print(format_args!("Set cloexec\n")); unimplemented!(); /* unsafe { @@ -60,6 +61,7 @@ impl FileDesc { } pub fn set_nonblocking(&self, _nonblocking: bool) -> io::Result<()> { + ::sys_common::util::dumb_print(format_args!("Set nonblocking\n")); unimplemented!(); /* unsafe { diff --git a/src/libstd/sys/redox/fs.rs b/src/libstd/sys/redox/fs.rs index ca1a7963f8e6e..3779c4c66775e 100644 --- a/src/libstd/sys/redox/fs.rs +++ b/src/libstd/sys/redox/fs.rs @@ -380,10 +380,12 @@ pub fn unlink(p: &Path) -> io::Result<()> { } pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> { + ::sys_common::util::dumb_print(format_args!("Rename\n")); unimplemented!(); } pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> { + ::sys_common::util::dumb_print(format_args!("Set perm\n")); unimplemented!(); } @@ -418,10 +420,12 @@ pub fn readlink(p: &Path) -> io::Result { } pub fn symlink(_src: &Path, _dst: &Path) -> io::Result<()> { + ::sys_common::util::dumb_print(format_args!("Symlink\n")); unimplemented!(); } pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> { + ::sys_common::util::dumb_print(format_args!("Link\n")); unimplemented!(); } diff --git a/src/libstd/sys/redox/mutex.rs b/src/libstd/sys/redox/mutex.rs index 5723443785a0d..aa808c2f8d45b 100644 --- a/src/libstd/sys/redox/mutex.rs +++ b/src/libstd/sys/redox/mutex.rs @@ -2,7 +2,7 @@ use cell::UnsafeCell; use intrinsics::{atomic_cxchg, atomic_xchg}; use ptr; -use libc::{futex, FUTEX_WAIT, FUTEX_WAKE}; +use libc::{futex, getpid, FUTEX_WAIT, FUTEX_WAKE}; pub unsafe fn mutex_try_lock(m: *mut i32) -> bool { atomic_cxchg(m, 0, 1).0 == 0 @@ -57,27 +57,36 @@ impl Mutex { } } + #[inline] pub unsafe fn init(&self) { - + *self.lock.get() = 0; } /// Try to lock the mutex + #[inline] pub unsafe fn try_lock(&self) -> bool { + ::sys_common::util::dumb_print(format_args!("mutex try lock\n")); mutex_try_lock(self.lock.get()) } /// Lock the mutex + #[inline] pub unsafe fn lock(&self) { - mutex_lock(self.lock.get()); + ::sys_common::util::dumb_print(format_args!("mutex lock\n")); + mutex_try_lock(self.lock.get()); + //mutex_lock(self.lock.get()); } /// Unlock the mutex + #[inline] pub unsafe fn unlock(&self) { + ::sys_common::util::dumb_print(format_args!("mutex unlock\n")); mutex_unlock(self.lock.get()); } + #[inline] pub unsafe fn destroy(&self) { - + *self.lock.get() = 0; } } @@ -87,36 +96,78 @@ unsafe impl Sync for Mutex {} pub struct ReentrantMutex { pub lock: UnsafeCell, + pub owner: UnsafeCell, + pub own_count: UnsafeCell, } impl ReentrantMutex { pub const fn uninitialized() -> Self { ReentrantMutex { lock: UnsafeCell::new(0), + owner: UnsafeCell::new(0), + own_count: UnsafeCell::new(0), } } + #[inline] pub unsafe fn init(&mut self) { - + *self.lock.get() = 0; + *self.owner.get() = 0; + *self.own_count.get() = 0; } /// Try to lock the mutex + #[inline] pub unsafe fn try_lock(&self) -> bool { - mutex_try_lock(self.lock.get()) + ::sys_common::util::dumb_print(format_args!("remutex try_lock\n")); + let pid = getpid().unwrap(); + if *self.own_count.get() > 0 && *self.owner.get() == pid { + *self.own_count.get() += 1; + true + } else { + if mutex_try_lock(self.lock.get()) { + *self.owner.get() = pid; + *self.own_count.get() = 1; + true + } else { + false + } + } } /// Lock the mutex + #[inline] pub unsafe fn lock(&self) { - mutex_lock(self.lock.get()); + ::sys_common::util::dumb_print(format_args!("remutex lock\n")); + let pid = getpid().unwrap(); + if *self.own_count.get() > 0 && *self.owner.get() == pid { + *self.own_count.get() += 1; + } else { + mutex_lock(self.lock.get()); + *self.owner.get() = pid; + *self.own_count.get() = 1; + } } /// Unlock the mutex + #[inline] pub unsafe fn unlock(&self) { - mutex_unlock(self.lock.get()); + ::sys_common::util::dumb_print(format_args!("remutex unlock\n")); + let pid = getpid().unwrap(); + if *self.own_count.get() > 0 && *self.owner.get() == pid { + *self.own_count.get() -= 1; + if *self.own_count.get() == 0 { + *self.owner.get() = 0; + mutex_unlock(self.lock.get()); + } + } } + #[inline] pub unsafe fn destroy(&self) { - + *self.lock.get() = 0; + *self.owner.get() = 0; + *self.own_count.get() = 0; } } diff --git a/src/libstd/sys/redox/os.rs b/src/libstd/sys/redox/os.rs index c2e419aeaaa5a..9524f2c28f9da 100644 --- a/src/libstd/sys/redox/os.rs +++ b/src/libstd/sys/redox/os.rs @@ -17,7 +17,7 @@ use os::unix::prelude::*; use error::Error as StdError; use ffi::{CString, CStr, OsString, OsStr}; use fmt; -use io; +use io::{self, Read, Write}; use iter; use libc::{self, c_int, c_char, c_void}; use marker::PhantomData; @@ -131,19 +131,48 @@ impl Iterator for Env { /// Returns a vector of (variable, value) byte-vector pairs for all the /// environment variables of the current process. pub fn env() -> Env { - unimplemented!(); + let mut variables: Vec<(OsString, OsString)> = Vec::new(); + if let Ok(mut file) = ::fs::File::open("env:") { + let mut string = String::new(); + if file.read_to_string(&mut string).is_ok() { + for line in string.lines() { + if let Some(equal_sign) = line.chars().position(|c| c == '=') { + let name = line.chars().take(equal_sign).collect::(); + let value = line.chars().skip(equal_sign+1).collect::(); + variables.push((OsString::from(name), OsString::from(value))); + } + } + } + } + Env { iter: variables.into_iter(), _dont_send_or_sync_me: PhantomData } } -pub fn getenv(_k: &OsStr) -> io::Result> { - unimplemented!(); +pub fn getenv(key: &OsStr) -> io::Result> { + if ! key.is_empty() { + if let Ok(mut file) = ::fs::File::open(&("env:".to_owned() + key.to_str().unwrap())) { + let mut string = String::new(); + file.read_to_string(&mut string)?; + Ok(Some(OsString::from(string))) + } else { + Ok(None) + } + } else { + Ok(None) + } } -pub fn setenv(_k: &OsStr, _v: &OsStr) -> io::Result<()> { - unimplemented!(); +pub fn setenv(key: &OsStr, value: &OsStr) -> io::Result<()> { + if ! key.is_empty() { + let mut file = ::fs::File::open(&("env:".to_owned() + key.to_str().unwrap()))?; + file.write_all(value.as_bytes())?; + file.set_len(value.len() as u64)?; + } + Ok(()) } -pub fn unsetenv(_n: &OsStr) -> io::Result<()> { - unimplemented!(); +pub fn unsetenv(key: &OsStr) -> io::Result<()> { + ::fs::remove_file(&("env:".to_owned() + key.to_str().unwrap()))?; + Ok(()) } pub fn page_size() -> usize { diff --git a/src/libstd/sys/redox/pipe.rs b/src/libstd/sys/redox/pipe.rs index 5902ba128e8d7..a25ca04894272 100644 --- a/src/libstd/sys/redox/pipe.rs +++ b/src/libstd/sys/redox/pipe.rs @@ -54,6 +54,7 @@ pub fn read2(_p1: AnonPipe, _v1: &mut Vec, _p2: AnonPipe, _v2: &mut Vec) -> io::Result<()> { + ::sys_common::util::dumb_print(format_args!("read2\n")); unimplemented!(); /* // Set both pipes into nonblocking mode as we're gonna be reading from both diff --git a/src/libstd/sys/redox/rwlock.rs b/src/libstd/sys/redox/rwlock.rs index c2de1d50685f2..c752fa50ea9dd 100644 --- a/src/libstd/sys/redox/rwlock.rs +++ b/src/libstd/sys/redox/rwlock.rs @@ -8,48 +8,54 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub struct RWLock; +use super::mutex::Mutex; + +pub struct RWLock { + mutex: Mutex +} unsafe impl Send for RWLock {} unsafe impl Sync for RWLock {} impl RWLock { pub const fn new() -> RWLock { - RWLock + RWLock { + mutex: Mutex::new() + } } #[inline] pub unsafe fn read(&self) { - unimplemented!(); + self.mutex.lock(); } #[inline] pub unsafe fn try_read(&self) -> bool { - unimplemented!(); + self.mutex.try_lock() } #[inline] pub unsafe fn write(&self) { - unimplemented!(); + self.mutex.lock(); } #[inline] pub unsafe fn try_write(&self) -> bool { - unimplemented!(); + self.mutex.try_lock() } #[inline] pub unsafe fn read_unlock(&self) { - unimplemented!(); + self.mutex.unlock(); } #[inline] pub unsafe fn write_unlock(&self) { - unimplemented!(); + self.mutex.unlock(); } #[inline] pub unsafe fn destroy(&self) { - + self.mutex.destroy(); } } diff --git a/src/libstd/sys/redox/stack_overflow.rs b/src/libstd/sys/redox/stack_overflow.rs index c8595d38b21c7..92846bfe0c8d1 100644 --- a/src/libstd/sys/redox/stack_overflow.rs +++ b/src/libstd/sys/redox/stack_overflow.rs @@ -14,7 +14,7 @@ pub struct Handler; impl Handler { pub unsafe fn new() -> Handler { - unimplemented!(); + Handler } } @@ -23,5 +23,5 @@ pub unsafe fn init() { } pub unsafe fn cleanup() { - unimplemented!(); + } diff --git a/src/libstd/sys/redox/thread.rs b/src/libstd/sys/redox/thread.rs index 616da662d9ac1..b6685f14ec724 100644 --- a/src/libstd/sys/redox/thread.rs +++ b/src/libstd/sys/redox/thread.rs @@ -32,6 +32,8 @@ impl Thread { start_thread(&*p as *const _ as *mut _); + ::sys_common::util::dumb_print(format_args!("thread\n")); + unimplemented!(); } @@ -41,7 +43,7 @@ impl Thread { } pub fn set_name(_name: &CStr) { - unimplemented!(); + } pub fn sleep(dur: Duration) { @@ -67,7 +69,8 @@ impl Thread { } pub fn join(self) { - panic!(); + ::sys_common::util::dumb_print(format_args!("Thread::join")); + unimplemented!(); } pub fn id(&self) -> libc::pid_t { self.id } @@ -81,7 +84,8 @@ impl Thread { impl Drop for Thread { fn drop(&mut self) { - panic!(); + ::sys_common::util::dumb_print(format_args!("Thread::drop")); + unimplemented!(); } } diff --git a/src/libstd/sys/redox/thread_local.rs b/src/libstd/sys/redox/thread_local.rs index 2639ef013dee3..b12ffebbcac1d 100644 --- a/src/libstd/sys/redox/thread_local.rs +++ b/src/libstd/sys/redox/thread_local.rs @@ -10,32 +10,48 @@ #![allow(dead_code)] // not used on all platforms +use collections::BTreeMap; +use ptr; + pub type Key = usize; +type Dtor = unsafe extern fn(*mut u8); + +//TODO: Implement this properly + +static mut NEXT_KEY: Key = 0; + +static mut LOCALS: *mut BTreeMap)> = ptr::null_mut(); + +unsafe fn locals() -> &'static mut BTreeMap)> { + if LOCALS == ptr::null_mut() { + LOCALS = Box::into_raw(Box::new(BTreeMap::new())); + } + &mut *LOCALS +} + #[inline] -pub unsafe fn create(_dtor: Option) -> Key { - panic!("pthread key create not supported"); - //let mut key = 0; - //assert_eq!(libc::pthread_key_create(&mut key, mem::transmute(dtor)), 0); - //key +pub unsafe fn create(dtor: Option) -> Key { + let key = NEXT_KEY; + NEXT_KEY += 1; + locals().insert(key, (0 as *mut u8, dtor)); + 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); +pub unsafe fn set(key: Key, value: *mut u8) { + locals().get_mut(&key).unwrap().0 = value; } #[inline] -pub unsafe fn get(_key: Key) -> *mut u8 { - panic!("pthread key get not supported"); - //libc::pthread_getspecific(key) as *mut u8 +pub unsafe fn get(key: Key) -> *mut u8 { + locals()[&key].0 } #[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); +pub unsafe fn destroy(key: Key) { + let (value, dtor) = locals().remove(&key).unwrap(); + if let Some(dtor_fn) = dtor { + dtor_fn(value); + } } From ea6f5aa1b19655035475c7155441f658eeccdc5a Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sat, 29 Oct 2016 21:46:49 -0600 Subject: [PATCH 05/34] Implement rand and args, cleanup other modules --- src/libstd/sys/redox/args.rs | 14 +++++++++----- src/libstd/sys/redox/condvar.rs | 3 --- src/libstd/sys/redox/fd.rs | 26 ++++---------------------- src/libstd/sys/redox/mutex.rs | 9 +-------- src/libstd/sys/redox/os.rs | 2 +- src/libstd/sys/redox/process.rs | 23 +---------------------- src/libstd/sys/redox/rand.rs | 26 +++++++++++++------------- 7 files changed, 29 insertions(+), 74 deletions(-) diff --git a/src/libstd/sys/redox/args.rs b/src/libstd/sys/redox/args.rs index 9123364598948..52ba030e7c640 100644 --- a/src/libstd/sys/redox/args.rs +++ b/src/libstd/sys/redox/args.rs @@ -52,9 +52,10 @@ impl DoubleEndedIterator for Args { mod imp { use os::unix::prelude::*; use mem; - use ffi::{CStr, OsString}; + use ffi::OsString; use marker::PhantomData; - use libc; + use slice; + use str; use super::Args; use sys_common::mutex::Mutex; @@ -63,9 +64,12 @@ mod imp { 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(); + let mut args: Vec> = Vec::new(); + for i in 0..argc { + let len = *(argv.offset(i * 2)) as usize; + let ptr = *(argv.offset(i * 2 + 1)); + args.push(slice::from_raw_parts(ptr, len).to_vec()); + } LOCK.lock(); let ptr = get_global_ptr(); diff --git a/src/libstd/sys/redox/condvar.rs b/src/libstd/sys/redox/condvar.rs index b5234be567dd5..f6c8fec545b97 100644 --- a/src/libstd/sys/redox/condvar.rs +++ b/src/libstd/sys/redox/condvar.rs @@ -28,7 +28,6 @@ impl Condvar { #[inline] pub fn notify_one(&self) { - ::sys_common::util::dumb_print(format_args!("condvar notify_one\n")); unsafe { let seq = self.seq.get(); @@ -40,7 +39,6 @@ impl Condvar { #[inline] pub fn notify_all(&self) { - ::sys_common::util::dumb_print(format_args!("condvar notify_all\n")); unsafe { let lock = self.lock.get(); let seq = self.seq.get(); @@ -57,7 +55,6 @@ impl Condvar { #[inline] pub fn wait(&self, mutex: &Mutex) { - ::sys_common::util::dumb_print(format_args!("condvar wait\n")); unsafe { let lock = self.lock.get(); let seq = self.seq.get(); diff --git a/src/libstd/sys/redox/fd.rs b/src/libstd/sys/redox/fd.rs index 4a3c0fdb37e96..9c50c547965a8 100644 --- a/src/libstd/sys/redox/fd.rs +++ b/src/libstd/sys/redox/fd.rs @@ -49,32 +49,14 @@ impl FileDesc { } pub fn set_cloexec(&self) -> io::Result<()> { - ::sys_common::util::dumb_print(format_args!("Set cloexec\n")); - 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(()) - } - */ + ::sys_common::util::dumb_print(format_args!("{}: set cloexec\n", self.fd)); + //unimplemented!(); + Ok(()) } pub fn set_nonblocking(&self, _nonblocking: bool) -> io::Result<()> { - ::sys_common::util::dumb_print(format_args!("Set nonblocking\n")); + ::sys_common::util::dumb_print(format_args!("{}: set nonblocking\n", self.fd)); 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 { diff --git a/src/libstd/sys/redox/mutex.rs b/src/libstd/sys/redox/mutex.rs index aa808c2f8d45b..4c2b0de8bd94b 100644 --- a/src/libstd/sys/redox/mutex.rs +++ b/src/libstd/sys/redox/mutex.rs @@ -65,22 +65,18 @@ impl Mutex { /// Try to lock the mutex #[inline] pub unsafe fn try_lock(&self) -> bool { - ::sys_common::util::dumb_print(format_args!("mutex try lock\n")); mutex_try_lock(self.lock.get()) } /// Lock the mutex #[inline] pub unsafe fn lock(&self) { - ::sys_common::util::dumb_print(format_args!("mutex lock\n")); - mutex_try_lock(self.lock.get()); - //mutex_lock(self.lock.get()); + mutex_lock(self.lock.get()); } /// Unlock the mutex #[inline] pub unsafe fn unlock(&self) { - ::sys_common::util::dumb_print(format_args!("mutex unlock\n")); mutex_unlock(self.lock.get()); } @@ -119,7 +115,6 @@ impl ReentrantMutex { /// Try to lock the mutex #[inline] pub unsafe fn try_lock(&self) -> bool { - ::sys_common::util::dumb_print(format_args!("remutex try_lock\n")); let pid = getpid().unwrap(); if *self.own_count.get() > 0 && *self.owner.get() == pid { *self.own_count.get() += 1; @@ -138,7 +133,6 @@ impl ReentrantMutex { /// Lock the mutex #[inline] pub unsafe fn lock(&self) { - ::sys_common::util::dumb_print(format_args!("remutex lock\n")); let pid = getpid().unwrap(); if *self.own_count.get() > 0 && *self.owner.get() == pid { *self.own_count.get() += 1; @@ -152,7 +146,6 @@ impl ReentrantMutex { /// Unlock the mutex #[inline] pub unsafe fn unlock(&self) { - ::sys_common::util::dumb_print(format_args!("remutex unlock\n")); let pid = getpid().unwrap(); if *self.own_count.get() > 0 && *self.owner.get() == pid { *self.own_count.get() -= 1; diff --git a/src/libstd/sys/redox/os.rs b/src/libstd/sys/redox/os.rs index 9524f2c28f9da..309201352c404 100644 --- a/src/libstd/sys/redox/os.rs +++ b/src/libstd/sys/redox/os.rs @@ -15,7 +15,7 @@ use os::unix::prelude::*; use error::Error as StdError; -use ffi::{CString, CStr, OsString, OsStr}; +use ffi::{OsString, OsStr}; use fmt; use io::{self, Read, Write}; use iter; diff --git a/src/libstd/sys/redox/process.rs b/src/libstd/sys/redox/process.rs index 921e3f056daba..b6968f285d7aa 100644 --- a/src/libstd/sys/redox/process.rs +++ b/src/libstd/sys/redox/process.rs @@ -8,11 +8,9 @@ // 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}; +use ffi::OsStr; use fmt; use io::{self, Error, ErrorKind}; use libc::{self, pid_t, c_int, gid_t, uid_t}; @@ -344,13 +342,6 @@ impl Command { } } -fn os2c(s: &OsStr, saw_nul: &mut bool) -> CString { - CString::new(s.as_bytes()).unwrap_or_else(|_e| { - *saw_nul = true; - CString::new("").unwrap() - }) -} - impl Stdio { fn to_child_stdio(&self, readable: bool) -> io::Result<(ChildStdio, Option)> { @@ -403,18 +394,6 @@ impl ChildStdio { } } -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)?; diff --git a/src/libstd/sys/redox/rand.rs b/src/libstd/sys/redox/rand.rs index 6ea9a3fb1057f..7d2df6bf95769 100644 --- a/src/libstd/sys/redox/rand.rs +++ b/src/libstd/sys/redox/rand.rs @@ -8,33 +8,33 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use fs::File; use io; +use libc; use rand::Rng; -use rand::reader::ReaderRng; -pub struct OsRng { - inner: ReaderRng, -} +pub struct OsRng; impl OsRng { /// Create a new `OsRng`. pub fn new() -> io::Result { - let reader = File::open("rand:")?; - let reader_rng = ReaderRng::new(reader); - - Ok(OsRng { inner: reader_rng }) + Ok(OsRng) } } impl Rng for OsRng { fn next_u32(&mut self) -> u32 { - self.inner.next_u32() + self.next_u64() as u32 } fn next_u64(&mut self) -> u64 { - self.inner.next_u64() + unsafe { libc::random() } } - fn fill_bytes(&mut self, v: &mut [u8]) { - self.inner.fill_bytes(v) + fn fill_bytes(&mut self, buf: &mut [u8]) { + for chunk in buf.chunks_mut(8) { + let mut rand: u64 = self.next_u64(); + for b in chunk.iter_mut() { + *b = rand as u8; + rand = rand >> 8; + } + } } } From 37bfef023dab045852ea577dbe40693147a810f5 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 30 Oct 2016 09:36:04 -0600 Subject: [PATCH 06/34] Implement thread --- src/libstd/sys/redox/thread.rs | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/libstd/sys/redox/thread.rs b/src/libstd/sys/redox/thread.rs index b6685f14ec724..46bc6346a6a80 100644 --- a/src/libstd/sys/redox/thread.rs +++ b/src/libstd/sys/redox/thread.rs @@ -15,6 +15,7 @@ use io; use libc; use mem; use sys_common::thread::start_thread; +use sys::cvt; use time::Duration; pub struct Thread { @@ -30,11 +31,15 @@ impl Thread { pub unsafe fn new<'a>(_stack: usize, p: Box) -> io::Result { let p = box p; - start_thread(&*p as *const _ as *mut _); - - ::sys_common::util::dumb_print(format_args!("thread\n")); - - unimplemented!(); + let id = cvt(libc::clone(libc::CLONE_VM | libc::CLONE_FS | libc::CLONE_FILES))?; + if id == 0 { + start_thread(&*p as *const _ as *mut _); + let _ = libc::exit(0); + panic!("thread failed to exit"); + } else { + mem::forget(p); + Ok(Thread { id: id }) + } } pub fn yield_now() { @@ -69,8 +74,8 @@ impl Thread { } pub fn join(self) { - ::sys_common::util::dumb_print(format_args!("Thread::join")); - unimplemented!(); + let mut status = 0; + libc::waitpid(self.id, &mut status, 0).unwrap(); } pub fn id(&self) -> libc::pid_t { self.id } @@ -82,13 +87,6 @@ impl Thread { } } -impl Drop for Thread { - fn drop(&mut self) { - ::sys_common::util::dumb_print(format_args!("Thread::drop")); - unimplemented!(); - } -} - pub mod guard { pub unsafe fn current() -> Option { None } pub unsafe fn init() -> Option { None } From 4edcddfb618a6d684d1f3289706ecc7794b30278 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 30 Oct 2016 16:14:47 -0600 Subject: [PATCH 07/34] Implement TLS scoped keys, compiler builtins --- src/libstd/lib.rs | 2 +- src/libstd/sys/redox/thread_local.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 219f244be29cc..82a719693ec03 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -322,7 +322,7 @@ extern crate unwind; extern crate alloc_system; // compiler-rt intrinsics -//REDOX TODO extern crate compiler_builtins; +extern crate compiler_builtins; // Make std testable by not duplicating lang items and other globals. See #2912 #[cfg(test)] extern crate std as realstd; diff --git a/src/libstd/sys/redox/thread_local.rs b/src/libstd/sys/redox/thread_local.rs index b12ffebbcac1d..7958437a30a5a 100644 --- a/src/libstd/sys/redox/thread_local.rs +++ b/src/libstd/sys/redox/thread_local.rs @@ -17,10 +17,10 @@ pub type Key = usize; type Dtor = unsafe extern fn(*mut u8); -//TODO: Implement this properly - +#[thread_local] static mut NEXT_KEY: Key = 0; +#[thread_local] static mut LOCALS: *mut BTreeMap)> = ptr::null_mut(); unsafe fn locals() -> &'static mut BTreeMap)> { From c77979b419959dda0d628ffb4af15c5f2a9e8648 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Sun, 30 Oct 2016 18:35:19 -0600 Subject: [PATCH 08/34] Fix for thread locals --- src/libstd/sys/redox/thread_local.rs | 39 +++++++++++++++++----------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/src/libstd/sys/redox/thread_local.rs b/src/libstd/sys/redox/thread_local.rs index 7958437a30a5a..43b0bf09a6fe1 100644 --- a/src/libstd/sys/redox/thread_local.rs +++ b/src/libstd/sys/redox/thread_local.rs @@ -12,18 +12,27 @@ use collections::BTreeMap; use ptr; +use sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; pub type Key = usize; type Dtor = unsafe extern fn(*mut u8); -#[thread_local] -static mut NEXT_KEY: Key = 0; +static NEXT_KEY: AtomicUsize = ATOMIC_USIZE_INIT; + +static mut KEYS: *mut BTreeMap> = ptr::null_mut(); #[thread_local] -static mut LOCALS: *mut BTreeMap)> = ptr::null_mut(); +static mut LOCALS: *mut BTreeMap = ptr::null_mut(); + +unsafe fn keys() -> &'static mut BTreeMap> { + if KEYS == ptr::null_mut() { + KEYS = Box::into_raw(Box::new(BTreeMap::new())); + } + &mut *KEYS +} -unsafe fn locals() -> &'static mut BTreeMap)> { +unsafe fn locals() -> &'static mut BTreeMap { if LOCALS == ptr::null_mut() { LOCALS = Box::into_raw(Box::new(BTreeMap::new())); } @@ -32,26 +41,26 @@ unsafe fn locals() -> &'static mut BTreeMap)> { #[inline] pub unsafe fn create(dtor: Option) -> Key { - let key = NEXT_KEY; - NEXT_KEY += 1; - locals().insert(key, (0 as *mut u8, dtor)); + let key = NEXT_KEY.fetch_add(1, Ordering::SeqCst); + keys().insert(key, dtor); key } #[inline] -pub unsafe fn set(key: Key, value: *mut u8) { - locals().get_mut(&key).unwrap().0 = value; +pub unsafe fn get(key: Key) -> *mut u8 { + if let Some(&entry) = locals().get(&key) { + entry + } else { + ptr::null_mut() + } } #[inline] -pub unsafe fn get(key: Key) -> *mut u8 { - locals()[&key].0 +pub unsafe fn set(key: Key, value: *mut u8) { + locals().insert(key, value); } #[inline] pub unsafe fn destroy(key: Key) { - let (value, dtor) = locals().remove(&key).unwrap(); - if let Some(dtor_fn) = dtor { - dtor_fn(value); - } + keys().remove(&key); } From 01e837807095e99d68ecf9c0b38527288281dd02 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 3 Nov 2016 08:58:01 -0600 Subject: [PATCH 09/34] Update to new sys requirements --- src/libstd/sys/redox/fast_thread_local.rs | 116 ++++++++++++++++++++++ src/libstd/sys/redox/mod.rs | 6 ++ src/libstd/sys/redox/stdio.rs | 1 + 3 files changed, 123 insertions(+) create mode 100644 src/libstd/sys/redox/fast_thread_local.rs diff --git a/src/libstd/sys/redox/fast_thread_local.rs b/src/libstd/sys/redox/fast_thread_local.rs new file mode 100644 index 0000000000000..e0a1773084699 --- /dev/null +++ b/src/libstd/sys/redox/fast_thread_local.rs @@ -0,0 +1,116 @@ +// 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 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![cfg(target_thread_local)] +#![unstable(feature = "thread_local_internals", issue = "0")] + +use cell::{Cell, UnsafeCell}; +use intrinsics; +use ptr; + +pub struct Key { + inner: UnsafeCell>, + + // Metadata to keep track of the state of the destructor. Remember that + // these variables are thread-local, not global. + dtor_registered: Cell, + dtor_running: Cell, +} + +unsafe impl ::marker::Sync for Key { } + +impl Key { + pub const fn new() -> Key { + Key { + inner: UnsafeCell::new(None), + dtor_registered: Cell::new(false), + dtor_running: Cell::new(false) + } + } + + pub fn get(&'static self) -> Option<&'static UnsafeCell>> { + unsafe { + if intrinsics::needs_drop::() && self.dtor_running.get() { + return None + } + self.register_dtor(); + } + Some(&self.inner) + } + + unsafe fn register_dtor(&self) { + if !intrinsics::needs_drop::() || self.dtor_registered.get() { + return + } + + register_dtor(self as *const _ as *mut u8, + destroy_value::); + self.dtor_registered.set(true); + } +} + +unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { + // The fallback implementation uses a vanilla OS-based TLS key to track + // the list of destructors that need to be run for this thread. The key + // then has its own destructor which runs all the other destructors. + // + // The destructor for DTORS is a little special in that it has a `while` + // loop to continuously drain the list of registered destructors. It + // *should* be the case that this loop always terminates because we + // provide the guarantee that a TLS key cannot be set after it is + // flagged for destruction. + use sys_common::thread_local as os; + + static DTORS: os::StaticKey = os::StaticKey::new(Some(run_dtors)); + type List = Vec<(*mut u8, unsafe extern fn(*mut u8))>; + if DTORS.get().is_null() { + let v: Box = box Vec::new(); + DTORS.set(Box::into_raw(v) as *mut u8); + } + let list: &mut List = &mut *(DTORS.get() as *mut List); + list.push((t, dtor)); + + unsafe extern fn run_dtors(mut ptr: *mut u8) { + while !ptr.is_null() { + let list: Box = Box::from_raw(ptr as *mut List); + for &(ptr, dtor) in list.iter() { + dtor(ptr); + } + ptr = DTORS.get(); + DTORS.set(ptr::null_mut()); + } + } +} + +pub unsafe extern fn destroy_value(ptr: *mut u8) { + let ptr = ptr as *mut Key; + // Right before we run the user destructor be sure to flag the + // destructor as running for this thread so calls to `get` will return + // `None`. + (*ptr).dtor_running.set(true); + + // The OSX implementation of TLS apparently had an odd aspect to it + // where the pointer we have may be overwritten while this destructor + // is running. Specifically if a TLS destructor re-accesses TLS it may + // trigger a re-initialization of all TLS variables, paving over at + // least some destroyed ones with initial values. + // + // This means that if we drop a TLS value in place on OSX that we could + // revert the value to its original state halfway through the + // destructor, which would be bad! + // + // Hence, we use `ptr::read` on OSX (to move to a "safe" location) + // instead of drop_in_place. + if cfg!(target_os = "macos") { + ptr::read((*ptr).inner.get()); + } else { + ptr::drop_in_place((*ptr).inner.get()); + } +} diff --git a/src/libstd/sys/redox/mod.rs b/src/libstd/sys/redox/mod.rs index f7465d01fada3..3f3d8f2c4f41b 100644 --- a/src/libstd/sys/redox/mod.rs +++ b/src/libstd/sys/redox/mod.rs @@ -8,6 +8,7 @@ pub mod backtrace; pub mod condvar; pub mod env; pub mod ext; +pub mod fast_thread_local; pub mod fd; pub mod fs; pub mod memchr; @@ -76,3 +77,8 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind { pub fn cvt(result: Result) -> io::Result { result.map_err(|err| io::Error::from_raw_os_error(err.errno as i32)) } + +/// On Redox, use an illegal instruction to abort +pub unsafe fn abort_internal() -> ! { + ::core::intrinsics::abort(); +} diff --git a/src/libstd/sys/redox/stdio.rs b/src/libstd/sys/redox/stdio.rs index 0ed9de36c73dc..f0a781b438346 100644 --- a/src/libstd/sys/redox/stdio.rs +++ b/src/libstd/sys/redox/stdio.rs @@ -67,3 +67,4 @@ impl io::Write for Stderr { } pub const EBADF_ERR: i32 = ::libc::EBADF; +pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE; From ced32a08f3bf7325bf3fe6488e21b108f996abc5 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 9 Nov 2016 20:52:30 -0700 Subject: [PATCH 10/34] Fix exec --- src/libstd/sys/redox/process.rs | 66 +++++---------------------------- 1 file changed, 10 insertions(+), 56 deletions(-) diff --git a/src/libstd/sys/redox/process.rs b/src/libstd/sys/redox/process.rs index b6968f285d7aa..ad50d1de28333 100644 --- a/src/libstd/sys/redox/process.rs +++ b/src/libstd/sys/redox/process.rs @@ -18,7 +18,7 @@ use path::Path; use sys::fd::FileDesc; use sys::fs::{File, OpenOptions}; use sys::pipe::{self, AnonPipe}; -use sys::{self, cvt}; +use sys::cvt; //////////////////////////////////////////////////////////////////////////////// // Command @@ -145,78 +145,32 @@ impl Command { 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::clone(0))? { + match cvt(libc::clone(libc::CLONE_VFORK))? { 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()); - let _ = libc::exit(1); + let _ = libc::exit((-err.raw_os_error().unwrap_or(libc::EINVAL)) as usize); unreachable!(); } 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") - } + let mut status_mux = 0; + if cvt(libc::waitpid(pid, &mut status_mux, libc::WNOHANG))? == pid { + match libc::Error::demux(status_mux) { + Ok(status) => Ok((Process { pid: pid, status: Some(ExitStatus::from(status as c_int)) }, ours)), + Err(err) => Err(io::Error::from_raw_os_error(err.errno)), } - } - - 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 + } else { + Ok((Process { pid: pid, status: None }, ours)) } } From a90850995f9f177c910ba548f1a6312353673926 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 10 Nov 2016 19:33:59 -0700 Subject: [PATCH 11/34] Fixes for stdio and processes on Redox --- src/libpanic_abort/lib.rs | 4 ++-- src/libpanic_unwind/lib.rs | 1 + src/libstd/io/stdio.rs | 6 ++++++ src/libstd/sys/redox/fd.rs | 3 +-- src/libstd/sys/redox/process.rs | 16 +++++++++++++++- src/libstd/sys/redox/stdio.rs | 14 +++++++++++++- 6 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/libpanic_abort/lib.rs b/src/libpanic_abort/lib.rs index b87160dd75d04..26bc46931bd5f 100644 --- a/src/libpanic_abort/lib.rs +++ b/src/libpanic_abort/lib.rs @@ -28,7 +28,7 @@ #![panic_runtime] #![feature(panic_runtime)] #![cfg_attr(unix, feature(libc))] -#![cfg_attr(windows, feature(core_intrinsics))] +#![cfg_attr(any(target_os = "redox", windows), feature(core_intrinsics))] // Rust's "try" function, but if we're aborting on panics we just call the // function as there's nothing else we need to do here. @@ -61,7 +61,7 @@ pub unsafe extern fn __rust_start_panic(_data: usize, _vtable: usize) -> u32 { libc::abort(); } - #[cfg(windows)] + #[cfg(any(target_os = "redox", windows))] unsafe fn abort() -> ! { core::intrinsics::abort(); } diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs index ff483fa823e0c..b75d9ec6520a4 100644 --- a/src/libpanic_unwind/lib.rs +++ b/src/libpanic_unwind/lib.rs @@ -69,6 +69,7 @@ mod imp; // i686-pc-windows-gnu and all others #[cfg(any(all(unix, not(target_os = "emscripten")), + target_os = "redox", all(windows, target_arch = "x86", target_env = "gnu")))] #[path = "gcc.rs"] mod imp; diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index 1777b79ea1b59..27bc5f0890ce9 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -81,11 +81,17 @@ impl Read for StdinRaw { } impl Write for StdoutRaw { fn write(&mut self, buf: &[u8]) -> io::Result { self.0.write(buf) } + #[cfg(not(target_os = "redox"))] fn flush(&mut self) -> io::Result<()> { Ok(()) } + #[cfg(target_os = "redox")] + fn flush(&mut self) -> io::Result<()> { self.0.flush() } } impl Write for StderrRaw { fn write(&mut self, buf: &[u8]) -> io::Result { self.0.write(buf) } + #[cfg(not(target_os = "redox"))] fn flush(&mut self) -> io::Result<()> { Ok(()) } + #[cfg(target_os = "redox")] + fn flush(&mut self) -> io::Result<()> { self.0.flush() } } enum Maybe { diff --git a/src/libstd/sys/redox/fd.rs b/src/libstd/sys/redox/fd.rs index 9c50c547965a8..786d767661210 100644 --- a/src/libstd/sys/redox/fd.rs +++ b/src/libstd/sys/redox/fd.rs @@ -50,8 +50,7 @@ impl FileDesc { pub fn set_cloexec(&self) -> io::Result<()> { ::sys_common::util::dumb_print(format_args!("{}: set cloexec\n", self.fd)); - //unimplemented!(); - Ok(()) + unimplemented!(); } pub fn set_nonblocking(&self, _nonblocking: bool) -> io::Result<()> { diff --git a/src/libstd/sys/redox/process.rs b/src/libstd/sys/redox/process.rs index ad50d1de28333..934cf20bf07d6 100644 --- a/src/libstd/sys/redox/process.rs +++ b/src/libstd/sys/redox/process.rs @@ -264,7 +264,21 @@ impl Command { env::set_var(key, val); } - if let Err(err) = libc::exec(&self.program, &args) { + let program = if self.program.contains(':') || self.program.contains('/') { + self.program.to_owned() + } else { + let mut path_env = ::env::var("PATH").unwrap_or(".".to_string()); + + if ! path_env.ends_with('/') { + path_env.push('/'); + } + + path_env.push_str(&self.program); + + path_env + }; + + if let Err(err) = libc::exec(&program, &args) { io::Error::from_raw_os_error(err.errno as i32) } else { panic!("return from exec without err"); diff --git a/src/libstd/sys/redox/stdio.rs b/src/libstd/sys/redox/stdio.rs index f0a781b438346..5006218690336 100644 --- a/src/libstd/sys/redox/stdio.rs +++ b/src/libstd/sys/redox/stdio.rs @@ -10,6 +10,7 @@ use io; use libc; +use sys::cvt; use sys::fd::FileDesc; pub struct Stdin(()); @@ -43,6 +44,10 @@ impl Stdout { fd.into_raw(); ret } + + pub fn flush(&self) -> io::Result<()> { + cvt(libc::fsync(libc::STDOUT_FILENO)).and(Ok(())) + } } impl Stderr { @@ -54,6 +59,10 @@ impl Stderr { fd.into_raw(); ret } + + pub fn flush(&self) -> io::Result<()> { + cvt(libc::fsync(libc::STDERR_FILENO)).and(Ok(())) + } } // FIXME: right now this raw stderr handle is used in a few places because @@ -63,7 +72,10 @@ impl io::Write for Stderr { fn write(&mut self, data: &[u8]) -> io::Result { Stderr::write(self, data) } - fn flush(&mut self) -> io::Result<()> { Ok(()) } + + fn flush(&mut self) -> io::Result<()> { + cvt(libc::fsync(libc::STDERR_FILENO)).and(Ok(())) + } } pub const EBADF_ERR: i32 = ::libc::EBADF; From 79a8c272fb8ad09600ef58ff223c73eb44343040 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 10 Nov 2016 19:58:19 -0700 Subject: [PATCH 12/34] Fix readdir --- src/libstd/sys/redox/fs.rs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/libstd/sys/redox/fs.rs b/src/libstd/sys/redox/fs.rs index 3779c4c66775e..1a96ac2f2eabd 100644 --- a/src/libstd/sys/redox/fs.rs +++ b/src/libstd/sys/redox/fs.rs @@ -146,16 +146,17 @@ impl Iterator for ReadDir { fn next(&mut self) -> Option> { loop { let start = self.i; - while self.i < self.data.len() { - let i = self.i; + let mut i = self.i; + while i < self.data.len() { self.i += 1; if self.data[i] == b'\n' { break; } + i += 1; } if start < self.i { let ret = DirEntry { - name: self.data[start .. self.i].to_owned().into_boxed_slice(), + name: self.data[start .. i].to_owned().into_boxed_slice(), root: self.root.clone() }; if ret.name_bytes() != b"." && ret.name_bytes() != b".." { @@ -182,7 +183,7 @@ impl DirEntry { } pub fn file_type(&self) -> io::Result { - stat(&self.path()).map(|m| m.file_type()) + lstat(&self.path()).map(|m| m.file_type()) } fn name_bytes(&self) -> &[u8] { @@ -367,7 +368,8 @@ impl fmt::Debug for File { pub fn readdir(p: &Path) -> io::Result { let root = Arc::new(p.to_path_buf()); - let options = OpenOptions::new(); + let mut options = OpenOptions::new(); + options.read(true); let fd = File::open(p, &options)?; let mut data = Vec::new(); fd.read_to_end(&mut data)?; @@ -431,7 +433,8 @@ pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> { pub fn stat(p: &Path) -> io::Result { let mut stat: stat = stat::default(); - let options = OpenOptions::new(); + let mut options = OpenOptions::new(); + options.read(true); let file = File::open(p, &options)?; cvt(fstat(file.0.raw(), &mut stat))?; Ok(FileAttr { stat: stat }) @@ -442,7 +445,8 @@ pub fn lstat(p: &Path) -> io::Result { } pub fn canonicalize(p: &Path) -> io::Result { - let options = OpenOptions::new(); + let mut options = OpenOptions::new(); + options.read(true); let file = File::open(p, &options)?; file.path() } From 25e1a4a0084a56807d7a1e4ca676e078c085b3aa Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 10 Nov 2016 20:13:14 -0700 Subject: [PATCH 13/34] Use target_os = redox for cfg --- src/libstd/fs.rs | 2 +- src/libstd/os/mod.rs | 5 +---- src/libstd/sys/mod.rs | 2 +- src/libstd/sys_common/mod.rs | 4 ++-- 4 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 5845963d31a10..3fc1267c06e81 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -353,7 +353,7 @@ impl File { /// /// This function is only implemented on Redox, but could be /// implemented on other operating systems using readlink - #[cfg(redox)] + #[cfg(target_os = "redox")] #[stable(feature = "rust1", since = "1.14.0")] pub fn path(&self) -> io::Result { self.inner.path() diff --git a/src/libstd/os/mod.rs b/src/libstd/os/mod.rs index 744ee6c22e5bf..58f1604de1c5c 100644 --- a/src/libstd/os/mod.rs +++ b/src/libstd/os/mod.rs @@ -13,10 +13,7 @@ #![stable(feature = "os", since = "1.0.0")] #![allow(missing_docs, bad_style)] -#[cfg(redox)] -#[stable(feature = "rust1", since = "1.0.0")] -pub use sys::ext as unix; -#[cfg(unix)] +#[cfg(any(target_os = "redox", unix))] #[stable(feature = "rust1", since = "1.0.0")] pub use sys::ext as unix; #[cfg(windows)] diff --git a/src/libstd/sys/mod.rs b/src/libstd/sys/mod.rs index c196bf39432cf..a237d8a067e2b 100644 --- a/src/libstd/sys/mod.rs +++ b/src/libstd/sys/mod.rs @@ -32,7 +32,7 @@ pub use self::imp::*; -#[cfg(redox)] +#[cfg(target_os = "redox")] #[path = "redox/mod.rs"] mod imp; diff --git a/src/libstd/sys_common/mod.rs b/src/libstd/sys_common/mod.rs index bbd2f679bcaf4..5f5ea09c78d61 100644 --- a/src/libstd/sys_common/mod.rs +++ b/src/libstd/sys_common/mod.rs @@ -43,10 +43,10 @@ pub mod thread_local; pub mod util; pub mod wtf8; -#[cfg(redox)] +#[cfg(target_os = "redox")] pub use sys::net; -#[cfg(not(redox))] +#[cfg(not(target_os = "redox"))] pub mod net; #[cfg(any(not(cargobuild), feature = "backtrace"))] From a0b5dfef2a36a15f76476a9d6bb7184a701d0d3c Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 14 Nov 2016 12:15:11 -0700 Subject: [PATCH 14/34] Add fcntl --- src/libstd/sys/redox/fd.rs | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/libstd/sys/redox/fd.rs b/src/libstd/sys/redox/fd.rs index 786d767661210..47d2280fe05f2 100644 --- a/src/libstd/sys/redox/fd.rs +++ b/src/libstd/sys/redox/fd.rs @@ -49,13 +49,19 @@ impl FileDesc { } pub fn set_cloexec(&self) -> io::Result<()> { - ::sys_common::util::dumb_print(format_args!("{}: set cloexec\n", self.fd)); - unimplemented!(); + let mut flags = cvt(libc::fcntl(self.fd, libc::F_GETFL, 0))?; + flags |= libc::O_CLOEXEC; + cvt(libc::fcntl(self.fd, libc::F_SETFL, flags)).and(Ok(())) } - pub fn set_nonblocking(&self, _nonblocking: bool) -> io::Result<()> { - ::sys_common::util::dumb_print(format_args!("{}: set nonblocking\n", self.fd)); - unimplemented!(); + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + let mut flags = cvt(libc::fcntl(self.fd, libc::F_GETFL, 0))?; + if nonblocking { + flags |= libc::O_NONBLOCK; + } else { + flags &= !libc::O_NONBLOCK; + } + cvt(libc::fcntl(self.fd, libc::F_SETFL, flags)).and(Ok(())) } pub fn duplicate(&self) -> io::Result { From 18bf0540bf8a04a5724dd515fec2311d1e4768e4 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 14 Nov 2016 15:02:18 -0700 Subject: [PATCH 15/34] Fix redox prefix handling --- src/libstd/path.rs | 9 ++++++++- src/libstd/sys/redox/path.rs | 12 ++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index bb6883236e802..3e414a28a301b 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -129,7 +129,9 @@ use sys::path::{is_sep_byte, is_verbatim_sep, MAIN_SEP_STR, parse_prefix}; // Windows Prefixes //////////////////////////////////////////////////////////////////////////////// -/// Path prefixes (Windows only). +/// Path prefixes (Redox and Windows only). +/// +/// Redox uses schemes like `scheme:reference` to identify different I/O systems /// /// Windows uses a variety of path styles, including references to drive /// volumes (like `C:`), network shared folders (like `\\server\share`) and @@ -139,6 +141,10 @@ use sys::path::{is_sep_byte, is_verbatim_sep, MAIN_SEP_STR, parse_prefix}; #[derive(Copy, Clone, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)] #[stable(feature = "rust1", since = "1.0.0")] pub enum Prefix<'a> { + /// Prefix `scheme:`, where `scheme` is the component stored + #[unstable(feature="redox_prefix", issue="0")] + Scheme(&'a OsStr), + /// Prefix `\\?\`, together with the given component immediately following it. #[stable(feature = "rust1", since = "1.0.0")] Verbatim(#[stable(feature = "rust1", since = "1.0.0")] &'a OsStr), @@ -178,6 +184,7 @@ impl<'a> Prefix<'a> { os_str_as_u8_slice(s).len() } match *self { + Scheme(x) => os_str_len(x) + 1, Verbatim(x) => 4 + os_str_len(x), VerbatimUNC(x, y) => { 8 + os_str_len(x) + diff --git a/src/libstd/sys/redox/path.rs b/src/libstd/sys/redox/path.rs index bf9af7a4353a8..4069a0ea726f9 100644 --- a/src/libstd/sys/redox/path.rs +++ b/src/libstd/sys/redox/path.rs @@ -21,8 +21,16 @@ pub fn is_verbatim_sep(b: u8) -> bool { b == b'/' } -pub fn parse_prefix(_: &OsStr) -> Option { - None +pub fn parse_prefix(path: &OsStr) -> Option { + if let Some(path_str) = path.to_str() { + if let Some(i) = path_str.find(':') { + Some(Prefix::Scheme(OsStr::new(&path_str[..i]))) + } else { + None + } + } else { + None + } } pub const MAIN_SEP_STR: &'static str = "/"; From de68aced95ab53bc0f69ff4d6867a03d2dd0f8d7 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 14 Nov 2016 19:08:48 -0700 Subject: [PATCH 16/34] Add current_exe support --- src/libstd/sys/redox/os.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/libstd/sys/redox/os.rs b/src/libstd/sys/redox/os.rs index 309201352c404..e007e33258f61 100644 --- a/src/libstd/sys/redox/os.rs +++ b/src/libstd/sys/redox/os.rs @@ -113,8 +113,18 @@ impl StdError for JoinPathsError { } pub fn current_exe() -> io::Result { - use io::ErrorKind; - Err(io::Error::new(ErrorKind::Other, "Not yet implemented on redox")) + use fs::File; + + let mut file = File::open("sys:exe")?; + + let mut path = String::new(); + file.read_to_string(&mut path)?; + + if path.ends_with('\n') { + path.pop(); + } + + Ok(PathBuf::from(path)) } pub struct Env { From 73f24d47dee367563019b18ac5089b91eded2753 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 14 Nov 2016 20:56:06 -0700 Subject: [PATCH 17/34] Simple implementation of read2 --- src/libstd/sys/redox/pipe.rs | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/libstd/sys/redox/pipe.rs b/src/libstd/sys/redox/pipe.rs index a25ca04894272..fff4a10f913d2 100644 --- a/src/libstd/sys/redox/pipe.rs +++ b/src/libstd/sys/redox/pipe.rs @@ -23,9 +23,7 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { libc::pipe2(&mut fds, libc::O_CLOEXEC).map_err(|err| io::Error::from_raw_os_error(err.errno))?; - let fd0 = FileDesc::new(fds[0]); - let fd1 = FileDesc::new(fds[1]); - Ok((AnonPipe::from_fd(fd0)?, AnonPipe::from_fd(fd1)?)) + Ok((AnonPipe(FileDesc::new(fds[0])), AnonPipe(FileDesc::new(fds[1])))) } impl AnonPipe { @@ -50,12 +48,18 @@ impl AnonPipe { pub fn into_fd(self) -> FileDesc { self.0 } } -pub fn read2(_p1: AnonPipe, - _v1: &mut Vec, - _p2: AnonPipe, - _v2: &mut Vec) -> io::Result<()> { - ::sys_common::util::dumb_print(format_args!("read2\n")); - unimplemented!(); +pub fn read2(p1: AnonPipe, + v1: &mut Vec, + p2: AnonPipe, + v2: &mut Vec) -> io::Result<()> { + //TODO: Use event based I/O multiplexing + //unimplemented!() + + p1.read_to_end(v1)?; + p2.read_to_end(v2)?; + + Ok(()) + /* // Set both pipes into nonblocking mode as we're gonna be reading from both // in the `select` loop below, and we wouldn't want one to block the other! @@ -64,7 +68,6 @@ pub fn read2(_p1: AnonPipe, 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 { From 2e5c821619c7b62ec46c8a4f90ead4e59fb6c36e Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 15 Nov 2016 16:12:30 -0700 Subject: [PATCH 18/34] Add set_perm --- src/libstd/sys/redox/ext/fs.rs | 2 +- src/libstd/sys/redox/fs.rs | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/libstd/sys/redox/ext/fs.rs b/src/libstd/sys/redox/ext/fs.rs index 45ad7c092de18..2914fafa94c88 100644 --- a/src/libstd/sys/redox/ext/fs.rs +++ b/src/libstd/sys/redox/ext/fs.rs @@ -216,7 +216,7 @@ impl MetadataExt for fs::Metadata { } } -/* +/* TODO /// Add special unix types (block/char device, fifo and socket) #[stable(feature = "file_type_ext", since = "1.5.0")] pub trait FileTypeExt { diff --git a/src/libstd/sys/redox/fs.rs b/src/libstd/sys/redox/fs.rs index 1a96ac2f2eabd..df2926565f73b 100644 --- a/src/libstd/sys/redox/fs.rs +++ b/src/libstd/sys/redox/fs.rs @@ -386,9 +386,12 @@ pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> { unimplemented!(); } -pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> { - ::sys_common::util::dumb_print(format_args!("Set perm\n")); - unimplemented!(); +pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> { + let mut options = OpenOptions::new(); + options.read(true); + let file = File::open(p, &options)?; + cvt(libc::fcntl(file.0.raw(), libc::F_SETMODE, perm.mode as usize))?; + Ok(()) } pub fn rmdir(p: &Path) -> io::Result<()> { From 267bc54fbd2cfeadde7a87fc2aa3fb975ff58b6c Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Tue, 15 Nov 2016 17:07:55 -0700 Subject: [PATCH 19/34] Use chmod instead of fcntl to change file perms --- src/libstd/sys/redox/fs.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/libstd/sys/redox/fs.rs b/src/libstd/sys/redox/fs.rs index df2926565f73b..3a7b8266a63fb 100644 --- a/src/libstd/sys/redox/fs.rs +++ b/src/libstd/sys/redox/fs.rs @@ -387,10 +387,7 @@ pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> { } pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> { - let mut options = OpenOptions::new(); - options.read(true); - let file = File::open(p, &options)?; - cvt(libc::fcntl(file.0.raw(), libc::F_SETMODE, perm.mode as usize))?; + cvt(libc::chmod(p.to_str().unwrap(), perm.mode as usize))?; Ok(()) } From f01add1a3bc3d86ee62f5819fa6ed9f79d453665 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 17 Nov 2016 10:22:07 -0700 Subject: [PATCH 20/34] Add signal support, better exec error handling --- src/libstd/sys/redox/process.rs | 114 ++++++++++++++++++++++---------- 1 file changed, 80 insertions(+), 34 deletions(-) diff --git a/src/libstd/sys/redox/process.rs b/src/libstd/sys/redox/process.rs index 934cf20bf07d6..92694e4b2227c 100644 --- a/src/libstd/sys/redox/process.rs +++ b/src/libstd/sys/redox/process.rs @@ -13,7 +13,7 @@ use env; use ffi::OsStr; use fmt; use io::{self, Error, ErrorKind}; -use libc::{self, pid_t, c_int, gid_t, uid_t}; +use libc::{self, pid_t, gid_t, uid_t}; use path::Path; use sys::fd::FileDesc; use sys::fs::{File, OpenOptions}; @@ -145,33 +145,79 @@ impl Command { pub fn spawn(&mut self, default: Stdio, needs_stdin: bool) -> io::Result<(Process, StdioPipes)> { - 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 pid = unsafe { - match cvt(libc::clone(libc::CLONE_VFORK))? { - 0 => { - let err = self.do_exec(theirs); - let _ = libc::exit((-err.raw_os_error().unwrap_or(libc::EINVAL)) as usize); - unreachable!(); - } - n => n as pid_t, - } - }; - - let mut status_mux = 0; - if cvt(libc::waitpid(pid, &mut status_mux, libc::WNOHANG))? == pid { - match libc::Error::demux(status_mux) { - Ok(status) => Ok((Process { pid: pid, status: Some(ExitStatus::from(status as c_int)) }, ours)), - Err(err) => Err(io::Error::from_raw_os_error(err.errno)), - } - } else { - Ok((Process { pid: pid, status: None }, ours)) - } + const CLOEXEC_MSG_FOOTER: &'static [u8] = b"NOEX"; + + if self.saw_nul { + return Err(io::Error::new(ErrorKind::InvalidInput, + "nul byte found in provided data")); + } + + let (ours, theirs) = self.setup_io(default, needs_stdin)?; + let (input, output) = pipe::anon_pipe()?; + + let pid = unsafe { + match cvt(libc::clone(0))? { + 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()); + let _ = libc::exit(1); + panic!("failed to exit"); + } + n => n, + } + }; + + let mut p = Process { pid: pid, status: None }; + drop(output); + let mut bytes = [0; 8]; + + // loop to handle EINTR + loop { + match input.read(&mut bytes) { + Ok(0) => return Ok((p, ours)), + Ok(8) => { + assert!(combine(CLOEXEC_MSG_FOOTER) == combine(&bytes[4.. 8]), + "Validation on the CLOEXEC pipe failed: {:?}", bytes); + let errno = combine(&bytes[0.. 4]); + assert!(p.wait().is_ok(), + "wait() should either return Ok or panic"); + return Err(Error::from_raw_os_error(errno)) + } + Err(ref e) if e.kind() == ErrorKind::Interrupted => {} + Err(e) => { + assert!(p.wait().is_ok(), + "wait() should either return Ok or panic"); + panic!("the CLOEXEC pipe failed: {:?}", e) + }, + Ok(..) => { // pipe I/O up to PIPE_BUF bytes should be atomic + assert!(p.wait().is_ok(), + "wait() should either return Ok or panic"); + panic!("short read on the CLOEXEC pipe") + } + } + } + + fn combine(arr: &[u8]) -> i32 { + let a = arr[0] as u32; + let b = arr[1] as u32; + let c = arr[2] as u32; + let d = arr[3] as u32; + + ((a << 24) | (b << 16) | (c << 8) | (d << 0)) as i32 + } } pub fn exec(&mut self, default: Stdio) -> io::Error { @@ -378,11 +424,11 @@ impl fmt::Debug for Command { /// Unix exit statuses #[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub struct ExitStatus(c_int); +pub struct ExitStatus(i32); impl ExitStatus { fn exited(&self) -> bool { - true + self.0 & 0x7F == 0 } pub fn success(&self) -> bool { @@ -391,7 +437,7 @@ impl ExitStatus { pub fn code(&self) -> Option { if self.exited() { - Some(self.0) + Some((self.0 >> 8) & 0xFF) } else { None } @@ -399,15 +445,15 @@ impl ExitStatus { pub fn signal(&self) -> Option { if !self.exited() { - Some(self.0) + Some(self.0 & 0x7F) } else { None } } } -impl From for ExitStatus { - fn from(a: c_int) -> ExitStatus { +impl From for ExitStatus { + fn from(a: i32) -> ExitStatus { ExitStatus(a) } } From 2556400a5d4c9b56084332c29b6c91ac5cd3a9fa Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Thu, 17 Nov 2016 14:15:58 -0700 Subject: [PATCH 21/34] Replace setuid, setgid with setreuid, setregid --- src/libstd/sys/redox/process.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libstd/sys/redox/process.rs b/src/libstd/sys/redox/process.rs index 92694e4b2227c..269aa6bedac0f 100644 --- a/src/libstd/sys/redox/process.rs +++ b/src/libstd/sys/redox/process.rs @@ -287,10 +287,10 @@ impl Command { } if let Some(g) = self.gid { - t!(cvt(libc::setgid(g))); + t!(cvt(libc::setregid(g, g))); } if let Some(u) = self.uid { - t!(cvt(libc::setuid(u))); + t!(cvt(libc::setreuid(u, u))); } if let Some(ref cwd) = self.cwd { t!(cvt(libc::chdir(cwd))); From 4a0bc71bb7e32d7f63d10be13055942fb5dc6aca Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 23 Nov 2016 08:24:49 -0700 Subject: [PATCH 22/34] Add File set_permissions --- src/libstd/sys/redox/fs.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/libstd/sys/redox/fs.rs b/src/libstd/sys/redox/fs.rs index 3a7b8266a63fb..2b0ab361492cc 100644 --- a/src/libstd/sys/redox/fs.rs +++ b/src/libstd/sys/redox/fs.rs @@ -316,6 +316,10 @@ impl File { Ok(File(FileDesc::new(fd))) } + pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> { + set_perm(&self.path()?, perm) + } + pub fn path(&self) -> io::Result { let mut buf: [u8; 4096] = [0; 4096]; match libc::fpath(*self.fd().as_inner() as usize, &mut buf) { From 6733074c847767fd3e0425fcefb73226bde1f6a1 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 23 Nov 2016 14:22:39 -0700 Subject: [PATCH 23/34] Allow setting nonblock on sockets --- src/libstd/sys/redox/fd.rs | 15 ++++++++++----- src/libstd/sys/redox/net/tcp.rs | 6 +++--- src/libstd/sys/redox/net/udp.rs | 6 +++--- 3 files changed, 16 insertions(+), 11 deletions(-) diff --git a/src/libstd/sys/redox/fd.rs b/src/libstd/sys/redox/fd.rs index 47d2280fe05f2..b716965860e1d 100644 --- a/src/libstd/sys/redox/fd.rs +++ b/src/libstd/sys/redox/fd.rs @@ -48,6 +48,16 @@ impl FileDesc { cvt(libc::write(self.fd, buf)) } + pub fn duplicate(&self) -> io::Result { + let new_fd = cvt(libc::dup(self.fd, &[]))?; + Ok(FileDesc::new(new_fd)) + } + + pub fn nonblocking(&self) -> io::Result { + let flags = cvt(libc::fcntl(self.fd, libc::F_GETFL, 0))?; + Ok(flags & libc::O_NONBLOCK == libc::O_NONBLOCK) + } + pub fn set_cloexec(&self) -> io::Result<()> { let mut flags = cvt(libc::fcntl(self.fd, libc::F_GETFL, 0))?; flags |= libc::O_CLOEXEC; @@ -63,11 +73,6 @@ impl FileDesc { } cvt(libc::fcntl(self.fd, libc::F_SETFL, flags)).and(Ok(())) } - - pub fn duplicate(&self) -> io::Result { - let new_fd = cvt(libc::dup(self.fd, &[]))?; - Ok(FileDesc::new(new_fd)) - } } impl<'a> Read for &'a FileDesc { diff --git a/src/libstd/sys/redox/net/tcp.rs b/src/libstd/sys/redox/net/tcp.rs index 351c534c036df..ceaa5df267fd3 100644 --- a/src/libstd/sys/redox/net/tcp.rs +++ b/src/libstd/sys/redox/net/tcp.rs @@ -58,7 +58,7 @@ impl TcpStream { } pub fn nonblocking(&self) -> Result { - Err(Error::new(ErrorKind::Other, "TcpStream::nonblocking not implemented")) + self.0.fd().nonblocking() } pub fn only_v6(&self) -> Result { @@ -81,8 +81,8 @@ impl TcpStream { 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_nonblocking(&self, nonblocking: bool) -> Result<()> { + self.0.fd().set_nonblocking(nonblocking) } pub fn set_only_v6(&self, _only_v6: bool) -> Result<()> { diff --git a/src/libstd/sys/redox/net/udp.rs b/src/libstd/sys/redox/net/udp.rs index a259db6a4c047..7856de033eb15 100644 --- a/src/libstd/sys/redox/net/udp.rs +++ b/src/libstd/sys/redox/net/udp.rs @@ -90,7 +90,7 @@ impl UdpSocket { } pub fn nonblocking(&self) -> Result { - Err(Error::new(ErrorKind::Other, "UdpSocket::nonblocking not implemented")) + self.0.fd().nonblocking() } pub fn only_v6(&self) -> Result { @@ -125,8 +125,8 @@ impl UdpSocket { 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_nonblocking(&self, nonblocking: bool) -> Result<()> { + self.0.fd().set_nonblocking(nonblocking) } pub fn set_only_v6(&self, _only_v6: bool) -> Result<()> { From 3a1bb2ba26a85bbea4c9be813a9a13d48ab448ac Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 25 Nov 2016 18:23:19 -0700 Subject: [PATCH 24/34] Use O_DIRECTORY --- src/libstd/sys/redox/fs.rs | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/src/libstd/sys/redox/fs.rs b/src/libstd/sys/redox/fs.rs index 2b0ab361492cc..0e51da711c98d 100644 --- a/src/libstd/sys/redox/fs.rs +++ b/src/libstd/sys/redox/fs.rs @@ -339,7 +339,8 @@ impl DirBuilder { } pub fn mkdir(&self, p: &Path) -> io::Result<()> { - cvt(libc::mkdir(p.to_str().unwrap(), self.mode))?; + let fd = cvt(libc::open(p.to_str().unwrap(), libc::O_CREAT | libc::O_DIRECTORY | libc::O_EXCL | (self.mode as usize & 0o777)))?; + let _ = libc::close(fd); Ok(()) } @@ -372,11 +373,12 @@ impl fmt::Debug for File { pub fn readdir(p: &Path) -> io::Result { let root = Arc::new(p.to_path_buf()); - let mut options = OpenOptions::new(); - options.read(true); - let fd = File::open(p, &options)?; + + let fd = cvt(open(p.to_str().unwrap(), libc::O_CLOEXEC | libc::O_RDONLY | libc::O_DIRECTORY))?; + let file = FileDesc::new(fd); let mut data = Vec::new(); - fd.read_to_end(&mut data)?; + file.read_to_end(&mut data)?; + Ok(ReadDir { data: data, i: 0, root: root }) } @@ -437,10 +439,11 @@ pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> { pub fn stat(p: &Path) -> io::Result { let mut stat: stat = stat::default(); - let mut options = OpenOptions::new(); - options.read(true); - let file = File::open(p, &options)?; - cvt(fstat(file.0.raw(), &mut stat))?; + + let fd = cvt(open(p.to_str().unwrap(), libc::O_CLOEXEC | libc::O_STAT))?; + cvt(fstat(fd, &mut stat))?; + let _ = libc::close(fd); + Ok(FileAttr { stat: stat }) } From d73d32f58d477ca1562e3fc0e966efc88e81409e Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Fri, 25 Nov 2016 19:53:21 -0700 Subject: [PATCH 25/34] Fix canonicalize --- src/libstd/sys/redox/fs.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/libstd/sys/redox/fs.rs b/src/libstd/sys/redox/fs.rs index 0e51da711c98d..12aa17becd860 100644 --- a/src/libstd/sys/redox/fs.rs +++ b/src/libstd/sys/redox/fs.rs @@ -452,9 +452,8 @@ pub fn lstat(p: &Path) -> io::Result { } pub fn canonicalize(p: &Path) -> io::Result { - let mut options = OpenOptions::new(); - options.read(true); - let file = File::open(p, &options)?; + let fd = cvt(open(p.to_str().unwrap(), libc::O_CLOEXEC | libc::O_STAT))?; + let file = File(FileDesc::new(fd)); file.path() } From 746222fd9d6c16d3dc3c44c797dcc868297c133b Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 28 Nov 2016 18:07:19 -0700 Subject: [PATCH 26/34] Switch to using syscall crate directly - without import --- src/libstd/sys/redox/condvar.rs | 5 +- src/libstd/sys/redox/ext/fs.rs | 10 +-- src/libstd/sys/redox/ext/mod.rs | 2 +- src/libstd/sys/redox/ext/process.rs | 4 +- src/libstd/sys/redox/fd.rs | 29 ++++--- src/libstd/sys/redox/fs.rs | 125 +++++++++++++--------------- src/libstd/sys/redox/mod.rs | 39 ++++----- src/libstd/sys/redox/mutex.rs | 2 +- src/libstd/sys/redox/net/mod.rs | 2 +- src/libstd/sys/redox/os.rs | 12 ++- src/libstd/sys/redox/pipe.rs | 4 +- src/libstd/sys/redox/process.rs | 53 ++++++------ src/libstd/sys/redox/stdio.rs | 19 ++--- src/libstd/sys/redox/thread.rs | 26 +++--- src/libstd/sys/redox/time.rs | 27 +++--- 15 files changed, 171 insertions(+), 188 deletions(-) diff --git a/src/libstd/sys/redox/condvar.rs b/src/libstd/sys/redox/condvar.rs index f6c8fec545b97..7e26162efbc8e 100644 --- a/src/libstd/sys/redox/condvar.rs +++ b/src/libstd/sys/redox/condvar.rs @@ -3,9 +3,8 @@ 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}; +use sys::mutex::{mutex_lock, mutex_unlock, Mutex}; +use sys::syscall::{futex, FUTEX_WAIT, FUTEX_WAKE, FUTEX_REQUEUE}; pub struct Condvar { lock: UnsafeCell<*mut i32>, diff --git a/src/libstd/sys/redox/ext/fs.rs b/src/libstd/sys/redox/ext/fs.rs index 2914fafa94c88..d292b43872439 100644 --- a/src/libstd/sys/redox/ext/fs.rs +++ b/src/libstd/sys/redox/ext/fs.rs @@ -216,7 +216,6 @@ impl MetadataExt for fs::Metadata { } } -/* TODO /// Add special unix types (block/char device, fifo and socket) #[stable(feature = "file_type_ext", since = "1.5.0")] pub trait FileTypeExt { @@ -236,12 +235,11 @@ pub trait FileTypeExt { #[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) } + fn is_block_device(&self) -> bool { false /*TODO*/ } + fn is_char_device(&self) -> bool { false /*TODO*/ } + fn is_fifo(&self) -> bool { false /*TODO*/ } + fn is_socket(&self) -> bool { false /*TODO*/ } } -*/ /// Creates a new symbolic link on the filesystem. /// diff --git a/src/libstd/sys/redox/ext/mod.rs b/src/libstd/sys/redox/ext/mod.rs index 7ba166e89320f..02edfa84aa090 100644 --- a/src/libstd/sys/redox/ext/mod.rs +++ b/src/libstd/sys/redox/ext/mod.rs @@ -44,7 +44,7 @@ pub mod prelude { #[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}; + pub use super::fs::{FileTypeExt, PermissionsExt, OpenOptionsExt, MetadataExt}; #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] pub use super::process::{CommandExt, ExitStatusExt}; } diff --git a/src/libstd/sys/redox/ext/process.rs b/src/libstd/sys/redox/ext/process.rs index f8e6b2cf4709d..3a7c59d4e6d09 100644 --- a/src/libstd/sys/redox/ext/process.rs +++ b/src/libstd/sys/redox/ext/process.rs @@ -86,12 +86,12 @@ pub trait CommandExt { #[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.as_inner_mut().uid(id); self } fn gid(&mut self, id: u32) -> &mut process::Command { - self.as_inner_mut().gid(id as usize); + self.as_inner_mut().gid(id); self } diff --git a/src/libstd/sys/redox/fd.rs b/src/libstd/sys/redox/fd.rs index b716965860e1d..4c8e62d1863b6 100644 --- a/src/libstd/sys/redox/fd.rs +++ b/src/libstd/sys/redox/fd.rs @@ -11,9 +11,8 @@ #![unstable(reason = "not public", issue = "0", feature = "fd")] use io::{self, Read}; -use libc; use mem; -use sys::cvt; +use sys::{cvt, syscall}; use sys_common::AsInner; use sys_common::io::read_to_end_uninitialized; @@ -36,7 +35,7 @@ impl FileDesc { } pub fn read(&self, buf: &mut [u8]) -> io::Result { - cvt(libc::read(self.fd, buf)) + cvt(syscall::read(self.fd, buf)) } pub fn read_to_end(&self, buf: &mut Vec) -> io::Result { @@ -45,33 +44,33 @@ impl FileDesc { } pub fn write(&self, buf: &[u8]) -> io::Result { - cvt(libc::write(self.fd, buf)) + cvt(syscall::write(self.fd, buf)) } pub fn duplicate(&self) -> io::Result { - let new_fd = cvt(libc::dup(self.fd, &[]))?; + let new_fd = cvt(syscall::dup(self.fd, &[]))?; Ok(FileDesc::new(new_fd)) } pub fn nonblocking(&self) -> io::Result { - let flags = cvt(libc::fcntl(self.fd, libc::F_GETFL, 0))?; - Ok(flags & libc::O_NONBLOCK == libc::O_NONBLOCK) + let flags = cvt(syscall::fcntl(self.fd, syscall::F_GETFL, 0))?; + Ok(flags & syscall::O_NONBLOCK == syscall::O_NONBLOCK) } pub fn set_cloexec(&self) -> io::Result<()> { - let mut flags = cvt(libc::fcntl(self.fd, libc::F_GETFL, 0))?; - flags |= libc::O_CLOEXEC; - cvt(libc::fcntl(self.fd, libc::F_SETFL, flags)).and(Ok(())) + let mut flags = cvt(syscall::fcntl(self.fd, syscall::F_GETFL, 0))?; + flags |= syscall::O_CLOEXEC; + cvt(syscall::fcntl(self.fd, syscall::F_SETFL, flags)).and(Ok(())) } pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { - let mut flags = cvt(libc::fcntl(self.fd, libc::F_GETFL, 0))?; + let mut flags = cvt(syscall::fcntl(self.fd, syscall::F_GETFL, 0))?; if nonblocking { - flags |= libc::O_NONBLOCK; + flags |= syscall::O_NONBLOCK; } else { - flags &= !libc::O_NONBLOCK; + flags &= !syscall::O_NONBLOCK; } - cvt(libc::fcntl(self.fd, libc::F_SETFL, flags)).and(Ok(())) + cvt(syscall::fcntl(self.fd, syscall::F_SETFL, flags)).and(Ok(())) } } @@ -96,6 +95,6 @@ impl Drop for FileDesc { // 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 _ = libc::close(self.fd); + let _ = syscall::close(self.fd); } } diff --git a/src/libstd/sys/redox/fs.rs b/src/libstd/sys/redox/fs.rs index 12aa17becd860..80aec2e978dd0 100644 --- a/src/libstd/sys/redox/fs.rs +++ b/src/libstd/sys/redox/fs.rs @@ -13,21 +13,18 @@ use os::unix::prelude::*; use ffi::{OsString, OsStr}; use fmt; use io::{self, Error, ErrorKind, SeekFrom}; -use libc::{self, c_int, mode_t}; use path::{Path, PathBuf}; use sync::Arc; use sys::fd::FileDesc; use sys::time::SystemTime; -use sys::cvt; +use sys::{cvt, syscall}; use sys_common::{AsInner, FromInner}; -use libc::{stat, fstat, fsync, ftruncate, lseek, open}; - pub struct File(FileDesc); #[derive(Clone)] pub struct FileAttr { - stat: stat, + stat: syscall::Stat, } pub struct ReadDir { @@ -57,53 +54,53 @@ pub struct OpenOptions { create_new: bool, // system-specific custom_flags: i32, - mode: mode_t, + mode: u16, } #[derive(Clone, PartialEq, Eq, Debug)] -pub struct FilePermissions { mode: mode_t } +pub struct FilePermissions { mode: u16 } #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] -pub struct FileType { mode: mode_t } +pub struct FileType { mode: u16 } -pub struct DirBuilder { mode: mode_t } +pub struct DirBuilder { mode: u16 } impl FileAttr { pub fn size(&self) -> u64 { self.stat.st_size as u64 } pub fn perm(&self) -> FilePermissions { - FilePermissions { mode: (self.stat.st_mode as mode_t) & 0o777 } + FilePermissions { mode: (self.stat.st_mode as u16) & 0o777 } } pub fn file_type(&self) -> FileType { - FileType { mode: self.stat.st_mode as mode_t } + FileType { mode: self.stat.st_mode as u16 } } } impl FileAttr { pub fn modified(&self) -> io::Result { - Ok(SystemTime::from(libc::timespec { - tv_sec: self.stat.st_mtime as libc::time_t, + Ok(SystemTime::from(syscall::TimeSpec { + tv_sec: self.stat.st_mtime as i64, tv_nsec: self.stat.st_mtime_nsec as i32, })) } pub fn accessed(&self) -> io::Result { - Ok(SystemTime::from(libc::timespec { - tv_sec: self.stat.st_atime as libc::time_t, + Ok(SystemTime::from(syscall::TimeSpec { + tv_sec: self.stat.st_atime as i64, tv_nsec: self.stat.st_atime_nsec as i32, })) } pub fn created(&self) -> io::Result { - Ok(SystemTime::from(libc::timespec { - tv_sec: self.stat.st_ctime as libc::time_t, + Ok(SystemTime::from(syscall::TimeSpec { + tv_sec: self.stat.st_ctime as i64, tv_nsec: self.stat.st_ctime_nsec as i32, })) } } -impl AsInner for FileAttr { - fn as_inner(&self) -> &stat { &self.stat } +impl AsInner for FileAttr { + fn as_inner(&self) -> &syscall::Stat { &self.stat } } impl FilePermissions { @@ -119,16 +116,16 @@ impl FilePermissions { } 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_dir(&self) -> bool { self.is(syscall::MODE_DIR) } + pub fn is_file(&self) -> bool { self.is(syscall::MODE_FILE) } pub fn is_symlink(&self) -> bool { false } - pub fn is(&self, mode: mode_t) -> bool { self.mode & (libc::MODE_DIR | libc::MODE_FILE) == mode } + pub fn is(&self, mode: u16) -> bool { self.mode & (syscall::MODE_DIR | syscall::MODE_FILE) == mode } } impl FromInner for FilePermissions { fn from_inner(mode: u32) -> FilePermissions { - FilePermissions { mode: mode as mode_t } + FilePermissions { mode: mode as u16 } } } @@ -215,60 +212,60 @@ impl OpenOptions { 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; } + pub fn mode(&mut self, mode: u32) { self.mode = mode as u16; } - fn get_access_mode(&self) -> io::Result { + fn get_access_mode(&self) -> io::Result { 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)), + (true, false, false) => Ok(syscall::O_RDONLY), + (false, true, false) => Ok(syscall::O_WRONLY), + (true, true, false) => Ok(syscall::O_RDWR), + (false, _, true) => Ok(syscall::O_WRONLY | syscall::O_APPEND), + (true, _, true) => Ok(syscall::O_RDWR | syscall::O_APPEND), + (false, false, false) => Err(Error::from_raw_os_error(syscall::EINVAL)), } } - fn get_creation_mode(&self) -> io::Result { + fn get_creation_mode(&self) -> io::Result { 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)); + return Err(Error::from_raw_os_error(syscall::EINVAL)); }, (_, true) => if self.truncate && !self.create_new { - return Err(Error::from_raw_os_error(libc::EINVAL)); + return Err(Error::from_raw_os_error(syscall::EINVAL)); }, } Ok(match (self.create, self.truncate, self.create_new) { (false, false, false) => 0, - (true, false, false) => 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, + (true, false, false) => syscall::O_CREAT, + (false, true, false) => syscall::O_TRUNC, + (true, true, false) => syscall::O_CREAT | syscall::O_TRUNC, + (_, _, true) => syscall::O_CREAT | syscall::O_EXCL, }) } } impl File { pub fn open(path: &Path, opts: &OpenOptions) -> io::Result { - let flags = libc::O_CLOEXEC | + let flags = syscall::O_CLOEXEC | opts.get_access_mode()? as usize | opts.get_creation_mode()? as usize | - (opts.custom_flags as usize & !libc::O_ACCMODE); - let fd = cvt(open(path.to_str().unwrap(), flags | opts.mode as usize))?; + (opts.custom_flags as usize & !syscall::O_ACCMODE); + let fd = cvt(syscall::open(path.to_str().unwrap(), flags | opts.mode as usize))?; Ok(File(FileDesc::new(fd))) } pub fn file_attr(&self) -> io::Result { - let mut stat: stat = stat::default(); - cvt(fstat(self.0.raw(), &mut stat))?; + let mut stat = syscall::Stat::default(); + cvt(syscall::fstat(self.0.raw(), &mut stat))?; Ok(FileAttr { stat: stat }) } pub fn fsync(&self) -> io::Result<()> { - cvt(fsync(self.0.raw()))?; + cvt(syscall::fsync(self.0.raw()))?; Ok(()) } @@ -277,7 +274,7 @@ impl File { } pub fn truncate(&self, size: u64) -> io::Result<()> { - cvt(ftruncate(self.0.raw(), size as usize))?; + cvt(syscall::ftruncate(self.0.raw(), size as usize))?; Ok(()) } @@ -299,11 +296,11 @@ impl File { 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), + SeekFrom::Start(off) => (syscall::SEEK_SET, off as i64), + SeekFrom::End(off) => (syscall::SEEK_END, off), + SeekFrom::Current(off) => (syscall::SEEK_CUR, off), }; - let n = cvt(lseek(self.0.raw(), pos as isize, whence))?; + let n = cvt(syscall::lseek(self.0.raw(), pos as isize, whence))?; Ok(n as u64) } @@ -312,7 +309,7 @@ impl File { } pub fn dup(&self, buf: &[u8]) -> io::Result { - let fd = cvt(libc::dup(*self.fd().as_inner() as usize, buf))?; + let fd = cvt(syscall::dup(*self.fd().as_inner() as usize, buf))?; Ok(File(FileDesc::new(fd))) } @@ -322,7 +319,7 @@ impl File { pub fn path(&self) -> io::Result { let mut buf: [u8; 4096] = [0; 4096]; - match libc::fpath(*self.fd().as_inner() as usize, &mut buf) { + match syscall::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)), } @@ -339,13 +336,13 @@ impl DirBuilder { } pub fn mkdir(&self, p: &Path) -> io::Result<()> { - let fd = cvt(libc::open(p.to_str().unwrap(), libc::O_CREAT | libc::O_DIRECTORY | libc::O_EXCL | (self.mode as usize & 0o777)))?; - let _ = libc::close(fd); + let fd = cvt(syscall::open(p.to_str().unwrap(), syscall::O_CREAT | syscall::O_DIRECTORY | syscall::O_EXCL | (self.mode as usize & 0o777)))?; + let _ = syscall::close(fd); Ok(()) } pub fn set_mode(&mut self, mode: u32) { - self.mode = mode as mode_t; + self.mode = mode as u16; } } @@ -374,7 +371,7 @@ impl fmt::Debug for File { pub fn readdir(p: &Path) -> io::Result { let root = Arc::new(p.to_path_buf()); - let fd = cvt(open(p.to_str().unwrap(), libc::O_CLOEXEC | libc::O_RDONLY | libc::O_DIRECTORY))?; + let fd = cvt(syscall::open(p.to_str().unwrap(), syscall::O_CLOEXEC | syscall::O_RDONLY | syscall::O_DIRECTORY))?; let file = FileDesc::new(fd); let mut data = Vec::new(); file.read_to_end(&mut data)?; @@ -383,7 +380,7 @@ pub fn readdir(p: &Path) -> io::Result { } pub fn unlink(p: &Path) -> io::Result<()> { - cvt(libc::unlink(p.to_str().unwrap()))?; + cvt(syscall::unlink(p.to_str().unwrap()))?; Ok(()) } @@ -393,12 +390,12 @@ pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> { } pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> { - cvt(libc::chmod(p.to_str().unwrap(), perm.mode as usize))?; + cvt(syscall::chmod(p.to_str().unwrap(), perm.mode as usize))?; Ok(()) } pub fn rmdir(p: &Path) -> io::Result<()> { - cvt(libc::rmdir(p.to_str().unwrap()))?; + cvt(syscall::rmdir(p.to_str().unwrap()))?; Ok(()) } @@ -438,13 +435,9 @@ pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> { } pub fn stat(p: &Path) -> io::Result { - let mut stat: stat = stat::default(); - - let fd = cvt(open(p.to_str().unwrap(), libc::O_CLOEXEC | libc::O_STAT))?; - cvt(fstat(fd, &mut stat))?; - let _ = libc::close(fd); - - Ok(FileAttr { stat: stat }) + let fd = cvt(syscall::open(p.to_str().unwrap(), syscall::O_CLOEXEC | syscall::O_STAT))?; + let file = File(FileDesc::new(fd)); + file.file_attr() } pub fn lstat(p: &Path) -> io::Result { @@ -452,7 +445,7 @@ pub fn lstat(p: &Path) -> io::Result { } pub fn canonicalize(p: &Path) -> io::Result { - let fd = cvt(open(p.to_str().unwrap(), libc::O_CLOEXEC | libc::O_STAT))?; + let fd = cvt(syscall::open(p.to_str().unwrap(), syscall::O_CLOEXEC | syscall::O_STAT))?; let file = File(FileDesc::new(fd)); file.path() } diff --git a/src/libstd/sys/redox/mod.rs b/src/libstd/sys/redox/mod.rs index 3f3d8f2c4f41b..07ead22b7a892 100644 --- a/src/libstd/sys/redox/mod.rs +++ b/src/libstd/sys/redox/mod.rs @@ -1,7 +1,8 @@ #![allow(dead_code, missing_docs, bad_style)] +pub extern crate syscall; + use io::{self, ErrorKind}; -use libc; pub mod args; pub mod backtrace; @@ -42,40 +43,40 @@ pub fn init() { use intrinsics; let msg = "fatal runtime error: out of memory\n"; unsafe { - let _ = libc::write(libc::STDERR_FILENO, msg.as_bytes()); + let _ = syscall::write(2, msg.as_bytes()); 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, + match errno { + syscall::ECONNREFUSED => ErrorKind::ConnectionRefused, + syscall::ECONNRESET => ErrorKind::ConnectionReset, + syscall::EPERM | syscall::EACCES => ErrorKind::PermissionDenied, + syscall::EPIPE => ErrorKind::BrokenPipe, + syscall::ENOTCONN => ErrorKind::NotConnected, + syscall::ECONNABORTED => ErrorKind::ConnectionAborted, + syscall::EADDRNOTAVAIL => ErrorKind::AddrNotAvailable, + syscall::EADDRINUSE => ErrorKind::AddrInUse, + syscall::ENOENT => ErrorKind::NotFound, + syscall::EINTR => ErrorKind::Interrupted, + syscall::EINVAL => ErrorKind::InvalidInput, + syscall::ETIMEDOUT => ErrorKind::TimedOut, + syscall::EEXIST => ErrorKind::AlreadyExists, // These two constants can have the same value on some systems, // but different values on others, so we can't use a match // clause - x if x == libc::EAGAIN || x == libc::EWOULDBLOCK => + x if x == syscall::EAGAIN || x == syscall::EWOULDBLOCK => ErrorKind::WouldBlock, _ => ErrorKind::Other, } } -pub fn cvt(result: Result) -> io::Result { - result.map_err(|err| io::Error::from_raw_os_error(err.errno as i32)) +pub fn cvt(result: Result) -> io::Result { + result.map_err(|err| io::Error::from_raw_os_error(err.errno)) } /// On Redox, use an illegal instruction to abort diff --git a/src/libstd/sys/redox/mutex.rs b/src/libstd/sys/redox/mutex.rs index 4c2b0de8bd94b..42424da858fbc 100644 --- a/src/libstd/sys/redox/mutex.rs +++ b/src/libstd/sys/redox/mutex.rs @@ -2,7 +2,7 @@ use cell::UnsafeCell; use intrinsics::{atomic_cxchg, atomic_xchg}; use ptr; -use libc::{futex, getpid, FUTEX_WAIT, FUTEX_WAKE}; +use sys::syscall::{futex, getpid, FUTEX_WAIT, FUTEX_WAKE}; pub unsafe fn mutex_try_lock(m: *mut i32) -> bool { atomic_cxchg(m, 0, 1).0 == 0 diff --git a/src/libstd/sys/redox/net/mod.rs b/src/libstd/sys/redox/net/mod.rs index 1c8fde546efb4..92c7d72887bf0 100644 --- a/src/libstd/sys/redox/net/mod.rs +++ b/src/libstd/sys/redox/net/mod.rs @@ -4,7 +4,7 @@ use iter::Iterator; use net::{Ipv4Addr, SocketAddr, SocketAddrV4}; use str::FromStr; use string::{String, ToString}; -use libc::EINVAL; +use sys::syscall::EINVAL; use time; use vec::{IntoIter, Vec}; diff --git a/src/libstd/sys/redox/os.rs b/src/libstd/sys/redox/os.rs index e007e33258f61..9ebbae4199b78 100644 --- a/src/libstd/sys/redox/os.rs +++ b/src/libstd/sys/redox/os.rs @@ -19,7 +19,6 @@ use ffi::{OsString, OsStr}; use fmt; use io::{self, Read, Write}; use iter; -use libc::{self, c_int, c_char, c_void}; use marker::PhantomData; use mem; use memchr; @@ -28,8 +27,7 @@ use ptr; use slice; use str; use sys_common::mutex::Mutex; -use sys::cvt; -use sys::fd; +use sys::{cvt, fd, syscall}; use vec; const TMPBUF_SZ: usize = 128; @@ -42,7 +40,7 @@ pub fn errno() -> i32 { /// Gets a detailed string description for the given error number. pub fn error_string(errno: i32) -> String { - if let Some(string) = libc::STR_ERROR.get(errno as usize) { + if let Some(string) = syscall::STR_ERROR.get(errno as usize) { string.to_string() } else { "unknown error".to_string() @@ -51,12 +49,12 @@ pub fn error_string(errno: i32) -> String { pub fn getcwd() -> io::Result { let mut buf = [0; 4096]; - let count = cvt(libc::getcwd(&mut buf))?; + let count = cvt(syscall::getcwd(&mut buf))?; Ok(PathBuf::from(OsString::from_vec(buf[.. count].to_vec()))) } pub fn chdir(p: &path::Path) -> io::Result<()> { - cvt(libc::chdir(p.to_str().unwrap())).and(Ok(())) + cvt(syscall::chdir(p.to_str().unwrap())).and(Ok(())) } pub struct SplitPaths<'a> { @@ -200,6 +198,6 @@ pub fn home_dir() -> Option { } pub fn exit(code: i32) -> ! { - let _ = libc::exit(code as usize); + let _ = syscall::exit(code as usize); unreachable!(); } diff --git a/src/libstd/sys/redox/pipe.rs b/src/libstd/sys/redox/pipe.rs index fff4a10f913d2..7f192bef495a9 100644 --- a/src/libstd/sys/redox/pipe.rs +++ b/src/libstd/sys/redox/pipe.rs @@ -9,7 +9,7 @@ // except according to those terms. use io; -use libc; +use sys::syscall; use sys::fd::FileDesc; //////////////////////////////////////////////////////////////////////////////// @@ -21,7 +21,7 @@ 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))?; + syscall::pipe2(&mut fds, syscall::O_CLOEXEC).map_err(|err| io::Error::from_raw_os_error(err.errno))?; Ok((AnonPipe(FileDesc::new(fds[0])), AnonPipe(FileDesc::new(fds[1])))) } diff --git a/src/libstd/sys/redox/process.rs b/src/libstd/sys/redox/process.rs index 269aa6bedac0f..3c0d96913285d 100644 --- a/src/libstd/sys/redox/process.rs +++ b/src/libstd/sys/redox/process.rs @@ -13,12 +13,11 @@ use env; use ffi::OsStr; use fmt; use io::{self, Error, ErrorKind}; -use libc::{self, pid_t, gid_t, uid_t}; use path::Path; use sys::fd::FileDesc; use sys::fs::{File, OpenOptions}; use sys::pipe::{self, AnonPipe}; -use sys::cvt; +use sys::{cvt, syscall}; //////////////////////////////////////////////////////////////////////////////// // Command @@ -47,8 +46,8 @@ pub struct Command { env: HashMap, cwd: Option, - uid: Option, - gid: Option, + uid: Option, + gid: Option, saw_nul: bool, closures: Vec io::Result<()> + Send + Sync>>, stdin: Option, @@ -121,10 +120,10 @@ impl Command { pub fn cwd(&mut self, dir: &OsStr) { self.cwd = Some(dir.to_str().unwrap().to_owned()); } - pub fn uid(&mut self, id: uid_t) { + pub fn uid(&mut self, id: u32) { self.uid = Some(id); } - pub fn gid(&mut self, id: gid_t) { + pub fn gid(&mut self, id: u32) { self.gid = Some(id); } @@ -156,11 +155,11 @@ impl Command { let (input, output) = pipe::anon_pipe()?; let pid = unsafe { - match cvt(libc::clone(0))? { + match cvt(syscall::clone(0))? { 0 => { drop(input); let err = self.do_exec(theirs); - let errno = err.raw_os_error().unwrap_or(libc::EINVAL) as u32; + let errno = err.raw_os_error().unwrap_or(syscall::EINVAL) as u32; let bytes = [ (errno >> 24) as u8, (errno >> 16) as u8, @@ -173,7 +172,7 @@ impl Command { // we want to be sure we *don't* run at_exit destructors as // we're being torn down regardless assert!(output.write(&bytes).is_ok()); - let _ = libc::exit(1); + let _ = syscall::exit(1); panic!("failed to exit"); } n => n, @@ -261,7 +260,7 @@ impl Command { // 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) + // child will either exec() or invoke syscall::exit) unsafe fn do_exec(&mut self, stdio: ChildPipes) -> io::Error { macro_rules! t { ($e:expr) => (match $e { @@ -271,29 +270,29 @@ impl Command { } if let Some(fd) = stdio.stderr.fd() { - let _ = libc::close(libc::STDERR_FILENO); - t!(cvt(libc::dup(fd, &[]))); - let _ = libc::close(fd); + let _ = syscall::close(2); + t!(cvt(syscall::dup(fd, &[]))); + let _ = syscall::close(fd); } if let Some(fd) = stdio.stdout.fd() { - let _ = libc::close(libc::STDOUT_FILENO); - t!(cvt(libc::dup(fd, &[]))); - let _ = libc::close(fd); + let _ = syscall::close(1); + t!(cvt(syscall::dup(fd, &[]))); + let _ = syscall::close(fd); } if let Some(fd) = stdio.stdin.fd() { - let _ = libc::close(libc::STDIN_FILENO); - t!(cvt(libc::dup(fd, &[]))); - let _ = libc::close(fd); + let _ = syscall::close(0); + t!(cvt(syscall::dup(fd, &[]))); + let _ = syscall::close(fd); } if let Some(g) = self.gid { - t!(cvt(libc::setregid(g, g))); + t!(cvt(syscall::setregid(g as usize, g as usize))); } if let Some(u) = self.uid { - t!(cvt(libc::setreuid(u, u))); + t!(cvt(syscall::setreuid(u as usize, u as usize))); } if let Some(ref cwd) = self.cwd { - t!(cvt(libc::chdir(cwd))); + t!(cvt(syscall::chdir(cwd))); } for callback in self.closures.iter_mut() { @@ -324,7 +323,7 @@ impl Command { path_env }; - if let Err(err) = libc::exec(&program, &args) { + if let Err(err) = syscall::execve(&program, &args) { io::Error::from_raw_os_error(err.errno as i32) } else { panic!("return from exec without err"); @@ -370,7 +369,7 @@ impl Stdio { // stderr. No matter which we dup first, the second will get // overwritten prematurely. Stdio::Fd(ref fd) => { - if fd.raw() <= libc::STDERR_FILENO { + if fd.raw() <= 2 { Ok((ChildStdio::Owned(fd.duplicate()?), None)) } else { Ok((ChildStdio::Explicit(fd.raw()), None)) @@ -471,7 +470,7 @@ impl fmt::Display for ExitStatus { /// The unique id of the process (this should never be negative). pub struct Process { - pid: pid_t, + pid: usize, status: Option, } @@ -488,7 +487,7 @@ impl Process { Err(Error::new(ErrorKind::InvalidInput, "invalid argument: can't kill an exited process")) } else { - cvt(libc::kill(self.pid, libc::SIGKILL))?; + cvt(syscall::kill(self.pid, syscall::SIGKILL))?; Ok(()) } } @@ -498,7 +497,7 @@ impl Process { return Ok(status) } let mut status = 0; - cvt(libc::waitpid(self.pid, &mut status, 0))?; + cvt(syscall::waitpid(self.pid, &mut status, 0))?; self.status = Some(ExitStatus(status as i32)); Ok(ExitStatus(status as i32)) } diff --git a/src/libstd/sys/redox/stdio.rs b/src/libstd/sys/redox/stdio.rs index 5006218690336..1fe7e33a35ecd 100644 --- a/src/libstd/sys/redox/stdio.rs +++ b/src/libstd/sys/redox/stdio.rs @@ -9,8 +9,7 @@ // except according to those terms. use io; -use libc; -use sys::cvt; +use sys::{cvt, syscall}; use sys::fd::FileDesc; pub struct Stdin(()); @@ -21,14 +20,14 @@ impl Stdin { pub fn new() -> io::Result { Ok(Stdin(())) } pub fn read(&self, data: &mut [u8]) -> io::Result { - let fd = FileDesc::new(libc::STDIN_FILENO); + let fd = FileDesc::new(0); let ret = fd.read(data); fd.into_raw(); ret } pub fn read_to_end(&self, buf: &mut Vec) -> io::Result { - let fd = FileDesc::new(libc::STDIN_FILENO); + let fd = FileDesc::new(0); let ret = fd.read_to_end(buf); fd.into_raw(); ret @@ -39,14 +38,14 @@ impl Stdout { pub fn new() -> io::Result { Ok(Stdout(())) } pub fn write(&self, data: &[u8]) -> io::Result { - let fd = FileDesc::new(libc::STDOUT_FILENO); + let fd = FileDesc::new(1); let ret = fd.write(data); fd.into_raw(); ret } pub fn flush(&self) -> io::Result<()> { - cvt(libc::fsync(libc::STDOUT_FILENO)).and(Ok(())) + cvt(syscall::fsync(1)).and(Ok(())) } } @@ -54,14 +53,14 @@ impl Stderr { pub fn new() -> io::Result { Ok(Stderr(())) } pub fn write(&self, data: &[u8]) -> io::Result { - let fd = FileDesc::new(libc::STDERR_FILENO); + let fd = FileDesc::new(2); let ret = fd.write(data); fd.into_raw(); ret } pub fn flush(&self) -> io::Result<()> { - cvt(libc::fsync(libc::STDERR_FILENO)).and(Ok(())) + cvt(syscall::fsync(2)).and(Ok(())) } } @@ -74,9 +73,9 @@ impl io::Write for Stderr { } fn flush(&mut self) -> io::Result<()> { - cvt(libc::fsync(libc::STDERR_FILENO)).and(Ok(())) + cvt(syscall::fsync(2)).and(Ok(())) } } -pub const EBADF_ERR: i32 = ::libc::EBADF; +pub const EBADF_ERR: i32 = ::sys::syscall::EBADF; pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE; diff --git a/src/libstd/sys/redox/thread.rs b/src/libstd/sys/redox/thread.rs index 46bc6346a6a80..0e7b27d396107 100644 --- a/src/libstd/sys/redox/thread.rs +++ b/src/libstd/sys/redox/thread.rs @@ -9,17 +9,15 @@ // except according to those terms. use alloc::boxed::FnBox; -use cmp; use ffi::CStr; use io; -use libc; use mem; use sys_common::thread::start_thread; -use sys::cvt; +use sys::{cvt, syscall}; use time::Duration; pub struct Thread { - id: libc::pid_t, + id: usize, } // Some platforms may have pthread_t as a pointer in which case we still want @@ -31,10 +29,10 @@ impl Thread { pub unsafe fn new<'a>(_stack: usize, p: Box) -> io::Result { let p = box p; - let id = cvt(libc::clone(libc::CLONE_VM | libc::CLONE_FS | libc::CLONE_FILES))?; + let id = cvt(syscall::clone(syscall::CLONE_VM | syscall::CLONE_FS | syscall::CLONE_FILES))?; if id == 0 { start_thread(&*p as *const _ as *mut _); - let _ = libc::exit(0); + let _ = syscall::exit(0); panic!("thread failed to exit"); } else { mem::forget(p); @@ -43,7 +41,7 @@ impl Thread { } pub fn yield_now() { - let ret = unsafe { libc::sched_yield() }; + let ret = syscall::sched_yield().expect("failed to sched_yield"); debug_assert_eq!(ret, 0); } @@ -58,13 +56,13 @@ impl Thread { // If we're awoken with a signal then the return value will be -1 and // nanosleep will fill in `ts` with the remaining time. while secs > 0 || nsecs > 0 { - let req = libc::timespec { - tv_sec: cmp::min(libc::time_t::max_value() as u64, secs) as libc::time_t, + let req = syscall::TimeSpec { + tv_sec: secs as i64, tv_nsec: nsecs, }; secs -= req.tv_sec as u64; - let mut rem = libc::timespec::default(); - if libc::nanosleep(&req, &mut rem).is_err() { + let mut rem = syscall::TimeSpec::default(); + if syscall::nanosleep(&req, &mut rem).is_err() { secs += rem.tv_sec as u64; nsecs = rem.tv_nsec; } else { @@ -75,12 +73,12 @@ impl Thread { pub fn join(self) { let mut status = 0; - libc::waitpid(self.id, &mut status, 0).unwrap(); + syscall::waitpid(self.id, &mut status, 0).unwrap(); } - pub fn id(&self) -> libc::pid_t { self.id } + pub fn id(&self) -> usize { self.id } - pub fn into_id(self) -> libc::pid_t { + pub fn into_id(self) -> usize { let id = self.id; mem::forget(self); id diff --git a/src/libstd/sys/redox/time.rs b/src/libstd/sys/redox/time.rs index 4e1a82bcc9a09..8f05e3bcfe716 100644 --- a/src/libstd/sys/redox/time.rs +++ b/src/libstd/sys/redox/time.rs @@ -10,15 +10,14 @@ use cmp::Ordering; use fmt; -use libc; -use sys::cvt; +use sys::{cvt, syscall}; use time::Duration; const NSEC_PER_SEC: u64 = 1_000_000_000; #[derive(Copy, Clone)] struct Timespec { - t: libc::timespec, + t: syscall::TimeSpec, } impl Timespec { @@ -53,8 +52,8 @@ impl Timespec { duration to time"); } Timespec { - t: libc::timespec { - tv_sec: secs as libc::time_t, + t: syscall::TimeSpec { + tv_sec: secs as i64, tv_nsec: nsec as i32, }, } @@ -73,8 +72,8 @@ impl Timespec { duration from time"); } Timespec { - t: libc::timespec { - tv_sec: secs as libc::time_t, + t: syscall::TimeSpec { + tv_sec: secs as i64, tv_nsec: nsec as i32, }, } @@ -115,7 +114,7 @@ pub struct SystemTime { pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec { - t: libc::timespec { + t: syscall::TimeSpec { tv_sec: 0, tv_nsec: 0, }, @@ -124,7 +123,7 @@ pub const UNIX_EPOCH: SystemTime = SystemTime { impl Instant { pub fn now() -> Instant { - Instant { t: now(libc::CLOCK_MONOTONIC) } + Instant { t: now(syscall::CLOCK_MONOTONIC) } } pub fn sub_instant(&self, other: &Instant) -> Duration { @@ -153,7 +152,7 @@ impl fmt::Debug for Instant { impl SystemTime { pub fn now() -> SystemTime { - SystemTime { t: now(libc::CLOCK_REALTIME) } + SystemTime { t: now(syscall::CLOCK_REALTIME) } } pub fn sub_time(&self, other: &SystemTime) @@ -170,8 +169,8 @@ impl SystemTime { } } -impl From for SystemTime { - fn from(t: libc::timespec) -> SystemTime { +impl From for SystemTime { + fn from(t: syscall::TimeSpec) -> SystemTime { SystemTime { t: Timespec { t: t } } } } @@ -189,11 +188,11 @@ pub type clock_t = usize; fn now(clock: clock_t) -> Timespec { let mut t = Timespec { - t: libc::timespec { + t: syscall::TimeSpec { tv_sec: 0, tv_nsec: 0, } }; - cvt(libc::clock_gettime(clock, &mut t.t)).unwrap(); + cvt(syscall::clock_gettime(clock, &mut t.t)).unwrap(); t } From 2ec21327f25e4646ce64a2e331bb4702cf96dc99 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 28 Nov 2016 18:19:17 -0700 Subject: [PATCH 27/34] Switch to using Prefix::Verbatim --- src/libstd/path.rs | 8 +++----- src/libstd/sys/redox/path.rs | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 8bf9bbb13208b..e38cff179c3b4 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -148,10 +148,6 @@ use sys::path::{is_sep_byte, is_verbatim_sep, MAIN_SEP_STR, parse_prefix}; #[derive(Copy, Clone, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)] #[stable(feature = "rust1", since = "1.0.0")] pub enum Prefix<'a> { - /// Prefix `scheme:`, where `scheme` is the component stored - #[unstable(feature="redox_prefix", issue="0")] - Scheme(&'a OsStr), - /// Prefix `\\?\`, together with the given component immediately following it. #[stable(feature = "rust1", since = "1.0.0")] Verbatim(#[stable(feature = "rust1", since = "1.0.0")] &'a OsStr), @@ -191,7 +187,9 @@ impl<'a> Prefix<'a> { os_str_as_u8_slice(s).len() } match *self { - Scheme(x) => os_str_len(x) + 1, + #[cfg(target_os = "redox")] + Verbatim(x) => 1 + os_str_len(x), + #[cfg(not(target_os = "redox"))] Verbatim(x) => 4 + os_str_len(x), VerbatimUNC(x, y) => { 8 + os_str_len(x) + diff --git a/src/libstd/sys/redox/path.rs b/src/libstd/sys/redox/path.rs index 4069a0ea726f9..e609f83bc0721 100644 --- a/src/libstd/sys/redox/path.rs +++ b/src/libstd/sys/redox/path.rs @@ -24,7 +24,7 @@ pub fn is_verbatim_sep(b: u8) -> bool { pub fn parse_prefix(path: &OsStr) -> Option { if let Some(path_str) = path.to_str() { if let Some(i) = path_str.find(':') { - Some(Prefix::Scheme(OsStr::new(&path_str[..i]))) + Some(Prefix::Verbatim(OsStr::new(&path_str[..i]))) } else { None } From 1d0bba8224686d054378bcc4e853798d56fdfecf Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 28 Nov 2016 18:25:47 -0700 Subject: [PATCH 28/34] Move stdout/err flush into sys --- src/libstd/io/stdio.rs | 6 ------ src/libstd/sys/redox/stdio.rs | 2 +- src/libstd/sys/unix/stdio.rs | 13 ++++++++++++- src/libstd/sys/windows/stdio.rs | 13 ++++++++++++- 4 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index f6ee0be47fad7..6419a9ff683de 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -81,16 +81,10 @@ impl Read for StdinRaw { } impl Write for StdoutRaw { fn write(&mut self, buf: &[u8]) -> io::Result { self.0.write(buf) } - #[cfg(not(target_os = "redox"))] - fn flush(&mut self) -> io::Result<()> { Ok(()) } - #[cfg(target_os = "redox")] fn flush(&mut self) -> io::Result<()> { self.0.flush() } } impl Write for StderrRaw { fn write(&mut self, buf: &[u8]) -> io::Result { self.0.write(buf) } - #[cfg(not(target_os = "redox"))] - fn flush(&mut self) -> io::Result<()> { Ok(()) } - #[cfg(target_os = "redox")] fn flush(&mut self) -> io::Result<()> { self.0.flush() } } diff --git a/src/libstd/sys/redox/stdio.rs b/src/libstd/sys/redox/stdio.rs index 1fe7e33a35ecd..aa8329bc28386 100644 --- a/src/libstd/sys/redox/stdio.rs +++ b/src/libstd/sys/redox/stdio.rs @@ -73,7 +73,7 @@ impl io::Write for Stderr { } fn flush(&mut self) -> io::Result<()> { - cvt(syscall::fsync(2)).and(Ok(())) + Stderr::flush(self) } } diff --git a/src/libstd/sys/unix/stdio.rs b/src/libstd/sys/unix/stdio.rs index 273341b1918d1..1002c60d30337 100644 --- a/src/libstd/sys/unix/stdio.rs +++ b/src/libstd/sys/unix/stdio.rs @@ -43,6 +43,10 @@ impl Stdout { fd.into_raw(); ret } + + pub fn flush(&self) -> io::Result<()> { + Ok(()) + } } impl Stderr { @@ -54,6 +58,10 @@ impl Stderr { fd.into_raw(); ret } + + pub fn flush(&self) -> io::Result<()> { + Ok(()) + } } // FIXME: right now this raw stderr handle is used in a few places because @@ -63,7 +71,10 @@ impl io::Write for Stderr { fn write(&mut self, data: &[u8]) -> io::Result { Stderr::write(self, data) } - fn flush(&mut self) -> io::Result<()> { Ok(()) } + + fn flush(&mut self) -> io::Result<()> { + Stderr::flush(self) + } } pub const EBADF_ERR: i32 = ::libc::EBADF as i32; diff --git a/src/libstd/sys/windows/stdio.rs b/src/libstd/sys/windows/stdio.rs index 72788776dedd6..0d58da29323ed 100644 --- a/src/libstd/sys/windows/stdio.rs +++ b/src/libstd/sys/windows/stdio.rs @@ -156,6 +156,10 @@ impl Stdout { pub fn write(&self, data: &[u8]) -> io::Result { write(&self.0, data) } + + pub fn flush(&self) -> io::Result<()> { + Ok(()) + } } impl Stderr { @@ -166,6 +170,10 @@ impl Stderr { pub fn write(&self, data: &[u8]) -> io::Result { write(&self.0, data) } + + pub fn flush(&self) -> io::Result<()> { + Ok(()) + } } // FIXME: right now this raw stderr handle is used in a few places because @@ -175,7 +183,10 @@ impl io::Write for Stderr { fn write(&mut self, data: &[u8]) -> io::Result { Stderr::write(self, data) } - fn flush(&mut self) -> io::Result<()> { Ok(()) } + + fn flush(&mut self) -> io::Result<()> { + Stderr::flush(self) + } } impl NoClose { From 6378c77716aa66a12af0fb41abf3dc000b81c2c7 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 28 Nov 2016 20:21:19 -0700 Subject: [PATCH 29/34] Remove file path from std::fs::File --- src/libstd/fs.rs | 10 ---------- src/libstd/sys/redox/fs.rs | 6 ++---- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/src/libstd/fs.rs b/src/libstd/fs.rs index 0cb9a49ad67b5..e91e808c5489a 100644 --- a/src/libstd/fs.rs +++ b/src/libstd/fs.rs @@ -383,16 +383,6 @@ impl File { pub fn set_permissions(&self, perm: Permissions) -> io::Result<()> { self.inner.set_permissions(perm.0) } - - /// Get the path that this file points to. - /// - /// This function is only implemented on Redox, but could be - /// implemented on other operating systems using readlink - #[cfg(target_os = "redox")] - #[unstable(feature = "file_path", issue="0")] - pub fn path(&self) -> io::Result { - self.inner.path() - } } impl AsInner for File { diff --git a/src/libstd/sys/redox/fs.rs b/src/libstd/sys/redox/fs.rs index 80aec2e978dd0..9d5d2f5d92108 100644 --- a/src/libstd/sys/redox/fs.rs +++ b/src/libstd/sys/redox/fs.rs @@ -319,10 +319,8 @@ impl File { pub fn path(&self) -> io::Result { let mut buf: [u8; 4096] = [0; 4096]; - match syscall::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)), - } + let count = cvt(syscall::fpath(*self.fd().as_inner() as usize, &mut buf))?; + Ok(PathBuf::from(unsafe { String::from_utf8_unchecked(Vec::from(&buf[..count])) })) } pub fn fd(&self) -> &FileDesc { &self.0 } From e68393397a10255ed645cb70bcedd20e5cba691d Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 28 Nov 2016 21:06:42 -0700 Subject: [PATCH 30/34] Commit to fix make tidy --- src/libstd/sys/redox/args.rs | 2 +- src/libstd/sys/redox/backtrace.rs | 10 +++++++ src/libstd/sys/redox/condvar.rs | 10 +++++++ src/libstd/sys/redox/env.rs | 2 +- src/libstd/sys/redox/ext/fs.rs | 10 +++---- src/libstd/sys/redox/ext/io.rs | 2 +- src/libstd/sys/redox/ext/mod.rs | 2 +- src/libstd/sys/redox/ext/process.rs | 2 +- src/libstd/sys/redox/fast_thread_local.rs | 2 +- src/libstd/sys/redox/fd.rs | 2 +- src/libstd/sys/redox/fs.rs | 14 +++++---- src/libstd/sys/redox/mod.rs | 10 +++++++ src/libstd/sys/redox/mutex.rs | 10 +++++++ src/libstd/sys/redox/net/dns/answer.rs | 10 +++++++ src/libstd/sys/redox/net/dns/mod.rs | 10 +++++++ src/libstd/sys/redox/net/dns/query.rs | 10 +++++++ src/libstd/sys/redox/net/mod.rs | 35 ++++++++++++++++++----- src/libstd/sys/redox/net/tcp.rs | 10 +++++++ src/libstd/sys/redox/net/udp.rs | 10 +++++++ src/libstd/sys/redox/os.rs | 2 +- src/libstd/sys/redox/os_str.rs | 2 +- src/libstd/sys/redox/path.rs | 2 +- src/libstd/sys/redox/pipe.rs | 10 +++---- src/libstd/sys/redox/process.rs | 2 +- src/libstd/sys/redox/rand.rs | 2 +- src/libstd/sys/redox/rwlock.rs | 2 +- src/libstd/sys/redox/stack_overflow.rs | 4 +-- src/libstd/sys/redox/stdio.rs | 2 +- src/libstd/sys/redox/thread.rs | 2 +- src/libstd/sys/redox/thread_local.rs | 2 +- src/libstd/sys/redox/time.rs | 2 +- src/libstd/sys/unix/stdio.rs | 2 +- src/libstd/sys/windows/stdio.rs | 2 +- 33 files changed, 157 insertions(+), 44 deletions(-) diff --git a/src/libstd/sys/redox/args.rs b/src/libstd/sys/redox/args.rs index 52ba030e7c640..f6fea2f10761b 100644 --- a/src/libstd/sys/redox/args.rs +++ b/src/libstd/sys/redox/args.rs @@ -1,4 +1,4 @@ -// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // diff --git a/src/libstd/sys/redox/backtrace.rs b/src/libstd/sys/redox/backtrace.rs index 63e427694ae6a..6f53841502ad2 100644 --- a/src/libstd/sys/redox/backtrace.rs +++ b/src/libstd/sys/redox/backtrace.rs @@ -1,3 +1,13 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + use libc; use io; use sys_common::backtrace::output; diff --git a/src/libstd/sys/redox/condvar.rs b/src/libstd/sys/redox/condvar.rs index 7e26162efbc8e..0ca0987b245a2 100644 --- a/src/libstd/sys/redox/condvar.rs +++ b/src/libstd/sys/redox/condvar.rs @@ -1,3 +1,13 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + use cell::UnsafeCell; use intrinsics::{atomic_cxchg, atomic_xadd, atomic_xchg}; use ptr; diff --git a/src/libstd/sys/redox/env.rs b/src/libstd/sys/redox/env.rs index 51fd2d079738f..669b7520df846 100644 --- a/src/libstd/sys/redox/env.rs +++ b/src/libstd/sys/redox/env.rs @@ -1,4 +1,4 @@ -// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // diff --git a/src/libstd/sys/redox/ext/fs.rs b/src/libstd/sys/redox/ext/fs.rs index d292b43872439..b4e220971fd9c 100644 --- a/src/libstd/sys/redox/ext/fs.rs +++ b/src/libstd/sys/redox/ext/fs.rs @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -235,10 +235,10 @@ pub trait FileTypeExt { #[stable(feature = "file_type_ext", since = "1.5.0")] impl FileTypeExt for fs::FileType { - fn is_block_device(&self) -> bool { false /*TODO*/ } - fn is_char_device(&self) -> bool { false /*TODO*/ } - fn is_fifo(&self) -> bool { false /*TODO*/ } - fn is_socket(&self) -> bool { false /*TODO*/ } + fn is_block_device(&self) -> bool { false /*FIXME: Implement block device mode*/ } + fn is_char_device(&self) -> bool { false /*FIXME: Implement char device mode*/ } + fn is_fifo(&self) -> bool { false /*FIXME: Implement fifo mode*/ } + fn is_socket(&self) -> bool { false /*FIXME: Implement socket mode*/ } } /// Creates a new symbolic link on the filesystem. diff --git a/src/libstd/sys/redox/ext/io.rs b/src/libstd/sys/redox/ext/io.rs index 4f39f3b4f33f7..135e31fae1e68 100644 --- a/src/libstd/sys/redox/ext/io.rs +++ b/src/libstd/sys/redox/ext/io.rs @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // diff --git a/src/libstd/sys/redox/ext/mod.rs b/src/libstd/sys/redox/ext/mod.rs index 02edfa84aa090..513ef272e9790 100644 --- a/src/libstd/sys/redox/ext/mod.rs +++ b/src/libstd/sys/redox/ext/mod.rs @@ -1,4 +1,4 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // diff --git a/src/libstd/sys/redox/ext/process.rs b/src/libstd/sys/redox/ext/process.rs index 3a7c59d4e6d09..1472242d3db5d 100644 --- a/src/libstd/sys/redox/ext/process.rs +++ b/src/libstd/sys/redox/ext/process.rs @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // diff --git a/src/libstd/sys/redox/fast_thread_local.rs b/src/libstd/sys/redox/fast_thread_local.rs index e0a1773084699..6eeae2d90ea0e 100644 --- a/src/libstd/sys/redox/fast_thread_local.rs +++ b/src/libstd/sys/redox/fast_thread_local.rs @@ -1,4 +1,4 @@ -// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // diff --git a/src/libstd/sys/redox/fd.rs b/src/libstd/sys/redox/fd.rs index 4c8e62d1863b6..b6de68a9dc1a9 100644 --- a/src/libstd/sys/redox/fd.rs +++ b/src/libstd/sys/redox/fd.rs @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // diff --git a/src/libstd/sys/redox/fs.rs b/src/libstd/sys/redox/fs.rs index 9d5d2f5d92108..e3bd77f400998 100644 --- a/src/libstd/sys/redox/fs.rs +++ b/src/libstd/sys/redox/fs.rs @@ -1,4 +1,4 @@ -// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -118,9 +118,11 @@ impl FilePermissions { impl FileType { pub fn is_dir(&self) -> bool { self.is(syscall::MODE_DIR) } pub fn is_file(&self) -> bool { self.is(syscall::MODE_FILE) } - pub fn is_symlink(&self) -> bool { false } + pub fn is_symlink(&self) -> bool { false /*FIXME: Implement symlink mode*/ } - pub fn is(&self, mode: u16) -> bool { self.mode & (syscall::MODE_DIR | syscall::MODE_FILE) == mode } + pub fn is(&self, mode: u16) -> bool { + self.mode & (syscall::MODE_DIR | syscall::MODE_FILE) == mode + } } impl FromInner for FilePermissions { @@ -334,7 +336,8 @@ impl DirBuilder { } pub fn mkdir(&self, p: &Path) -> io::Result<()> { - let fd = cvt(syscall::open(p.to_str().unwrap(), syscall::O_CREAT | syscall::O_DIRECTORY | syscall::O_EXCL | (self.mode as usize & 0o777)))?; + let flags = syscall::O_CREAT | syscall::O_DIRECTORY | syscall::O_EXCL; + let fd = cvt(syscall::open(p.to_str().unwrap(), flags | (self.mode as usize & 0o777)))?; let _ = syscall::close(fd); Ok(()) } @@ -369,7 +372,8 @@ impl fmt::Debug for File { pub fn readdir(p: &Path) -> io::Result { let root = Arc::new(p.to_path_buf()); - let fd = cvt(syscall::open(p.to_str().unwrap(), syscall::O_CLOEXEC | syscall::O_RDONLY | syscall::O_DIRECTORY))?; + let flags = syscall::O_CLOEXEC | syscall::O_RDONLY | syscall::O_DIRECTORY; + let fd = cvt(syscall::open(p.to_str().unwrap(), flags))?; let file = FileDesc::new(fd); let mut data = Vec::new(); file.read_to_end(&mut data)?; diff --git a/src/libstd/sys/redox/mod.rs b/src/libstd/sys/redox/mod.rs index 07ead22b7a892..96efa27c0d34b 100644 --- a/src/libstd/sys/redox/mod.rs +++ b/src/libstd/sys/redox/mod.rs @@ -1,3 +1,13 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + #![allow(dead_code, missing_docs, bad_style)] pub extern crate syscall; diff --git a/src/libstd/sys/redox/mutex.rs b/src/libstd/sys/redox/mutex.rs index 42424da858fbc..a995f597fc46a 100644 --- a/src/libstd/sys/redox/mutex.rs +++ b/src/libstd/sys/redox/mutex.rs @@ -1,3 +1,13 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + use cell::UnsafeCell; use intrinsics::{atomic_cxchg, atomic_xchg}; use ptr; diff --git a/src/libstd/sys/redox/net/dns/answer.rs b/src/libstd/sys/redox/net/dns/answer.rs index c0450c11ed6b9..8e6aaeb0293ad 100644 --- a/src/libstd/sys/redox/net/dns/answer.rs +++ b/src/libstd/sys/redox/net/dns/answer.rs @@ -1,3 +1,13 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + use string::String; use vec::Vec; diff --git a/src/libstd/sys/redox/net/dns/mod.rs b/src/libstd/sys/redox/net/dns/mod.rs index 4397b71b93914..43c4fe7ac9d96 100644 --- a/src/libstd/sys/redox/net/dns/mod.rs +++ b/src/libstd/sys/redox/net/dns/mod.rs @@ -1,3 +1,13 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + pub use self::answer::DnsAnswer; pub use self::query::DnsQuery; diff --git a/src/libstd/sys/redox/net/dns/query.rs b/src/libstd/sys/redox/net/dns/query.rs index dcb554d82debb..b0dcdcb624abd 100644 --- a/src/libstd/sys/redox/net/dns/query.rs +++ b/src/libstd/sys/redox/net/dns/query.rs @@ -1,3 +1,13 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + use string::String; #[derive(Clone, Debug)] diff --git a/src/libstd/sys/redox/net/mod.rs b/src/libstd/sys/redox/net/mod.rs index 92c7d72887bf0..334c5e51c39b4 100644 --- a/src/libstd/sys/redox/net/mod.rs +++ b/src/libstd/sys/redox/net/mod.rs @@ -1,3 +1,13 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + use fs::File; use io::{Error, Result, Read}; use iter::Iterator; @@ -30,14 +40,17 @@ impl Iterator for LookupHost { pub fn lookup_host(host: &str) -> Result { let mut ip_string = String::new(); File::open("/etc/net/ip")?.read_to_string(&mut ip_string)?; - let ip: Vec = ip_string.trim().split(".").map(|part| part.parse::().unwrap_or(0)).collect(); + let ip: Vec = ip_string.trim().split(".").map(|part| part.parse::() + .unwrap_or(0)).collect(); let mut dns_string = String::new(); File::open("/etc/net/dns")?.read_to_string(&mut dns_string)?; - let dns: Vec = dns_string.trim().split(".").map(|part| part.parse::().unwrap_or(0)).collect(); + let dns: Vec = dns_string.trim().split(".").map(|part| part.parse::() + .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 time = time::SystemTime::now().duration_since(time::UNIX_EPOCH).unwrap(); + let tid = (time.subsec_nanos() >> 16) as u16; let packet = Dns { transaction_id: tid, @@ -52,8 +65,10 @@ pub fn lookup_host(host: &str) -> Result { 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)))?; + let my_ip = Ipv4Addr::new(ip[0], ip[1], ip[2], ip[3]); + let dns_ip = Ipv4Addr::new(dns[0], dns[1], dns[2], dns[3]); + let socket = UdpSocket::bind(&SocketAddr::V4(SocketAddrV4::new(my_ip, 0)))?; + socket.connect(&SocketAddr::V4(SocketAddrV4::new(dns_ip, 53)))?; socket.send(&packet_data)?; let mut buf = [0; 65536]; @@ -63,8 +78,14 @@ pub fn lookup_host(host: &str) -> Result { 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))); + if answer.a_type == 0x0001 && answer.a_class == 0x0001 + && answer.data.len() == 4 + { + let answer_ip = Ipv4Addr::new(answer.data[0], + answer.data[1], + answer.data[2], + answer.data[3]); + addrs.push(SocketAddr::V4(SocketAddrV4::new(answer_ip, 0))); } } Ok(LookupHost(addrs.into_iter())) diff --git a/src/libstd/sys/redox/net/tcp.rs b/src/libstd/sys/redox/net/tcp.rs index ceaa5df267fd3..1bfec2e861a68 100644 --- a/src/libstd/sys/redox/net/tcp.rs +++ b/src/libstd/sys/redox/net/tcp.rs @@ -1,3 +1,13 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + use io::{Error, ErrorKind, Result}; use net::{SocketAddr, Shutdown}; use path::Path; diff --git a/src/libstd/sys/redox/net/udp.rs b/src/libstd/sys/redox/net/udp.rs index 7856de033eb15..b81508e8f0de1 100644 --- a/src/libstd/sys/redox/net/udp.rs +++ b/src/libstd/sys/redox/net/udp.rs @@ -1,3 +1,13 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + use cell::UnsafeCell; use io::{Error, ErrorKind, Result}; use net::{SocketAddr, Ipv4Addr, Ipv6Addr}; diff --git a/src/libstd/sys/redox/os.rs b/src/libstd/sys/redox/os.rs index 9ebbae4199b78..15fb0cf211147 100644 --- a/src/libstd/sys/redox/os.rs +++ b/src/libstd/sys/redox/os.rs @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // diff --git a/src/libstd/sys/redox/os_str.rs b/src/libstd/sys/redox/os_str.rs index 5a733c0cb8763..8922bf04f56da 100644 --- a/src/libstd/sys/redox/os_str.rs +++ b/src/libstd/sys/redox/os_str.rs @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // diff --git a/src/libstd/sys/redox/path.rs b/src/libstd/sys/redox/path.rs index e609f83bc0721..c896a39109a6b 100644 --- a/src/libstd/sys/redox/path.rs +++ b/src/libstd/sys/redox/path.rs @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // diff --git a/src/libstd/sys/redox/pipe.rs b/src/libstd/sys/redox/pipe.rs index 7f192bef495a9..e7240fbe7bfb2 100644 --- a/src/libstd/sys/redox/pipe.rs +++ b/src/libstd/sys/redox/pipe.rs @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -9,7 +9,7 @@ // except according to those terms. use io; -use sys::syscall; +use sys::{cvt, syscall}; use sys::fd::FileDesc; //////////////////////////////////////////////////////////////////////////////// @@ -20,9 +20,7 @@ pub struct AnonPipe(FileDesc); pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> { let mut fds = [0; 2]; - - syscall::pipe2(&mut fds, syscall::O_CLOEXEC).map_err(|err| io::Error::from_raw_os_error(err.errno))?; - + cvt(syscall::pipe2(&mut fds, syscall::O_CLOEXEC))?; Ok((AnonPipe(FileDesc::new(fds[0])), AnonPipe(FileDesc::new(fds[1])))) } @@ -52,7 +50,7 @@ pub fn read2(p1: AnonPipe, v1: &mut Vec, p2: AnonPipe, v2: &mut Vec) -> io::Result<()> { - //TODO: Use event based I/O multiplexing + //FIXME: Use event based I/O multiplexing //unimplemented!() p1.read_to_end(v1)?; diff --git a/src/libstd/sys/redox/process.rs b/src/libstd/sys/redox/process.rs index 3c0d96913285d..849f51013e665 100644 --- a/src/libstd/sys/redox/process.rs +++ b/src/libstd/sys/redox/process.rs @@ -1,4 +1,4 @@ -// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // diff --git a/src/libstd/sys/redox/rand.rs b/src/libstd/sys/redox/rand.rs index 7d2df6bf95769..d7e4d09a9d636 100644 --- a/src/libstd/sys/redox/rand.rs +++ b/src/libstd/sys/redox/rand.rs @@ -1,4 +1,4 @@ -// Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // diff --git a/src/libstd/sys/redox/rwlock.rs b/src/libstd/sys/redox/rwlock.rs index c752fa50ea9dd..d74b614ba47de 100644 --- a/src/libstd/sys/redox/rwlock.rs +++ b/src/libstd/sys/redox/rwlock.rs @@ -1,4 +1,4 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // diff --git a/src/libstd/sys/redox/stack_overflow.rs b/src/libstd/sys/redox/stack_overflow.rs index 92846bfe0c8d1..760fe06c57faf 100644 --- a/src/libstd/sys/redox/stack_overflow.rs +++ b/src/libstd/sys/redox/stack_overflow.rs @@ -1,4 +1,4 @@ -// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // @@ -23,5 +23,5 @@ pub unsafe fn init() { } pub unsafe fn cleanup() { - + } diff --git a/src/libstd/sys/redox/stdio.rs b/src/libstd/sys/redox/stdio.rs index aa8329bc28386..607eef051d6eb 100644 --- a/src/libstd/sys/redox/stdio.rs +++ b/src/libstd/sys/redox/stdio.rs @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // diff --git a/src/libstd/sys/redox/thread.rs b/src/libstd/sys/redox/thread.rs index 0e7b27d396107..b2c0e285f0663 100644 --- a/src/libstd/sys/redox/thread.rs +++ b/src/libstd/sys/redox/thread.rs @@ -1,4 +1,4 @@ -// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // diff --git a/src/libstd/sys/redox/thread_local.rs b/src/libstd/sys/redox/thread_local.rs index 43b0bf09a6fe1..abdd9ace795f4 100644 --- a/src/libstd/sys/redox/thread_local.rs +++ b/src/libstd/sys/redox/thread_local.rs @@ -1,4 +1,4 @@ -// Copyright 2014-2015 The Rust Project Developers. See the COPYRIGHT +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // diff --git a/src/libstd/sys/redox/time.rs b/src/libstd/sys/redox/time.rs index 8f05e3bcfe716..dea406efe6ca9 100644 --- a/src/libstd/sys/redox/time.rs +++ b/src/libstd/sys/redox/time.rs @@ -1,4 +1,4 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // diff --git a/src/libstd/sys/unix/stdio.rs b/src/libstd/sys/unix/stdio.rs index 1002c60d30337..6d38b00b39eb5 100644 --- a/src/libstd/sys/unix/stdio.rs +++ b/src/libstd/sys/unix/stdio.rs @@ -71,7 +71,7 @@ impl io::Write for Stderr { fn write(&mut self, data: &[u8]) -> io::Result { Stderr::write(self, data) } - + fn flush(&mut self) -> io::Result<()> { Stderr::flush(self) } diff --git a/src/libstd/sys/windows/stdio.rs b/src/libstd/sys/windows/stdio.rs index 0d58da29323ed..a74e7699ba0fd 100644 --- a/src/libstd/sys/windows/stdio.rs +++ b/src/libstd/sys/windows/stdio.rs @@ -183,7 +183,7 @@ impl io::Write for Stderr { fn write(&mut self, data: &[u8]) -> io::Result { Stderr::write(self, data) } - + fn flush(&mut self) -> io::Result<()> { Stderr::flush(self) } From 729442206cda26e1a6d03f545a872389b2139606 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Wed, 30 Nov 2016 21:50:17 -0700 Subject: [PATCH 31/34] Cleanup env --- src/libstd/sys/redox/os.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/libstd/sys/redox/os.rs b/src/libstd/sys/redox/os.rs index 15fb0cf211147..135e972bca401 100644 --- a/src/libstd/sys/redox/os.rs +++ b/src/libstd/sys/redox/os.rs @@ -144,10 +144,11 @@ pub fn env() -> Env { let mut string = String::new(); if file.read_to_string(&mut string).is_ok() { for line in string.lines() { - if let Some(equal_sign) = line.chars().position(|c| c == '=') { - let name = line.chars().take(equal_sign).collect::(); - let value = line.chars().skip(equal_sign+1).collect::(); - variables.push((OsString::from(name), OsString::from(value))); + let mut parts = line.splitn(2, '='); + if let Some(name) = parts.next() { + let value = parts.next().unwrap_or(""); + variables.push((OsString::from(name.to_string()), + OsString::from(value.to_string()))); } } } From 056ebccee3d9587623fab9a9b2e72796c95142b4 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 12 Dec 2016 14:21:44 -0700 Subject: [PATCH 32/34] Rollback prefix --- src/libstd/path.rs | 7 +------ src/libstd/sys/redox/path.rs | 6 +++--- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/libstd/path.rs b/src/libstd/path.rs index e38cff179c3b4..95c8af664254e 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -136,9 +136,7 @@ use sys::path::{is_sep_byte, is_verbatim_sep, MAIN_SEP_STR, parse_prefix}; // Windows Prefixes //////////////////////////////////////////////////////////////////////////////// -/// Path prefixes (Redox and Windows only). -/// -/// Redox uses schemes like `scheme:reference` to identify different I/O systems +/// Path prefixes (Windows only). /// /// Windows uses a variety of path styles, including references to drive /// volumes (like `C:`), network shared folders (like `\\server\share`) and @@ -187,9 +185,6 @@ impl<'a> Prefix<'a> { os_str_as_u8_slice(s).len() } match *self { - #[cfg(target_os = "redox")] - Verbatim(x) => 1 + os_str_len(x), - #[cfg(not(target_os = "redox"))] Verbatim(x) => 4 + os_str_len(x), VerbatimUNC(x, y) => { 8 + os_str_len(x) + diff --git a/src/libstd/sys/redox/path.rs b/src/libstd/sys/redox/path.rs index c896a39109a6b..bef10011887c3 100644 --- a/src/libstd/sys/redox/path.rs +++ b/src/libstd/sys/redox/path.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use path::Prefix; use ffi::OsStr; #[inline] @@ -23,8 +22,9 @@ pub fn is_verbatim_sep(b: u8) -> bool { pub fn parse_prefix(path: &OsStr) -> Option { if let Some(path_str) = path.to_str() { - if let Some(i) = path_str.find(':') { - Some(Prefix::Verbatim(OsStr::new(&path_str[..i]))) + if let Some(_i) = path_str.find(':') { + //TODO: Redox specific prefix Some(Prefix::Verbatim(OsStr::new(&path_str[..i]))) + None } else { None } From c61baa0fc7a85bd2bcce34aac05ed739261cf037 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 12 Dec 2016 14:30:41 -0700 Subject: [PATCH 33/34] Fix accidental removal of import --- src/libstd/sys/redox/path.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/libstd/sys/redox/path.rs b/src/libstd/sys/redox/path.rs index bef10011887c3..dabec1acacd4f 100644 --- a/src/libstd/sys/redox/path.rs +++ b/src/libstd/sys/redox/path.rs @@ -9,6 +9,7 @@ // except according to those terms. use ffi::OsStr; +use path::Prefix; #[inline] pub fn is_sep_byte(b: u8) -> bool { From daaa23187624543189e58fda5e5893c76252ff0a Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 12 Dec 2016 15:57:19 -0700 Subject: [PATCH 34/34] Fix tidy checks --- src/libstd/sys/redox/path.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/libstd/sys/redox/path.rs b/src/libstd/sys/redox/path.rs index dabec1acacd4f..e6a267dd5d913 100644 --- a/src/libstd/sys/redox/path.rs +++ b/src/libstd/sys/redox/path.rs @@ -24,7 +24,8 @@ pub fn is_verbatim_sep(b: u8) -> bool { pub fn parse_prefix(path: &OsStr) -> Option { if let Some(path_str) = path.to_str() { if let Some(_i) = path_str.find(':') { - //TODO: Redox specific prefix Some(Prefix::Verbatim(OsStr::new(&path_str[..i]))) + // FIXME: Redox specific prefix + // Some(Prefix::Verbatim(OsStr::new(&path_str[..i]))) None } else { None