diff options
| author | Marcin Fatyga <marcinf@google.com> | 2016-11-01 15:26:22 +0100 |
|---|---|---|
| committer | Marcin Fatyga <marcinf@google.com> | 2016-11-01 15:26:22 +0100 |
| commit | 655effedf25e2039d283b839429bf2f42b7012a4 (patch) | |
| tree | 34fd087d891556c70a14b26a90d1bdccd0a7ccb2 /src/libstd/sys | |
| parent | 4e2822c5c28bb342e5862ba7cc0b90b865c68be1 (diff) | |
| parent | ac968c466451cb9aafd9e8598ddb396ed0e6fe31 (diff) | |
| download | rust-655effedf25e2039d283b839429bf2f42b7012a4.tar.gz rust-655effedf25e2039d283b839429bf2f42b7012a4.zip | |
Merge branch 'master' of https://github.com/rust-lang/rust
Conflicts: src/libcoretest/lib.rs
Diffstat (limited to 'src/libstd/sys')
38 files changed, 1462 insertions, 358 deletions
diff --git a/src/libstd/sys/common/args.rs b/src/libstd/sys/common/args.rs deleted file mode 100644 index fad2c277da4..00000000000 --- a/src/libstd/sys/common/args.rs +++ /dev/null @@ -1,99 +0,0 @@ -// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Global storage for command line arguments -//! -//! The current incarnation of the Rust runtime expects for -//! the processes `argc` and `argv` arguments to be stored -//! in a globally-accessible location for use by the `os` module. -//! -//! Only valid to call on Linux. Mac and Windows use syscalls to -//! discover the command line arguments. -//! -//! FIXME #7756: Would be nice for this to not exist. - -#![allow(dead_code)] // different code on OSX/linux/etc - -/// 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() } - -/// Make a clone of the global arguments. -pub fn clone() -> Option<Vec<Vec<u8>>> { imp::clone() } - -#[cfg(any(target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris", - target_os = "emscripten"))] -mod imp { - use libc::c_char; - use mem; - use ffi::CStr; - - 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 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 clone() -> Option<Vec<Vec<u8>>> { - unsafe { - LOCK.lock(); - let ptr = get_global_ptr(); - let ret = (*ptr).as_ref().map(|s| (**s).clone()); - LOCK.unlock(); - return ret - } - } - - fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> { - unsafe { mem::transmute(&GLOBAL_ARGS_PTR) } - } - -} - -#[cfg(any(target_os = "macos", - target_os = "ios", - target_os = "windows"))] -mod imp { - pub unsafe fn init(_argc: isize, _argv: *const *const u8) { - } - - pub fn cleanup() { - } - - pub fn clone() -> Option<Vec<Vec<u8>>> { - panic!() - } -} diff --git a/src/libstd/sys/common/io.rs b/src/libstd/sys/common/io.rs index 3cd70eddb85..0483725dd83 100644 --- a/src/libstd/sys/common/io.rs +++ b/src/libstd/sys/common/io.rs @@ -51,6 +51,7 @@ pub unsafe fn read_to_end_uninitialized(r: &mut Read, buf: &mut Vec<u8>) -> io:: } #[cfg(test)] +#[allow(dead_code)] // not used on emscripten pub mod test { use path::{Path, PathBuf}; use env; @@ -165,6 +166,7 @@ mod tests { } #[bench] + #[cfg_attr(target_os = "emscripten", ignore)] fn bench_uninitialized(b: &mut ::test::Bencher) { b.iter(|| { let mut lr = repeat(1).take(10000000); diff --git a/src/libstd/sys/common/memchr.rs b/src/libstd/sys/common/memchr.rs new file mode 100644 index 00000000000..3824a5fb528 --- /dev/null +++ b/src/libstd/sys/common/memchr.rs @@ -0,0 +1,230 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// +// Original implementation taken from rust-memchr +// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch + +#[allow(dead_code)] +pub mod fallback { + use cmp; + use mem; + + const LO_U64: u64 = 0x0101010101010101; + const HI_U64: u64 = 0x8080808080808080; + + // use truncation + const LO_USIZE: usize = LO_U64 as usize; + const HI_USIZE: usize = HI_U64 as usize; + + /// Return `true` if `x` contains any zero byte. + /// + /// From *Matters Computational*, J. Arndt + /// + /// "The idea is to subtract one from each of the bytes and then look for + /// bytes where the borrow propagated all the way to the most significant + /// bit." + #[inline] + fn contains_zero_byte(x: usize) -> bool { + x.wrapping_sub(LO_USIZE) & !x & HI_USIZE != 0 + } + + #[cfg(target_pointer_width = "32")] + #[inline] + fn repeat_byte(b: u8) -> usize { + let mut rep = (b as usize) << 8 | b as usize; + rep = rep << 16 | rep; + rep + } + + #[cfg(target_pointer_width = "64")] + #[inline] + fn repeat_byte(b: u8) -> usize { + let mut rep = (b as usize) << 8 | b as usize; + rep = rep << 16 | rep; + rep = rep << 32 | rep; + rep + } + + /// Return the first index matching the byte `a` in `text`. + pub fn memchr(x: u8, text: &[u8]) -> Option<usize> { + // Scan for a single byte value by reading two `usize` words at a time. + // + // Split `text` in three parts + // - unaligned initial part, before the first word aligned address in text + // - body, scan by 2 words at a time + // - the last remaining part, < 2 word size + let len = text.len(); + let ptr = text.as_ptr(); + let usize_bytes = mem::size_of::<usize>(); + + // search up to an aligned boundary + let align = (ptr as usize) & (usize_bytes- 1); + let mut offset; + if align > 0 { + offset = cmp::min(usize_bytes - align, len); + if let Some(index) = text[..offset].iter().position(|elt| *elt == x) { + return Some(index); + } + } else { + offset = 0; + } + + // search the body of the text + let repeated_x = repeat_byte(x); + + if len >= 2 * usize_bytes { + while offset <= len - 2 * usize_bytes { + unsafe { + let u = *(ptr.offset(offset as isize) as *const usize); + let v = *(ptr.offset((offset + usize_bytes) as isize) as *const usize); + + // break if there is a matching byte + let zu = contains_zero_byte(u ^ repeated_x); + let zv = contains_zero_byte(v ^ repeated_x); + if zu || zv { + break; + } + } + offset += usize_bytes * 2; + } + } + + // find the byte after the point the body loop stopped + text[offset..].iter().position(|elt| *elt == x).map(|i| offset + i) + } + + /// Return the last index matching the byte `a` in `text`. + pub fn memrchr(x: u8, text: &[u8]) -> Option<usize> { + // Scan for a single byte value by reading two `usize` words at a time. + // + // Split `text` in three parts + // - unaligned tail, after the last word aligned address in text + // - body, scan by 2 words at a time + // - the first remaining bytes, < 2 word size + let len = text.len(); + let ptr = text.as_ptr(); + let usize_bytes = mem::size_of::<usize>(); + + // search to an aligned boundary + let end_align = (ptr as usize + len) & (usize_bytes - 1); + let mut offset; + if end_align > 0 { + offset = if end_align >= len { 0 } else { len - end_align }; + if let Some(index) = text[offset..].iter().rposition(|elt| *elt == x) { + return Some(offset + index); + } + } else { + offset = len; + } + + // search the body of the text + let repeated_x = repeat_byte(x); + + while offset >= 2 * usize_bytes { + unsafe { + let u = *(ptr.offset(offset as isize - 2 * usize_bytes as isize) as *const usize); + let v = *(ptr.offset(offset as isize - usize_bytes as isize) as *const usize); + + // break if there is a matching byte + let zu = contains_zero_byte(u ^ repeated_x); + let zv = contains_zero_byte(v ^ repeated_x); + if zu || zv { + break; + } + } + offset -= 2 * usize_bytes; + } + + // find the byte before the point the body loop stopped + text[..offset].iter().rposition(|elt| *elt == x) + } + + // test fallback implementations on all platforms + #[test] + fn matches_one() { + assert_eq!(Some(0), memchr(b'a', b"a")); + } + + #[test] + fn matches_begin() { + assert_eq!(Some(0), memchr(b'a', b"aaaa")); + } + + #[test] + fn matches_end() { + assert_eq!(Some(4), memchr(b'z', b"aaaaz")); + } + + #[test] + fn matches_nul() { + assert_eq!(Some(4), memchr(b'\x00', b"aaaa\x00")); + } + + #[test] + fn matches_past_nul() { + assert_eq!(Some(5), memchr(b'z', b"aaaa\x00z")); + } + + #[test] + fn no_match_empty() { + assert_eq!(None, memchr(b'a', b"")); + } + + #[test] + fn no_match() { + assert_eq!(None, memchr(b'a', b"xyz")); + } + + #[test] + fn matches_one_reversed() { + assert_eq!(Some(0), memrchr(b'a', b"a")); + } + + #[test] + fn matches_begin_reversed() { + assert_eq!(Some(3), memrchr(b'a', b"aaaa")); + } + + #[test] + fn matches_end_reversed() { + assert_eq!(Some(0), memrchr(b'z', b"zaaaa")); + } + + #[test] + fn matches_nul_reversed() { + assert_eq!(Some(4), memrchr(b'\x00', b"aaaa\x00")); + } + + #[test] + fn matches_past_nul_reversed() { + assert_eq!(Some(0), memrchr(b'z', b"z\x00aaaa")); + } + + #[test] + fn no_match_empty_reversed() { + assert_eq!(None, memrchr(b'a', b"")); + } + + #[test] + fn no_match_reversed() { + assert_eq!(None, memrchr(b'a', b"xyz")); + } + + #[test] + fn each_alignment_reversed() { + let mut data = [1u8; 64]; + let needle = 2; + let pos = 40; + data[pos] = needle; + for start in 0..16 { + assert_eq!(Some(pos - start), memrchr(needle, &data[start..])); + } + } +} diff --git a/src/libstd/sys/common/mod.rs b/src/libstd/sys/common/mod.rs index d1ca6765107..2845f895f18 100644 --- a/src/libstd/sys/common/mod.rs +++ b/src/libstd/sys/common/mod.rs @@ -25,12 +25,12 @@ macro_rules! rtassert { }) } -pub mod args; pub mod at_exit_imp; #[cfg(any(not(cargobuild), feature = "backtrace"))] pub mod backtrace; pub mod condvar; pub mod io; +pub mod memchr; pub mod mutex; pub mod net; pub mod poison; @@ -91,7 +91,7 @@ pub fn at_exit<F: FnOnce() + Send + 'static>(f: F) -> Result<(), ()> { pub fn cleanup() { static CLEANUP: Once = Once::new(); CLEANUP.call_once(|| unsafe { - args::cleanup(); + sys::args::cleanup(); sys::stack_overflow::cleanup(); at_exit_imp::cleanup(); }); diff --git a/src/libstd/sys/common/net.rs b/src/libstd/sys/common/net.rs index a777cfe35e5..10ad61f4c80 100644 --- a/src/libstd/sys/common/net.rs +++ b/src/libstd/sys/common/net.rs @@ -24,24 +24,35 @@ use time::Duration; #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", target_os = "macos", target_os = "openbsd", target_os = "netbsd", - target_os = "solaris"))] + target_os = "solaris", target_os = "haiku"))] use sys::net::netc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP; #[cfg(not(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", target_os = "macos", target_os = "openbsd", target_os = "netbsd", - target_os = "solaris")))] + target_os = "solaris", target_os = "haiku")))] use sys::net::netc::IPV6_ADD_MEMBERSHIP; #[cfg(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", target_os = "macos", target_os = "openbsd", target_os = "netbsd", - target_os = "solaris"))] + target_os = "solaris", target_os = "haiku"))] use sys::net::netc::IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP; #[cfg(not(any(target_os = "dragonfly", target_os = "freebsd", target_os = "ios", target_os = "macos", target_os = "openbsd", target_os = "netbsd", - target_os = "solaris")))] + target_os = "solaris", target_os = "haiku")))] use sys::net::netc::IPV6_DROP_MEMBERSHIP; +#[cfg(any(target_os = "linux", target_os = "android", + target_os = "dragonfly", target_os = "freebsd", + target_os = "openbsd", target_os = "netbsd", + target_os = "haiku", target_os = "bitrig"))] +use libc::MSG_NOSIGNAL; +#[cfg(not(any(target_os = "linux", target_os = "android", + target_os = "dragonfly", target_os = "freebsd", + target_os = "openbsd", target_os = "netbsd", + target_os = "haiku", target_os = "bitrig")))] +const MSG_NOSIGNAL: c_int = 0x0; + //////////////////////////////////////////////////////////////////////////////// // sockaddr and misc bindings //////////////////////////////////////////////////////////////////////////////// @@ -225,7 +236,7 @@ impl TcpStream { c::send(*self.inner.as_inner(), buf.as_ptr() as *const c_void, len, - 0) + MSG_NOSIGNAL) })?; Ok(ret as usize) } @@ -449,7 +460,7 @@ impl UdpSocket { let ret = cvt(unsafe { c::sendto(*self.inner.as_inner(), buf.as_ptr() as *const c_void, len, - 0, dstp, dstlen) + MSG_NOSIGNAL, dstp, dstlen) })?; Ok(ret as usize) } @@ -573,7 +584,7 @@ impl UdpSocket { c::send(*self.inner.as_inner(), buf.as_ptr() as *const c_void, len, - 0) + MSG_NOSIGNAL) })?; Ok(ret as usize) } diff --git a/src/libstd/sys/common/poison.rs b/src/libstd/sys/common/poison.rs index 55212bf35d6..bdc727f1dfc 100644 --- a/src/libstd/sys/common/poison.rs +++ b/src/libstd/sys/common/poison.rs @@ -10,7 +10,6 @@ use error::{Error}; use fmt; -use marker::Reflect; use sync::atomic::{AtomicBool, Ordering}; use thread; @@ -117,7 +116,7 @@ impl<T> fmt::Display for PoisonError<T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<T: Reflect> Error for PoisonError<T> { +impl<T> Error for PoisonError<T> { fn description(&self) -> &str { "poisoned lock: another task failed inside" } @@ -174,7 +173,7 @@ impl<T> fmt::Display for TryLockError<T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<T: Reflect> Error for TryLockError<T> { +impl<T> Error for TryLockError<T> { fn description(&self) -> &str { match *self { TryLockError::Poisoned(ref p) => p.description(), diff --git a/src/libstd/sys/common/remutex.rs b/src/libstd/sys/common/remutex.rs index cbdeaad7f6b..4d0407ccf6c 100644 --- a/src/libstd/sys/common/remutex.rs +++ b/src/libstd/sys/common/remutex.rs @@ -156,7 +156,7 @@ impl<'a, T> Drop for ReentrantMutexGuard<'a, T> { } -#[cfg(test)] +#[cfg(all(test, not(target_os = "emscripten")))] mod tests { use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; use cell::RefCell; diff --git a/src/libstd/sys/common/wtf8.rs b/src/libstd/sys/common/wtf8.rs index 8d357aa78c9..0a94ff1e958 100644 --- a/src/libstd/sys/common/wtf8.rs +++ b/src/libstd/sys/common/wtf8.rs @@ -206,10 +206,12 @@ impl Wtf8Buf { /// Copied from String::push /// This does **not** include the WTF-8 concatenation check. fn push_code_point_unchecked(&mut self, code_point: CodePoint) { - let bytes = unsafe { - char::from_u32_unchecked(code_point.value).encode_utf8() + let c = unsafe { + char::from_u32_unchecked(code_point.value) }; - self.bytes.extend_from_slice(bytes.as_slice()); + let mut bytes = [0; 4]; + let bytes = c.encode_utf8(&mut bytes).as_bytes(); + self.bytes.extend_from_slice(bytes) } #[inline] @@ -738,15 +740,16 @@ impl<'a> Iterator for EncodeWide<'a> { return Some(tmp); } + let mut buf = [0; 2]; self.code_points.next().map(|code_point| { - let n = unsafe { - char::from_u32_unchecked(code_point.value).encode_utf16() + let c = unsafe { + char::from_u32_unchecked(code_point.value) }; - let n = n.as_slice(); - if n.len() == 2 { - self.extra = n[1]; + let n = c.encode_utf16(&mut buf).len(); + if n == 2 { + self.extra = buf[1]; } - n[0] + buf[0] }) } diff --git a/src/libstd/sys/unix/android.rs b/src/libstd/sys/unix/android.rs index abbe3fc1846..10436723a81 100644 --- a/src/libstd/sys/unix/android.rs +++ b/src/libstd/sys/unix/android.rs @@ -28,10 +28,11 @@ #![cfg(target_os = "android")] -use libc::{c_int, sighandler_t}; +use libc::{c_int, c_void, sighandler_t, size_t, ssize_t}; +use libc::{ftruncate, pread, pwrite}; use io; -use sys::cvt_r; +use super::{cvt, cvt_r}; // The `log2` and `log2f` functions apparently appeared in android-18, or at // least you can see they're not present in the android-17 header [1] and they @@ -96,13 +97,10 @@ pub unsafe fn signal(signum: c_int, handler: sighandler_t) -> sighandler_t { // // If it doesn't we just fall back to `ftruncate`, generating an error for // too-large values. +#[cfg(target_pointer_width = "32")] pub fn ftruncate64(fd: c_int, size: u64) -> io::Result<()> { weak!(fn ftruncate64(c_int, i64) -> c_int); - extern { - fn ftruncate(fd: c_int, off: i32) -> c_int; - } - unsafe { match ftruncate64.get() { Some(f) => cvt_r(|| f(fd, size as i64)).map(|_| ()), @@ -117,3 +115,56 @@ pub fn ftruncate64(fd: c_int, size: u64) -> io::Result<()> { } } } + +#[cfg(target_pointer_width = "64")] +pub fn ftruncate64(fd: c_int, size: u64) -> io::Result<()> { + unsafe { + cvt_r(|| ftruncate(fd, size as i64)).map(|_| ()) + } +} + +#[cfg(target_pointer_width = "32")] +pub unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: size_t, offset: i64) + -> io::Result<ssize_t> +{ + use convert::TryInto; + weak!(fn pread64(c_int, *mut c_void, size_t, i64) -> ssize_t); + pread64.get().map(|f| cvt(f(fd, buf, count, offset))).unwrap_or_else(|| { + if let Ok(o) = offset.try_into() { + cvt(pread(fd, buf, count, o)) + } else { + Err(io::Error::new(io::ErrorKind::InvalidInput, + "cannot pread >2GB")) + } + }) +} + +#[cfg(target_pointer_width = "32")] +pub unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: size_t, offset: i64) + -> io::Result<ssize_t> +{ + use convert::TryInto; + weak!(fn pwrite64(c_int, *const c_void, size_t, i64) -> ssize_t); + pwrite64.get().map(|f| cvt(f(fd, buf, count, offset))).unwrap_or_else(|| { + if let Ok(o) = offset.try_into() { + cvt(pwrite(fd, buf, count, o)) + } else { + Err(io::Error::new(io::ErrorKind::InvalidInput, + "cannot pwrite >2GB")) + } + }) +} + +#[cfg(target_pointer_width = "64")] +pub unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: size_t, offset: i64) + -> io::Result<ssize_t> +{ + cvt(pread(fd, buf, count, offset)) +} + +#[cfg(target_pointer_width = "64")] +pub unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: size_t, offset: i64) + -> io::Result<ssize_t> +{ + cvt(pwrite(fd, buf, count, offset)) +} diff --git a/src/libstd/sys/unix/args.rs b/src/libstd/sys/unix/args.rs new file mode 100644 index 00000000000..c04fd863674 --- /dev/null +++ b/src/libstd/sys/unix/args.rs @@ -0,0 +1,212 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! Global initialization and retreival of command line arguments. +//! +//! On some platforms these are stored during runtime startup, +//! and on some they are retrieved from the system on demand. + +#![allow(dead_code)] // runtime init functions not used during testing + +use ffi::OsString; +use marker::PhantomData; +use vec; + +/// One-time global initialization. +pub unsafe fn init(argc: isize, argv: *const *const u8) { imp::init(argc, argv) } + +/// One-time global cleanup. +pub unsafe fn cleanup() { imp::cleanup() } + +/// Returns the command line arguments +pub fn args() -> Args { + imp::args() +} + +pub struct Args { + iter: vec::IntoIter<OsString>, + _dont_send_or_sync_me: PhantomData<*mut ()>, +} + +impl Iterator for Args { + type Item = OsString; + fn next(&mut self) -> Option<OsString> { self.iter.next() } + fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() } +} + +impl ExactSizeIterator for Args { + fn len(&self) -> usize { self.iter.len() } +} + +impl DoubleEndedIterator for Args { + fn next_back(&mut self) -> Option<OsString> { self.iter.next_back() } +} + +#[cfg(any(target_os = "linux", + target_os = "android", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "bitrig", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_os = "emscripten", + target_os = "haiku", + target_os = "fuchsia"))] +mod imp { + use os::unix::prelude::*; + use mem; + use ffi::{CStr, OsString}; + use marker::PhantomData; + use libc; + use super::Args; + + use sys_common::mutex::Mutex; + + static mut GLOBAL_ARGS_PTR: usize = 0; + static LOCK: Mutex = Mutex::new(); + + pub unsafe fn init(argc: isize, argv: *const *const u8) { + let args = (0..argc).map(|i| { + CStr::from_ptr(*argv.offset(i) as *const libc::c_char).to_bytes().to_vec() + }).collect(); + + LOCK.lock(); + let ptr = get_global_ptr(); + assert!((*ptr).is_none()); + (*ptr) = Some(box args); + LOCK.unlock(); + } + + pub unsafe fn cleanup() { + LOCK.lock(); + *get_global_ptr() = None; + LOCK.unlock(); + } + + pub fn args() -> Args { + let bytes = clone().unwrap_or(Vec::new()); + let v: Vec<OsString> = bytes.into_iter().map(|v| { + OsStringExt::from_vec(v) + }).collect(); + Args { iter: v.into_iter(), _dont_send_or_sync_me: PhantomData } + } + + fn clone() -> Option<Vec<Vec<u8>>> { + unsafe { + LOCK.lock(); + let ptr = get_global_ptr(); + let ret = (*ptr).as_ref().map(|s| (**s).clone()); + LOCK.unlock(); + return ret + } + } + + fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> { + unsafe { mem::transmute(&GLOBAL_ARGS_PTR) } + } + +} + +#[cfg(any(target_os = "macos", + target_os = "ios"))] +mod imp { + use ffi::CStr; + use marker::PhantomData; + use libc; + use super::Args; + + pub unsafe fn init(_argc: isize, _argv: *const *const u8) { + } + + pub fn cleanup() { + } + + #[cfg(target_os = "macos")] + pub fn args() -> Args { + use os::unix::prelude::*; + extern { + // These functions are in crt_externs.h. + fn _NSGetArgc() -> *mut libc::c_int; + fn _NSGetArgv() -> *mut *mut *mut libc::c_char; + } + + let vec = unsafe { + let (argc, argv) = (*_NSGetArgc() as isize, + *_NSGetArgv() as *const *const libc::c_char); + (0.. argc as isize).map(|i| { + let bytes = CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec(); + OsStringExt::from_vec(bytes) + }).collect::<Vec<_>>() + }; + Args { + iter: vec.into_iter(), + _dont_send_or_sync_me: PhantomData, + } + } + + // As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs + // and use underscores in their names - they're most probably + // are considered private and therefore should be avoided + // Here is another way to get arguments using Objective C + // runtime + // + // In general it looks like: + // res = Vec::new() + // let args = [[NSProcessInfo processInfo] arguments] + // for i in (0..[args count]) + // res.push([args objectAtIndex:i]) + // res + #[cfg(target_os = "ios")] + pub fn args() -> Args { + use ffi::OsString; + use mem; + use str; + + extern { + fn sel_registerName(name: *const libc::c_uchar) -> Sel; + fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId; + fn objc_getClass(class_name: *const libc::c_uchar) -> NsId; + } + + #[link(name = "Foundation", kind = "framework")] + #[link(name = "objc")] + #[cfg(not(cargobuild))] + extern {} + + type Sel = *const libc::c_void; + type NsId = *const libc::c_void; + + let mut res = Vec::new(); + + unsafe { + let process_info_sel = sel_registerName("processInfo\0".as_ptr()); + let arguments_sel = sel_registerName("arguments\0".as_ptr()); + let utf8_sel = sel_registerName("UTF8String\0".as_ptr()); + let count_sel = sel_registerName("count\0".as_ptr()); + let object_at_sel = sel_registerName("objectAtIndex:\0".as_ptr()); + + let klass = objc_getClass("NSProcessInfo\0".as_ptr()); + let info = objc_msgSend(klass, process_info_sel); + let args = objc_msgSend(info, arguments_sel); + + let cnt: usize = mem::transmute(objc_msgSend(args, count_sel)); + for i in 0..cnt { + let tmp = objc_msgSend(args, object_at_sel, i); + let utf_c_str: *const libc::c_char = + mem::transmute(objc_msgSend(tmp, utf8_sel)); + let bytes = CStr::from_ptr(utf_c_str).to_bytes(); + res.push(OsString::from(str::from_utf8(bytes).unwrap())) + } + } + + Args { iter: res.into_iter(), _dont_send_or_sync_me: PhantomData } + } +} diff --git a/src/libstd/sys/unix/env.rs b/src/libstd/sys/unix/env.rs new file mode 100644 index 00000000000..eff3a8c2a34 --- /dev/null +++ b/src/libstd/sys/unix/env.rs @@ -0,0 +1,184 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#[cfg(target_os = "linux")] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "linux"; + 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 = ""; +} + +#[cfg(target_os = "macos")] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "macos"; + pub const DLL_PREFIX: &'static str = "lib"; + pub const DLL_SUFFIX: &'static str = ".dylib"; + pub const DLL_EXTENSION: &'static str = "dylib"; + pub const EXE_SUFFIX: &'static str = ""; + pub const EXE_EXTENSION: &'static str = ""; +} + +#[cfg(target_os = "ios")] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "ios"; + pub const DLL_PREFIX: &'static str = "lib"; + pub const DLL_SUFFIX: &'static str = ".dylib"; + pub const DLL_EXTENSION: &'static str = "dylib"; + pub const EXE_SUFFIX: &'static str = ""; + pub const EXE_EXTENSION: &'static str = ""; +} + +#[cfg(target_os = "freebsd")] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "freebsd"; + 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 = ""; +} + +#[cfg(target_os = "dragonfly")] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "dragonfly"; + 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 = ""; +} + +#[cfg(target_os = "bitrig")] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "bitrig"; + 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 = ""; +} + +#[cfg(target_os = "netbsd")] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "netbsd"; + 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 = ""; +} + +#[cfg(target_os = "openbsd")] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "openbsd"; + 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 = ""; +} + +#[cfg(target_os = "android")] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "android"; + 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 = ""; +} + +#[cfg(target_os = "solaris")] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "solaris"; + 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 = ""; +} + +#[cfg(all(target_os = "nacl", not(target_arch = "le32")))] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "nacl"; + 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 = ".nexe"; + pub const EXE_EXTENSION: &'static str = "nexe"; +} +#[cfg(all(target_os = "nacl", target_arch = "le32"))] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "pnacl"; + pub const DLL_PREFIX: &'static str = "lib"; + pub const DLL_SUFFIX: &'static str = ".pso"; + pub const DLL_EXTENSION: &'static str = "pso"; + pub const EXE_SUFFIX: &'static str = ".pexe"; + pub const EXE_EXTENSION: &'static str = "pexe"; +} + +#[cfg(target_os = "haiku")] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "haiku"; + 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 = ""; +} + +#[cfg(all(target_os = "emscripten", target_arch = "asmjs"))] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "emscripten"; + 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 = ".js"; + pub const EXE_EXTENSION: &'static str = "js"; +} + +#[cfg(all(target_os = "emscripten", target_arch = "wasm32"))] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "emscripten"; + 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 = ".js"; + pub const EXE_EXTENSION: &'static str = "js"; +} + +#[cfg(target_os = "fuchsia")] +pub mod os { + pub const FAMILY: &'static str = "unix"; + pub const OS: &'static str = "fuchsia"; + 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/unix/ext/fs.rs b/src/libstd/sys/unix/ext/fs.rs index 77587918ac9..fcfab051588 100644 --- a/src/libstd/sys/unix/ext/fs.rs +++ b/src/libstd/sys/unix/ext/fs.rs @@ -20,6 +20,51 @@ use sys; use sys_common::{FromInner, AsInner, AsInnerMut}; use sys::platform::fs::MetadataExt as UnixMetadataExt; +/// Unix-specific extensions to `File` +#[unstable(feature = "file_offset", issue = "35918")] +pub trait FileExt { + /// Reads a number of bytes starting from a given offset. + /// + /// Returns the number of bytes read. + /// + /// The offset is relative to the start of the file and thus independent + /// from the current cursor. + /// + /// The current file cursor is not affected by this function. + /// + /// Note that similar to `File::read`, it is not an error to return with a + /// short read. + #[unstable(feature = "file_offset", issue = "35918")] + fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>; + + /// Writes a number of bytes starting from a given offset. + /// + /// Returns the number of bytes written. + /// + /// The offset is relative to the start of the file and thus independent + /// from the current cursor. + /// + /// The current file cursor is not affected by this function. + /// + /// When writing beyond the end of the file, the file is appropiately + /// extended and the intermediate bytes are initialized with the value 0. + /// + /// Note that similar to `File::write`, it is not an error to return a + /// short write. + #[unstable(feature = "file_offset", issue = "35918")] + fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize>; +} + +#[unstable(feature = "file_offset", issue = "35918")] +impl FileExt for fs::File { + fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { + self.as_inner().read_at(buf, offset) + } + fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { + self.as_inner().write_at(buf, offset) + } +} + /// Unix-specific extensions to `Permissions` #[stable(feature = "fs_ext", since = "1.1.0")] pub trait PermissionsExt { diff --git a/src/libstd/sys/unix/ext/mod.rs b/src/libstd/sys/unix/ext/mod.rs index 1be3d75d866..b2483f4e209 100644 --- a/src/libstd/sys/unix/ext/mod.rs +++ b/src/libstd/sys/unix/ext/mod.rs @@ -50,6 +50,8 @@ pub mod prelude { pub use super::fs::{PermissionsExt, OpenOptionsExt, MetadataExt, FileTypeExt}; #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] pub use super::fs::DirEntryExt; + #[doc(no_inline)] #[unstable(feature = "file_offset", issue = "35918")] + pub use super::fs::FileExt; #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] pub use super::thread::JoinHandleExt; #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs index 3f93fce1935..80f53da1cef 100644 --- a/src/libstd/sys/unix/ext/net.rs +++ b/src/libstd/sys/unix/ext/net.rs @@ -28,6 +28,17 @@ use sys::cvt; use sys::net::Socket; use sys_common::{AsInner, FromInner, IntoInner}; +#[cfg(any(target_os = "linux", target_os = "android", + target_os = "dragonfly", target_os = "freebsd", + target_os = "openbsd", target_os = "netbsd", + target_os = "haiku", target_os = "bitrig"))] +use libc::MSG_NOSIGNAL; +#[cfg(not(any(target_os = "linux", target_os = "android", + target_os = "dragonfly", target_os = "freebsd", + target_os = "openbsd", target_os = "netbsd", + target_os = "haiku", target_os = "bitrig")))] +const MSG_NOSIGNAL: libc::c_int = 0x0; + fn sun_path_offset() -> usize { unsafe { // Work with an actual instance of the type since using a null pointer is UB @@ -690,7 +701,7 @@ impl UnixDatagram { let count = cvt(libc::sendto(*d.0.as_inner(), buf.as_ptr() as *const _, buf.len(), - 0, + MSG_NOSIGNAL, &addr as *const _ as *const _, len))?; Ok(count as usize) @@ -786,7 +797,7 @@ impl IntoRawFd for UnixDatagram { } } -#[cfg(test)] +#[cfg(all(test, not(target_os = "emscripten")))] mod test { use thread; use io; diff --git a/src/libstd/sys/unix/ext/process.rs b/src/libstd/sys/unix/ext/process.rs index 5bd92f2eb57..3a7c59d4e6d 100644 --- a/src/libstd/sys/unix/ext/process.rs +++ b/src/libstd/sys/unix/ext/process.rs @@ -161,21 +161,21 @@ impl AsRawFd for process::ChildStderr { } } -#[stable(feature = "process_extensions", since = "1.2.0")] +#[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 = "process_extensions", since = "1.2.0")] +#[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 = "process_extensions", since = "1.2.0")] +#[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/unix/fd.rs b/src/libstd/sys/unix/fd.rs index b2b1f16f20a..41bb96fed16 100644 --- a/src/libstd/sys/unix/fd.rs +++ b/src/libstd/sys/unix/fd.rs @@ -11,7 +11,7 @@ #![unstable(reason = "not public", issue = "0", feature = "fd")] use io::{self, Read}; -use libc::{self, c_int, size_t, c_void}; +use libc::{self, c_int, c_void}; use mem; use sync::atomic::{AtomicBool, Ordering}; use sys::cvt; @@ -40,7 +40,7 @@ impl FileDesc { let ret = cvt(unsafe { libc::read(self.fd, buf.as_mut_ptr() as *mut c_void, - buf.len() as size_t) + buf.len()) })?; Ok(ret as usize) } @@ -50,23 +50,77 @@ impl FileDesc { (&mut me).read_to_end(buf) } + pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { + #[cfg(target_os = "android")] + use super::android::cvt_pread64; + + #[cfg(not(target_os = "android"))] + unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: usize, offset: i64) + -> io::Result<isize> + { + #[cfg(any(target_os = "linux", target_os = "emscripten"))] + use libc::pread64; + #[cfg(not(any(target_os = "linux", target_os = "emscripten")))] + use libc::pread as pread64; + cvt(pread64(fd, buf, count, offset)) + } + + unsafe { + cvt_pread64(self.fd, + buf.as_mut_ptr() as *mut c_void, + buf.len(), + offset as i64) + .map(|n| n as usize) + } + } + pub fn write(&self, buf: &[u8]) -> io::Result<usize> { let ret = cvt(unsafe { libc::write(self.fd, buf.as_ptr() as *const c_void, - buf.len() as size_t) + buf.len()) })?; Ok(ret as usize) } - #[cfg(not(any(target_env = "newlib", target_os = "solaris", target_os = "emscripten")))] + pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { + #[cfg(target_os = "android")] + use super::android::cvt_pwrite64; + + #[cfg(not(target_os = "android"))] + unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: usize, offset: i64) + -> io::Result<isize> + { + #[cfg(any(target_os = "linux", target_os = "emscripten"))] + use libc::pwrite64; + #[cfg(not(any(target_os = "linux", target_os = "emscripten")))] + use libc::pwrite as pwrite64; + cvt(pwrite64(fd, buf, count, offset)) + } + + unsafe { + cvt_pwrite64(self.fd, + buf.as_ptr() as *const c_void, + buf.len(), + offset as i64) + .map(|n| n as usize) + } + } + + #[cfg(not(any(target_env = "newlib", + target_os = "solaris", + target_os = "emscripten", + target_os = "haiku")))] pub fn set_cloexec(&self) -> io::Result<()> { unsafe { cvt(libc::ioctl(self.fd, libc::FIOCLEX))?; Ok(()) } } - #[cfg(any(target_env = "newlib", target_os = "solaris", target_os = "emscripten"))] + #[cfg(any(target_env = "newlib", + target_os = "solaris", + target_os = "emscripten", + target_os = "haiku"))] pub fn set_cloexec(&self) -> io::Result<()> { unsafe { let previous = cvt(libc::fcntl(self.fd, libc::F_GETFD))?; @@ -104,9 +158,9 @@ impl FileDesc { // resolve so we at least compile this. // // [1]: http://comments.gmane.org/gmane.linux.lib.musl.general/2963 - #[cfg(target_os = "android")] + #[cfg(any(target_os = "android", target_os = "haiku"))] use libc::F_DUPFD as F_DUPFD_CLOEXEC; - #[cfg(not(target_os = "android"))] + #[cfg(not(any(target_os = "android", target_os="haiku")))] use libc::F_DUPFD_CLOEXEC; let make_filedesc = |fd| { diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index e6fe3eb112a..0b43fd2ac8c 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -193,6 +193,14 @@ impl FromInner<u32> for FilePermissions { } } +impl fmt::Debug for ReadDir { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame. + // Thus the result will be e g 'ReadDir("/home")' + fmt::Debug::fmt(&*self.root, f) + } +} + impl Iterator for ReadDir { type Item = io::Result<DirEntry>; @@ -279,7 +287,12 @@ impl DirEntry { stat(&self.path()).map(|m| m.file_type()) } - #[cfg(not(target_os = "solaris"))] + #[cfg(target_os = "haiku")] + pub fn file_type(&self) -> io::Result<FileType> { + lstat(&self.path()).map(|m| m.file_type()) + } + + #[cfg(not(any(target_os = "solaris", target_os = "haiku")))] pub fn file_type(&self) -> io::Result<FileType> { match self.entry.d_type { libc::DT_CHR => Ok(FileType { mode: libc::S_IFCHR }), @@ -298,7 +311,9 @@ impl DirEntry { target_os = "linux", target_os = "emscripten", target_os = "android", - target_os = "solaris"))] + target_os = "solaris", + target_os = "haiku", + target_os = "fuchsia"))] pub fn ino(&self) -> u64 { self.entry.d_ino as u64 } @@ -327,7 +342,9 @@ impl DirEntry { } #[cfg(any(target_os = "android", target_os = "linux", - target_os = "emscripten"))] + target_os = "emscripten", + target_os = "haiku", + target_os = "fuchsia"))] fn name_bytes(&self) -> &[u8] { unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()).to_bytes() @@ -476,10 +493,18 @@ impl File { self.0.read_to_end(buf) } + pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { + self.0.read_at(buf, offset) + } + pub fn write(&self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) } + pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { + self.0.write_at(buf, offset) + } + pub fn flush(&self) -> io::Result<()> { Ok(()) } pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> { @@ -662,7 +687,7 @@ pub fn readlink(p: &Path) -> io::Result<PathBuf> { loop { let buf_read = cvt(unsafe { - libc::readlink(p, buf.as_mut_ptr() as *mut _, buf.capacity() as libc::size_t) + libc::readlink(p, buf.as_mut_ptr() as *mut _, buf.capacity()) })? as usize; unsafe { buf.set_len(buf_read); } diff --git a/src/libstd/sys/unix/memchr.rs b/src/libstd/sys/unix/memchr.rs new file mode 100644 index 00000000000..aed04703ea1 --- /dev/null +++ b/src/libstd/sys/unix/memchr.rs @@ -0,0 +1,57 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// +// Original implementation taken from rust-memchr +// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch + +pub fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> { + use libc; + + let p = unsafe { + libc::memchr( + haystack.as_ptr() as *const libc::c_void, + needle as libc::c_int, + haystack.len()) + }; + if p.is_null() { + None + } else { + Some(p as usize - (haystack.as_ptr() as usize)) + } +} + +pub fn memrchr(needle: u8, haystack: &[u8]) -> Option<usize> { + + #[cfg(target_os = "linux")] + fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> { + use libc; + + // GNU's memrchr() will - unlike memchr() - error if haystack is empty. + if haystack.is_empty() {return None} + let p = unsafe { + libc::memrchr( + haystack.as_ptr() as *const libc::c_void, + needle as libc::c_int, + haystack.len()) + }; + if p.is_null() { + None + } else { + Some(p as usize - (haystack.as_ptr() as usize)) + } + } + + #[cfg(not(target_os = "linux"))] + fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> { + ::sys_common::memchr::fallback::memrchr(needle, haystack) + } + + memrchr_specific(needle, haystack) +} diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index 23687e10e47..66bc9d4a491 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -17,6 +17,7 @@ use libc; #[cfg(target_os = "bitrig")] pub use os::bitrig as platform; #[cfg(target_os = "dragonfly")] pub use os::dragonfly as platform; #[cfg(target_os = "freebsd")] pub use os::freebsd as platform; +#[cfg(target_os = "haiku")] pub use os::haiku as platform; #[cfg(target_os = "ios")] pub use os::ios as platform; #[cfg(target_os = "linux")] pub use os::linux as platform; #[cfg(target_os = "macos")] pub use os::macos as platform; @@ -25,21 +26,26 @@ use libc; #[cfg(target_os = "openbsd")] pub use os::openbsd as platform; #[cfg(target_os = "solaris")] pub use os::solaris as platform; #[cfg(target_os = "emscripten")] pub use os::emscripten as platform; +#[cfg(target_os = "fuchsia")] pub use os::fuchsia as platform; #[macro_use] pub mod weak; +pub mod args; pub mod android; #[cfg(any(not(cargobuild), feature = "backtrace"))] 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; @@ -78,16 +84,16 @@ pub fn init() { unsafe { libc::write(libc::STDERR_FILENO, msg.as_ptr() as *const libc::c_void, - msg.len() as libc::size_t); + msg.len()); intrinsics::abort(); } } - #[cfg(not(any(target_os = "nacl", target_os = "emscripten")))] + #[cfg(not(any(target_os = "nacl", target_os = "emscripten", target_os="fuchsia")))] unsafe fn reset_sigpipe() { assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != !0); } - #[cfg(any(target_os = "nacl", target_os = "emscripten"))] + #[cfg(any(target_os = "nacl", target_os = "emscripten", target_os="fuchsia"))] unsafe fn reset_sigpipe() {} } diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index f124ea651ec..ad287bbec38 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -10,7 +10,7 @@ use ffi::CStr; use io; -use libc::{self, c_int, size_t, sockaddr, socklen_t}; +use libc::{self, c_int, size_t, sockaddr, socklen_t, EAI_SYSTEM}; use net::{SocketAddr, Shutdown}; use str; use sys::fd::FileDesc; @@ -33,12 +33,25 @@ use libc::SOCK_CLOEXEC; #[cfg(not(target_os = "linux"))] const SOCK_CLOEXEC: c_int = 0; +// Another conditional contant for name resolution: Macos et iOS use +// SO_NOSIGPIPE as a setsockopt flag to disable SIGPIPE emission on socket. +// Other platforms do otherwise. +#[cfg(target_vendor = "apple")] +use libc::SO_NOSIGPIPE; +#[cfg(not(target_vendor = "apple"))] +const SO_NOSIGPIPE: c_int = 0; + pub struct Socket(FileDesc); pub fn init() {} pub fn cvt_gai(err: c_int) -> io::Result<()> { - if err == 0 { return Ok(()) } + if err == 0 { + return Ok(()) + } + if err == EAI_SYSTEM { + return Err(io::Error::last_os_error()) + } let detail = unsafe { str::from_utf8(CStr::from_ptr(libc::gai_strerror(err)).to_bytes()).unwrap() @@ -76,7 +89,11 @@ impl Socket { let fd = cvt(libc::socket(fam, ty, 0))?; let fd = FileDesc::new(fd); fd.set_cloexec()?; - Ok(Socket(fd)) + let socket = Socket(fd); + if cfg!(target_vendor = "apple") { + setsockopt(&socket, libc::SOL_SOCKET, SO_NOSIGPIPE, 1)?; + } + Ok(socket) } } diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index 82606d2c728..e591f25cac1 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -38,7 +38,7 @@ static ENV_LOCK: Mutex = Mutex::new(); extern { #[cfg(not(target_os = "dragonfly"))] - #[cfg_attr(any(target_os = "linux", target_os = "emscripten"), + #[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", @@ -51,6 +51,7 @@ extern { target_os = "ios", target_os = "freebsd"), link_name = "__error")] + #[cfg_attr(target_os = "haiku", link_name = "_errnop")] fn errno_location() -> *mut c_int; } @@ -93,7 +94,7 @@ pub fn error_string(errno: i32) -> String { let p = buf.as_mut_ptr(); unsafe { - if strerror_r(errno as c_int, p, buf.len() as libc::size_t) < 0 { + if strerror_r(errno as c_int, p, buf.len()) < 0 { panic!("strerror_r failure"); } @@ -107,7 +108,7 @@ pub fn getcwd() -> io::Result<PathBuf> { loop { unsafe { let ptr = buf.as_mut_ptr() as *mut libc::c_char; - if !libc::getcwd(ptr, buf.capacity() as libc::size_t).is_null() { + 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(); @@ -199,21 +200,20 @@ pub fn current_exe() -> io::Result<PathBuf> { libc::KERN_PROC as c_int, libc::KERN_PROC_PATHNAME as c_int, -1 as c_int]; - let mut sz: libc::size_t = 0; + let mut sz = 0; cvt(libc::sysctl(mib.as_mut_ptr(), mib.len() as ::libc::c_uint, - ptr::null_mut(), &mut sz, ptr::null_mut(), - 0 as libc::size_t))?; + ptr::null_mut(), &mut sz, ptr::null_mut(), 0))?; if sz == 0 { return Err(io::Error::last_os_error()) } - let mut v: Vec<u8> = Vec::with_capacity(sz as usize); + let mut v: Vec<u8> = Vec::with_capacity(sz); cvt(libc::sysctl(mib.as_mut_ptr(), mib.len() as ::libc::c_uint, v.as_mut_ptr() as *mut libc::c_void, &mut sz, - ptr::null_mut(), 0 as libc::size_t))?; + ptr::null_mut(), 0))?; if sz == 0 { return Err(io::Error::last_os_error()); } - v.set_len(sz as usize - 1); // chop off trailing NUL + v.set_len(sz - 1); // chop off trailing NUL Ok(PathBuf::from(OsString::from_vec(v))) } } @@ -303,123 +303,53 @@ pub fn current_exe() -> io::Result<PathBuf> { } } -pub struct Args { - iter: vec::IntoIter<OsString>, - _dont_send_or_sync_me: PhantomData<*mut ()>, -} - -impl Iterator for Args { - type Item = OsString; - fn next(&mut self) -> Option<OsString> { self.iter.next() } - fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() } -} - -impl ExactSizeIterator for Args { - fn len(&self) -> usize { self.iter.len() } -} - -impl DoubleEndedIterator for Args { - fn next_back(&mut self) -> Option<OsString> { self.iter.next_back() } -} - -/// Returns the command line arguments -/// -/// Returns a list of the command line arguments. -#[cfg(target_os = "macos")] -pub fn args() -> Args { - extern { - // These functions are in crt_externs.h. - fn _NSGetArgc() -> *mut c_int; - fn _NSGetArgv() -> *mut *mut *mut c_char; - } - - let vec = unsafe { - let (argc, argv) = (*_NSGetArgc() as isize, - *_NSGetArgv() as *const *const c_char); - (0.. argc as isize).map(|i| { - let bytes = CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec(); - OsStringExt::from_vec(bytes) - }).collect::<Vec<_>>() - }; - Args { - iter: vec.into_iter(), - _dont_send_or_sync_me: PhantomData, - } -} - -// As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs -// and use underscores in their names - they're most probably -// are considered private and therefore should be avoided -// Here is another way to get arguments using Objective C -// runtime -// -// In general it looks like: -// res = Vec::new() -// let args = [[NSProcessInfo processInfo] arguments] -// for i in (0..[args count]) -// res.push([args objectAtIndex:i]) -// res -#[cfg(target_os = "ios")] -pub fn args() -> Args { - use mem; - - extern { - fn sel_registerName(name: *const libc::c_uchar) -> Sel; - fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId; - fn objc_getClass(class_name: *const libc::c_uchar) -> NsId; +#[cfg(target_os = "haiku")] +pub fn current_exe() -> io::Result<PathBuf> { + // Use Haiku's image info functions + #[repr(C)] + struct image_info { + id: i32, + type_: i32, + sequence: i32, + init_order: i32, + init_routine: *mut libc::c_void, // function pointer + term_routine: *mut libc::c_void, // function pointer + device: libc::dev_t, + node: libc::ino_t, + name: [libc::c_char; 1024], // MAXPATHLEN + text: *mut libc::c_void, + data: *mut libc::c_void, + text_size: i32, + data_size: i32, + api_version: i32, + abi: i32, } - #[link(name = "Foundation", kind = "framework")] - #[link(name = "objc")] - #[cfg(not(cargobuild))] - extern {} - - type Sel = *const libc::c_void; - type NsId = *const libc::c_void; - - let mut res = Vec::new(); - unsafe { - let process_info_sel = sel_registerName("processInfo\0".as_ptr()); - let arguments_sel = sel_registerName("arguments\0".as_ptr()); - let utf8_sel = sel_registerName("UTF8String\0".as_ptr()); - let count_sel = sel_registerName("count\0".as_ptr()); - let object_at_sel = sel_registerName("objectAtIndex:\0".as_ptr()); - - let klass = objc_getClass("NSProcessInfo\0".as_ptr()); - let info = objc_msgSend(klass, process_info_sel); - let args = objc_msgSend(info, arguments_sel); - - let cnt: usize = mem::transmute(objc_msgSend(args, count_sel)); - for i in 0..cnt { - let tmp = objc_msgSend(args, object_at_sel, i); - let utf_c_str: *const libc::c_char = - mem::transmute(objc_msgSend(tmp, utf8_sel)); - let bytes = CStr::from_ptr(utf_c_str).to_bytes(); - res.push(OsString::from(str::from_utf8(bytes).unwrap())) + extern { + fn _get_next_image_info(team_id: i32, cookie: *mut i32, + info: *mut image_info, size: i32) -> i32; } - } - Args { iter: res.into_iter(), _dont_send_or_sync_me: PhantomData } + let mut info: image_info = mem::zeroed(); + let mut cookie: i32 = 0; + // the executable can be found at team id 0 + let result = _get_next_image_info(0, &mut cookie, &mut info, + mem::size_of::<image_info>() as i32); + if result != 0 { + use io::ErrorKind; + Err(io::Error::new(ErrorKind::Other, "Error getting executable path")) + } else { + let name = CStr::from_ptr(info.name.as_ptr()).to_bytes(); + Ok(PathBuf::from(OsStr::from_bytes(name))) + } + } } -#[cfg(any(target_os = "linux", - target_os = "android", - target_os = "freebsd", - target_os = "dragonfly", - target_os = "bitrig", - target_os = "netbsd", - target_os = "openbsd", - target_os = "solaris", - target_os = "nacl", - target_os = "emscripten"))] -pub fn args() -> Args { - use sys_common; - let bytes = sys_common::args::clone().unwrap_or(Vec::new()); - let v: Vec<OsString> = bytes.into_iter().map(|v| { - OsStringExt::from_vec(v) - }).collect(); - Args { iter: v.into_iter(), _dont_send_or_sync_me: PhantomData } +#[cfg(target_os = "fuchsia")] +pub fn current_exe() -> io::Result<PathBuf> { + use io::ErrorKind; + Err(io::Error::new(ErrorKind::Other, "Not yet implemented on fuchsia")) } pub struct Env { @@ -563,7 +493,7 @@ pub fn home_dir() -> Option<PathBuf> { buf: &mut Vec<c_char>) -> Option<()> { let mut result = ptr::null_mut(); match libc::getpwuid_r(me, passwd, buf.as_mut_ptr(), - buf.capacity() as libc::size_t, + buf.capacity(), &mut result) { 0 if !result.is_null() => Some(()), _ => None @@ -576,7 +506,7 @@ pub fn home_dir() -> Option<PathBuf> { // getpwuid_r semantics is different on Illumos/Solaris: // http://illumos.org/man/3c/getpwuid_r let result = libc::getpwuid_r(me, passwd, buf.as_mut_ptr(), - buf.capacity() as libc::size_t); + buf.capacity()); if result.is_null() { None } else { Some(()) } } diff --git a/src/libstd/sys/unix/path.rs b/src/libstd/sys/unix/path.rs new file mode 100644 index 00000000000..bf9af7a4353 --- /dev/null +++ b/src/libstd/sys/unix/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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use path::Prefix; +use ffi::OsStr; + +#[inline] +pub fn is_sep_byte(b: u8) -> bool { + b == b'/' +} + +#[inline] +pub fn is_verbatim_sep(b: u8) -> bool { + b == b'/' +} + +pub fn parse_prefix(_: &OsStr) -> Option<Prefix> { + None +} + +pub const MAIN_SEP_STR: &'static str = "/"; +pub const MAIN_SEP: char = '/'; diff --git a/src/libstd/sys/unix/process.rs b/src/libstd/sys/unix/process.rs index 50014f51f6c..dafc11d9cc8 100644 --- a/src/libstd/sys/unix/process.rs +++ b/src/libstd/sys/unix/process.rs @@ -369,7 +369,7 @@ impl Command { } // NaCl has no signal support. - if cfg!(not(target_os = "nacl")) { + if cfg!(not(any(target_os = "nacl", target_os = "emscripten"))) { // Reset signal handling so the child process starts in a // standardized state. libstd ignores SIGPIPE, and signal-handling // libraries often set a mask. Child processes inherit ignored @@ -589,7 +589,7 @@ impl Process { } } -#[cfg(test)] +#[cfg(all(test, not(target_os = "emscripten")))] mod tests { use super::*; diff --git a/src/libstd/sys/unix/rand.rs b/src/libstd/sys/unix/rand.rs index 6b50ca9bcdf..3aebb8c18ec 100644 --- a/src/libstd/sys/unix/rand.rs +++ b/src/libstd/sys/unix/rand.rs @@ -27,7 +27,8 @@ fn next_u64(mut fill_buf: &mut FnMut(&mut [u8])) -> u64 { #[cfg(all(unix, not(target_os = "ios"), not(target_os = "openbsd"), - not(target_os = "freebsd")))] + not(target_os = "freebsd"), + not(target_os = "fuchsia")))] mod imp { use self::OsRngInner::*; use super::{next_u32, next_u64}; @@ -97,8 +98,8 @@ mod imp { // full entropy pool let reader = File::open("/dev/urandom").expect("Unable to open /dev/urandom"); let mut reader_rng = ReaderRng::new(reader); - reader_rng.fill_bytes(& mut v[read..]); - read += v.len() as usize; + reader_rng.fill_bytes(&mut v[read..]); + read += v.len(); } else { panic!("unexpected getrandom error: {}", err); } @@ -281,7 +282,7 @@ mod imp { } fn fill_bytes(&mut self, v: &mut [u8]) { let ret = unsafe { - SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, + SecRandomCopyBytes(kSecRandomDefault, v.len(), v.as_mut_ptr()) }; if ret == -1 { @@ -339,3 +340,54 @@ mod imp { } } } + +#[cfg(target_os = "fuchsia")] +mod imp { + use super::{next_u32, next_u64}; + + use io; + use rand::Rng; + + #[link(name = "magenta")] + extern { + fn mx_cprng_draw(buffer: *mut u8, len: usize) -> isize; + } + + fn getrandom(buf: &mut [u8]) -> isize { + unsafe { mx_cprng_draw(buf.as_mut_ptr(), buf.len()) } + } + + pub struct OsRng { + // dummy field to ensure that this struct cannot be constructed outside + // of this module + _dummy: (), + } + + impl OsRng { + /// Create a new `OsRng`. + pub fn new() -> io::Result<OsRng> { + Ok(OsRng { _dummy: () }) + } + } + + impl Rng for OsRng { + fn next_u32(&mut self) -> u32 { + next_u32(&mut |v| self.fill_bytes(v)) + } + fn next_u64(&mut self) -> u64 { + next_u64(&mut |v| self.fill_bytes(v)) + } + fn fill_bytes(&mut self, v: &mut [u8]) { + let mut buf = v; + while !buf.is_empty() { + let ret = getrandom(buf); + if ret < 0 { + panic!("kernel mx_cprng_draw call failed! (returned {}, buf.len() {})", + ret, buf.len()); + } + let move_buf = buf; + buf = &mut move_buf[(ret as usize)..]; + } + } + } +} diff --git a/src/libstd/sys/unix/stdio.rs b/src/libstd/sys/unix/stdio.rs index 972bdbc3818..947ba2cc752 100644 --- a/src/libstd/sys/unix/stdio.rs +++ b/src/libstd/sys/unix/stdio.rs @@ -65,3 +65,5 @@ impl io::Write for Stderr { } fn flush(&mut self) -> io::Result<()> { Ok(()) } } + +pub const EBADF_ERR: i32 = ::libc::EBADF as i32; diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index 5db7086e427..1642baa34d6 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -29,6 +29,20 @@ pub struct Thread { unsafe impl Send for Thread {} unsafe impl Sync for Thread {} +// The pthread_attr_setstacksize symbol doesn't exist in the emscripten libc, +// so we have to not link to it to satisfy emcc's ERROR_ON_UNDEFINED_SYMBOLS. +#[cfg(not(target_os = "emscripten"))] +unsafe fn pthread_attr_setstacksize(attr: *mut libc::pthread_attr_t, + stack_size: libc::size_t) -> libc::c_int { + libc::pthread_attr_setstacksize(attr, stack_size) +} + +#[cfg(target_os = "emscripten")] +unsafe fn pthread_attr_setstacksize(_attr: *mut libc::pthread_attr_t, + _stack_size: libc::size_t) -> libc::c_int { + panic!() +} + impl Thread { pub unsafe fn new<'a>(stack: usize, p: Box<FnBox() + 'a>) -> io::Result<Thread> { @@ -38,8 +52,8 @@ impl Thread { assert_eq!(libc::pthread_attr_init(&mut attr), 0); let stack_size = cmp::max(stack, min_stack_size(&attr)); - match libc::pthread_attr_setstacksize(&mut attr, - stack_size as libc::size_t) { + match pthread_attr_setstacksize(&mut attr, + stack_size) { 0 => {} n => { assert_eq!(n, libc::EINVAL); @@ -50,7 +64,6 @@ impl Thread { let page_size = os::page_size(); let stack_size = (stack_size + page_size - 1) & (-(page_size as isize - 1) as usize - 1); - let stack_size = stack_size as libc::size_t; assert_eq!(libc::pthread_attr_setstacksize(&mut attr, stack_size), 0); } @@ -115,9 +128,16 @@ impl Thread { name.as_ptr() as *mut libc::c_void); } } - #[cfg(any(target_env = "newlib", target_os = "solaris", target_os = "emscripten"))] + #[cfg(any(target_env = "newlib", + target_os = "solaris", + target_os = "haiku", + target_os = "emscripten"))] + pub fn set_name(_name: &CStr) { + // Newlib, Illumos, Haiku, and Emscripten have no way to set a thread name. + } + #[cfg(target_os = "fuchsia")] pub fn set_name(_name: &CStr) { - // Newlib, Illumos and Emscripten have no way to set a thread name. + // FIXME: determine whether Fuchsia has a way to set a thread name. } pub fn sleep(dur: Duration) { @@ -247,12 +267,8 @@ pub mod guard { // Rellocate the last page of the stack. // This ensures SIGBUS will be raised on // stack overflow. - let result = mmap(stackaddr, - psize as libc::size_t, - PROT_NONE, - MAP_PRIVATE | MAP_ANON | MAP_FIXED, - -1, - 0); + let result = mmap(stackaddr, psize, PROT_NONE, + MAP_PRIVATE | MAP_ANON | MAP_FIXED, -1, 0); if result != stackaddr || result == MAP_FAILED { panic!("failed to allocate a guard page"); @@ -276,8 +292,8 @@ pub mod guard { #[cfg(target_os = "macos")] pub unsafe fn current() -> Option<usize> { - Some((libc::pthread_get_stackaddr_np(libc::pthread_self()) as libc::size_t - - libc::pthread_get_stacksize_np(libc::pthread_self())) as usize) + Some((libc::pthread_get_stackaddr_np(libc::pthread_self()) as usize - + libc::pthread_get_stacksize_np(libc::pthread_self()))) } #[cfg(any(target_os = "openbsd", target_os = "bitrig"))] @@ -289,10 +305,10 @@ pub mod guard { let extra = if cfg!(target_os = "bitrig") {3} else {1} * os::page_size(); Some(if libc::pthread_main_np() == 1 { // main thread - current_stack.ss_sp as usize - current_stack.ss_size as usize + extra + current_stack.ss_sp as usize - current_stack.ss_size + extra } else { // new thread - current_stack.ss_sp as usize - current_stack.ss_size as usize + current_stack.ss_sp as usize - current_stack.ss_size }) } @@ -318,11 +334,11 @@ pub mod guard { &mut size), 0); ret = if cfg!(target_os = "freebsd") { - Some(stackaddr as usize - guardsize as usize) + Some(stackaddr as usize - guardsize) } else if cfg!(target_os = "netbsd") { Some(stackaddr as usize) } else { - Some(stackaddr as usize + guardsize as usize) + Some(stackaddr as usize + guardsize) }; } assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); @@ -341,8 +357,8 @@ fn min_stack_size(attr: *const libc::pthread_attr_t) -> usize { weak!(fn __pthread_get_minstack(*const libc::pthread_attr_t) -> libc::size_t); match __pthread_get_minstack.get() { - None => libc::PTHREAD_STACK_MIN as usize, - Some(f) => unsafe { f(attr) as usize }, + None => libc::PTHREAD_STACK_MIN, + Some(f) => unsafe { f(attr) }, } } @@ -351,7 +367,7 @@ fn min_stack_size(attr: *const libc::pthread_attr_t) -> usize { #[cfg(all(not(target_os = "linux"), not(target_os = "netbsd")))] fn min_stack_size(_: *const libc::pthread_attr_t) -> usize { - libc::PTHREAD_STACK_MIN as usize + libc::PTHREAD_STACK_MIN } #[cfg(target_os = "netbsd")] diff --git a/src/libstd/sys/windows/args.rs b/src/libstd/sys/windows/args.rs new file mode 100644 index 00000000000..aa61f9adb82 --- /dev/null +++ b/src/libstd/sys/windows/args.rs @@ -0,0 +1,76 @@ +// Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![allow(dead_code)] // runtime init functions not used during testing + +use os::windows::prelude::*; +use sys::c; +use slice; +use ops::Range; +use ffi::OsString; +use libc::{c_int, c_void}; + +pub unsafe fn init(_argc: isize, _argv: *const *const u8) { } + +pub unsafe fn cleanup() { } + +pub fn args() -> Args { + unsafe { + let mut nArgs: c_int = 0; + let lpCmdLine = c::GetCommandLineW(); + let szArgList = c::CommandLineToArgvW(lpCmdLine, &mut nArgs); + + // szArcList can be NULL if CommandLinToArgvW failed, + // but in that case nArgs is 0 so we won't actually + // try to read a null pointer + Args { cur: szArgList, range: 0..(nArgs as isize) } + } +} + +pub struct Args { + range: Range<isize>, + cur: *mut *mut u16, +} + +unsafe fn os_string_from_ptr(ptr: *mut u16) -> OsString { + let mut len = 0; + while *ptr.offset(len) != 0 { len += 1; } + + // Push it onto the list. + let ptr = ptr as *const u16; + let buf = slice::from_raw_parts(ptr, len as usize); + OsStringExt::from_wide(buf) +} + +impl Iterator for Args { + type Item = OsString; + fn next(&mut self) -> Option<OsString> { + self.range.next().map(|i| unsafe { os_string_from_ptr(*self.cur.offset(i)) } ) + } + fn size_hint(&self) -> (usize, Option<usize>) { self.range.size_hint() } +} + +impl DoubleEndedIterator for Args { + fn next_back(&mut self) -> Option<OsString> { + self.range.next_back().map(|i| unsafe { os_string_from_ptr(*self.cur.offset(i)) } ) + } +} + +impl ExactSizeIterator for Args { + fn len(&self) -> usize { self.range.len() } +} + +impl Drop for Args { + fn drop(&mut self) { + // self.cur can be null if CommandLineToArgvW previously failed, + // but LocalFree ignores NULL pointers + unsafe { c::LocalFree(self.cur as *mut c_void); } + } +} diff --git a/src/libstd/sys/windows/env.rs b/src/libstd/sys/windows/env.rs new file mode 100644 index 00000000000..e6d74895774 --- /dev/null +++ b/src/libstd/sys/windows/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 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub mod os { + pub const FAMILY: &'static str = "windows"; + pub const OS: &'static str = "windows"; + pub const DLL_PREFIX: &'static str = ""; + pub const DLL_SUFFIX: &'static str = ".dll"; + pub const DLL_EXTENSION: &'static str = "dll"; + pub const EXE_SUFFIX: &'static str = ".exe"; + pub const EXE_EXTENSION: &'static str = "exe"; +} diff --git a/src/libstd/sys/windows/ext/fs.rs b/src/libstd/sys/windows/ext/fs.rs index 4388a0bdff2..1e2b8bf38fa 100644 --- a/src/libstd/sys/windows/ext/fs.rs +++ b/src/libstd/sys/windows/ext/fs.rs @@ -12,12 +12,61 @@ #![stable(feature = "rust1", since = "1.0.0")] -use fs::{OpenOptions, Metadata}; +use fs::{self, OpenOptions, Metadata}; use io; use path::Path; use sys; use sys_common::{AsInnerMut, AsInner}; +/// Windows-specific extensions to `File` +#[unstable(feature = "file_offset", issue = "35918")] +pub trait FileExt { + /// Seeks to a given position and reads a number of bytes. + /// + /// Returns the number of bytes read. + /// + /// The offset is relative to the start of the file and thus independent + /// from the current cursor. The current cursor **is** affected by this + /// function, it is set to the end of the read. + /// + /// Reading beyond the end of the file will always return with a length of + /// 0. + /// + /// Note that similar to `File::read`, it is not an error to return with a + /// short read. When returning from such a short read, the file pointer is + /// still updated. + #[unstable(feature = "file_offset", issue = "35918")] + fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>; + + /// Seeks to a given position and writes a number of bytes. + /// + /// Returns the number of bytes written. + /// + /// The offset is relative to the start of the file and thus independent + /// from the current cursor. The current cursor **is** affected by this + /// function, it is set to the end of the write. + /// + /// When writing beyond the end of the file, the file is appropiately + /// extended and the intermediate bytes are left uninitialized. + /// + /// Note that similar to `File::write`, it is not an error to return a + /// short write. When returning from such a short write, the file pointer + /// is still updated. + #[unstable(feature = "file_offset", issue = "35918")] + fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result<usize>; +} + +#[unstable(feature = "file_offset", issue = "35918")] +impl FileExt for fs::File { + fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { + self.as_inner().read_at(buf, offset) + } + + fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result<usize> { + self.as_inner().write_at(buf, offset) + } +} + /// Windows-specific extensions to `OpenOptions` #[stable(feature = "open_options_ext", since = "1.10.0")] pub trait OpenOptionsExt { diff --git a/src/libstd/sys/windows/ext/mod.rs b/src/libstd/sys/windows/ext/mod.rs index c3578fdfdb1..932bb5e9564 100644 --- a/src/libstd/sys/windows/ext/mod.rs +++ b/src/libstd/sys/windows/ext/mod.rs @@ -36,4 +36,6 @@ pub mod prelude { pub use super::ffi::{OsStrExt, OsStringExt}; #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")] pub use super::fs::{OpenOptionsExt, MetadataExt}; + #[doc(no_inline)] #[unstable(feature = "file_offset", issue = "35918")] + pub use super::fs::FileExt; } diff --git a/src/libstd/sys/windows/ext/process.rs b/src/libstd/sys/windows/ext/process.rs index 98166bf8cda..bce32959a23 100644 --- a/src/libstd/sys/windows/ext/process.rs +++ b/src/libstd/sys/windows/ext/process.rs @@ -33,7 +33,7 @@ impl AsRawHandle for process::Child { } } -#[stable(feature = "process_extensions", since = "1.2.0")] +#[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawHandle for process::Child { fn into_raw_handle(self) -> RawHandle { self.into_inner().into_handle().into_raw() as *mut _ @@ -61,21 +61,21 @@ impl AsRawHandle for process::ChildStderr { } } -#[stable(feature = "process_extensions", since = "1.2.0")] +#[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawHandle for process::ChildStdin { fn into_raw_handle(self) -> RawHandle { self.into_inner().into_handle().into_raw() as *mut _ } } -#[stable(feature = "process_extensions", since = "1.2.0")] +#[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawHandle for process::ChildStdout { fn into_raw_handle(self) -> RawHandle { self.into_inner().into_handle().into_raw() as *mut _ } } -#[stable(feature = "process_extensions", since = "1.2.0")] +#[stable(feature = "into_raw_os", since = "1.4.0")] impl IntoRawHandle for process::ChildStderr { fn into_raw_handle(self) -> RawHandle { self.into_inner().into_handle().into_raw() as *mut _ @@ -91,7 +91,7 @@ pub trait ExitStatusExt { fn from_raw(raw: u32) -> Self; } -#[stable(feature = "rust1", since = "1.0.0")] +#[stable(feature = "exit_status_from", since = "1.12.0")] impl ExitStatusExt for process::ExitStatus { fn from_raw(raw: u32) -> Self { process::ExitStatus::from_inner(From::from(raw)) diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index 90a16853d56..98fd15f863b 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -81,6 +81,14 @@ pub struct FilePermissions { attrs: c::DWORD } pub struct DirBuilder; +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("C:\")' + fmt::Debug::fmt(&*self.root, f) + } +} + impl Iterator for ReadDir { type Item = io::Result<DirEntry>; fn next(&mut self) -> Option<io::Result<DirEntry>> { @@ -311,6 +319,10 @@ impl File { self.handle.read(buf) } + pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { + self.handle.read_at(buf, offset) + } + pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> { self.handle.read_to_end(buf) } @@ -319,6 +331,10 @@ impl File { self.handle.write(buf) } + pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { + self.handle.write_at(buf, offset) + } + pub fn flush(&self) -> io::Result<()> { Ok(()) } pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> { diff --git a/src/libstd/sys/windows/handle.rs b/src/libstd/sys/windows/handle.rs index 97e746ee345..10b86ba44bc 100644 --- a/src/libstd/sys/windows/handle.rs +++ b/src/libstd/sys/windows/handle.rs @@ -104,6 +104,23 @@ impl RawHandle { } } + pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { + let mut read = 0; + let len = cmp::min(buf.len(), <c::DWORD>::max_value() as usize) as c::DWORD; + let res = unsafe { + let mut overlapped: c::OVERLAPPED = mem::zeroed(); + overlapped.Offset = offset as u32; + overlapped.OffsetHigh = (offset >> 32) as u32; + cvt(c::ReadFile(self.0, buf.as_mut_ptr() as c::LPVOID, + len, &mut read, &mut overlapped)) + }; + match res { + Ok(_) => Ok(read as usize), + Err(ref e) if e.raw_os_error() == Some(c::ERROR_HANDLE_EOF as i32) => Ok(0), + Err(e) => Err(e), + } + } + pub unsafe fn read_overlapped(&self, buf: &mut [u8], overlapped: *mut c::OVERLAPPED) @@ -174,6 +191,19 @@ impl RawHandle { Ok(amt as usize) } + pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { + let mut written = 0; + let len = cmp::min(buf.len(), <c::DWORD>::max_value() as usize) as c::DWORD; + unsafe { + let mut overlapped: c::OVERLAPPED = mem::zeroed(); + overlapped.Offset = offset as u32; + overlapped.OffsetHigh = (offset >> 32) as u32; + cvt(c::WriteFile(self.0, buf.as_ptr() as c::LPVOID, + len, &mut written, &mut overlapped))?; + } + Ok(written as usize) + } + pub fn duplicate(&self, access: c::DWORD, inherit: bool, options: c::DWORD) -> io::Result<Handle> { let mut ret = 0 as c::HANDLE; diff --git a/src/libstd/sys/windows/memchr.rs b/src/libstd/sys/windows/memchr.rs new file mode 100644 index 00000000000..5a5386acaa5 --- /dev/null +++ b/src/libstd/sys/windows/memchr.rs @@ -0,0 +1,15 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. +// +// Original implementation taken from rust-memchr +// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch + +// Fallback memchr is fastest on windows +pub use sys_common::memchr::fallback::{memchr, memrchr}; diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index 9741a704e8f..9cd6e6ca176 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -18,17 +18,21 @@ use time::Duration; #[macro_use] pub mod compat; +pub mod args; pub mod backtrace; pub mod c; pub mod condvar; pub mod dynamic_lib; +pub mod env; pub mod ext; pub mod fs; pub mod handle; +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; diff --git a/src/libstd/sys/windows/os.rs b/src/libstd/sys/windows/os.rs index 260fc3c4db6..7e28dd1e259 100644 --- a/src/libstd/sys/windows/os.rs +++ b/src/libstd/sys/windows/os.rs @@ -18,8 +18,6 @@ use error::Error as StdError; use ffi::{OsString, OsStr}; use fmt; use io; -use libc::{c_int, c_void}; -use ops::Range; use os::windows::ffi::EncodeWide; use path::{self, PathBuf}; use ptr; @@ -272,60 +270,6 @@ pub fn unsetenv(n: &OsStr) -> io::Result<()> { }).map(|_| ()) } -pub struct Args { - range: Range<isize>, - cur: *mut *mut u16, -} - -unsafe fn os_string_from_ptr(ptr: *mut u16) -> OsString { - let mut len = 0; - while *ptr.offset(len) != 0 { len += 1; } - - // Push it onto the list. - let ptr = ptr as *const u16; - let buf = slice::from_raw_parts(ptr, len as usize); - OsStringExt::from_wide(buf) -} - -impl Iterator for Args { - type Item = OsString; - fn next(&mut self) -> Option<OsString> { - self.range.next().map(|i| unsafe { os_string_from_ptr(*self.cur.offset(i)) } ) - } - fn size_hint(&self) -> (usize, Option<usize>) { self.range.size_hint() } -} - -impl DoubleEndedIterator for Args { - fn next_back(&mut self) -> Option<OsString> { - self.range.next_back().map(|i| unsafe { os_string_from_ptr(*self.cur.offset(i)) } ) - } -} - -impl ExactSizeIterator for Args { - fn len(&self) -> usize { self.range.len() } -} - -impl Drop for Args { - fn drop(&mut self) { - // self.cur can be null if CommandLineToArgvW previously failed, - // but LocalFree ignores NULL pointers - unsafe { c::LocalFree(self.cur as *mut c_void); } - } -} - -pub fn args() -> Args { - unsafe { - let mut nArgs: c_int = 0; - let lpCmdLine = c::GetCommandLineW(); - let szArgList = c::CommandLineToArgvW(lpCmdLine, &mut nArgs); - - // szArcList can be NULL if CommandLinToArgvW failed, - // but in that case nArgs is 0 so we won't actually - // try to read a null pointer - Args { cur: szArgList, range: 0..(nArgs as isize) } - } -} - pub fn temp_dir() -> PathBuf { super::fill_utf16_buf(|buf, sz| unsafe { c::GetTempPathW(sz, buf) diff --git a/src/libstd/sys/windows/path.rs b/src/libstd/sys/windows/path.rs new file mode 100644 index 00000000000..2b47808451b --- /dev/null +++ b/src/libstd/sys/windows/path.rs @@ -0,0 +1,108 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use ascii::*; + +use path::Prefix; +use ffi::OsStr; +use mem; + +fn os_str_as_u8_slice(s: &OsStr) -> &[u8] { + unsafe { mem::transmute(s) } +} +unsafe fn u8_slice_as_os_str(s: &[u8]) -> &OsStr { + mem::transmute(s) +} + +#[inline] +pub fn is_sep_byte(b: u8) -> bool { + b == b'/' || b == b'\\' +} + +#[inline] +pub fn is_verbatim_sep(b: u8) -> bool { + b == b'\\' +} + +pub fn parse_prefix<'a>(path: &'a OsStr) -> Option<Prefix> { + use path::Prefix::*; + unsafe { + // The unsafety here stems from converting between &OsStr and &[u8] + // and back. This is safe to do because (1) we only look at ASCII + // contents of the encoding and (2) new &OsStr values are produced + // only from ASCII-bounded slices of existing &OsStr values. + let mut path = os_str_as_u8_slice(path); + + if path.starts_with(br"\\") { + // \\ + path = &path[2..]; + if path.starts_with(br"?\") { + // \\?\ + path = &path[2..]; + if path.starts_with(br"UNC\") { + // \\?\UNC\server\share + path = &path[4..]; + let (server, share) = match parse_two_comps(path, is_verbatim_sep) { + Some((server, share)) => + (u8_slice_as_os_str(server), u8_slice_as_os_str(share)), + None => (u8_slice_as_os_str(path), u8_slice_as_os_str(&[])), + }; + return Some(VerbatimUNC(server, share)); + } else { + // \\?\path + let idx = path.iter().position(|&b| b == b'\\'); + if idx == Some(2) && path[1] == b':' { + let c = path[0]; + if c.is_ascii() && (c as char).is_alphabetic() { + // \\?\C:\ path + return Some(VerbatimDisk(c.to_ascii_uppercase())); + } + } + let slice = &path[..idx.unwrap_or(path.len())]; + return Some(Verbatim(u8_slice_as_os_str(slice))); + } + } else if path.starts_with(b".\\") { + // \\.\path + path = &path[2..]; + let pos = path.iter().position(|&b| b == b'\\'); + let slice = &path[..pos.unwrap_or(path.len())]; + return Some(DeviceNS(u8_slice_as_os_str(slice))); + } + match parse_two_comps(path, is_sep_byte) { + Some((server, share)) if !server.is_empty() && !share.is_empty() => { + // \\server\share + return Some(UNC(u8_slice_as_os_str(server), u8_slice_as_os_str(share))); + } + _ => (), + } + } else if path.get(1) == Some(& b':') { + // C: + let c = path[0]; + if c.is_ascii() && (c as char).is_alphabetic() { + return Some(Disk(c.to_ascii_uppercase())); + } + } + return None; + } + + fn parse_two_comps(mut path: &[u8], f: fn(u8) -> bool) -> Option<(&[u8], &[u8])> { + let first = match path.iter().position(|x| f(*x)) { + None => return None, + Some(x) => &path[..x], + }; + path = &path[(first.len() + 1)..]; + let idx = path.iter().position(|x| f(*x)); + let second = &path[..idx.unwrap_or(path.len())]; + Some((first, second)) + } +} + +pub const MAIN_SEP_STR: &'static str = "\\"; +pub const MAIN_SEP: char = '\\'; diff --git a/src/libstd/sys/windows/stdio.rs b/src/libstd/sys/windows/stdio.rs index 01249f05f62..5f097d2631d 100644 --- a/src/libstd/sys/windows/stdio.rs +++ b/src/libstd/sys/windows/stdio.rs @@ -205,3 +205,5 @@ impl Output { fn invalid_encoding() -> io::Error { io::Error::new(io::ErrorKind::InvalidData, "text was not valid unicode") } + +pub const EBADF_ERR: i32 = ::sys::c::ERROR_INVALID_HANDLE as i32; |
