diff options
| author | bors <bors@rust-lang.org> | 2015-02-19 18:36:59 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2015-02-19 18:36:59 +0000 |
| commit | 522d09dfecbeca1595f25ac58c6d0178bbd21d7d (patch) | |
| tree | cc0252dd3413e5f890d0ebcfdaa096e5b002be0b /src/libstd/sys | |
| parent | 0b664bb8436f2cfda7f13a6f302ab486f332816f (diff) | |
| parent | 49771bafa5fca16486bfd06741dac3de2c587adf (diff) | |
| download | rust-522d09dfecbeca1595f25ac58c6d0178bbd21d7d.tar.gz rust-522d09dfecbeca1595f25ac58c6d0178bbd21d7d.zip | |
Auto merge of #22541 - Manishearth:rollup, r=Gankro 1.0.0-alpha.2
Continued from #22520
Diffstat (limited to 'src/libstd/sys')
| -rw-r--r-- | src/libstd/sys/common/net.rs | 17 | ||||
| -rw-r--r-- | src/libstd/sys/common/net2.rs | 2 | ||||
| -rw-r--r-- | src/libstd/sys/common/wtf8.rs | 38 | ||||
| -rw-r--r-- | src/libstd/sys/unix/backtrace.rs | 6 | ||||
| -rw-r--r-- | src/libstd/sys/unix/ext.rs | 12 | ||||
| -rw-r--r-- | src/libstd/sys/unix/fs.rs | 42 | ||||
| -rw-r--r-- | src/libstd/sys/unix/fs2.rs | 44 | ||||
| -rw-r--r-- | src/libstd/sys/unix/mod.rs | 5 | ||||
| -rw-r--r-- | src/libstd/sys/unix/net.rs | 4 | ||||
| -rw-r--r-- | src/libstd/sys/unix/os.rs | 28 | ||||
| -rw-r--r-- | src/libstd/sys/unix/pipe.rs | 6 | ||||
| -rw-r--r-- | src/libstd/sys/unix/process.rs | 249 | ||||
| -rw-r--r-- | src/libstd/sys/unix/process2.rs | 9 | ||||
| -rw-r--r-- | src/libstd/sys/unix/thread.rs | 6 | ||||
| -rw-r--r-- | src/libstd/sys/windows/backtrace.rs | 4 | ||||
| -rw-r--r-- | src/libstd/sys/windows/c.rs | 2 | ||||
| -rw-r--r-- | src/libstd/sys/windows/mod.rs | 4 | ||||
| -rw-r--r-- | src/libstd/sys/windows/os.rs | 10 | ||||
| -rw-r--r-- | src/libstd/sys/windows/process.rs | 195 |
19 files changed, 580 insertions, 103 deletions
diff --git a/src/libstd/sys/common/net.rs b/src/libstd/sys/common/net.rs index 7325e0a5ac8..e2ac5ac24f8 100644 --- a/src/libstd/sys/common/net.rs +++ b/src/libstd/sys/common/net.rs @@ -12,8 +12,7 @@ use prelude::v1::*; use self::SocketStatus::*; use self::InAddr::*; -use ffi::CString; -use ffi; +use ffi::{CString, CStr}; use old_io::net::addrinfo; use old_io::net::ip::{SocketAddr, IpAddr, Ipv4Addr, Ipv6Addr}; use old_io::{IoResult, IoError}; @@ -235,9 +234,15 @@ pub fn get_host_addresses(host: Option<&str>, servname: Option<&str>, assert!(host.is_some() || servname.is_some()); - let c_host = host.map(|x| CString::from_slice(x.as_bytes())); + let c_host = match host { + Some(x) => Some(try!(CString::new(x))), + None => None, + }; let c_host = c_host.as_ref().map(|x| x.as_ptr()).unwrap_or(null()); - let c_serv = servname.map(|x| CString::from_slice(x.as_bytes())); + let c_serv = match servname { + Some(x) => Some(try!(CString::new(x))), + None => None, + }; let c_serv = c_serv.as_ref().map(|x| x.as_ptr()).unwrap_or(null()); let hint = hint.map(|hint| { @@ -325,8 +330,8 @@ pub fn get_address_name(addr: IpAddr) -> Result<String, IoError> { } unsafe { - Ok(str::from_utf8(ffi::c_str_to_bytes(&hostbuf.as_ptr())) - .unwrap().to_string()) + let data = CStr::from_ptr(hostbuf.as_ptr()); + Ok(str::from_utf8(data.to_bytes()).unwrap().to_string()) } } diff --git a/src/libstd/sys/common/net2.rs b/src/libstd/sys/common/net2.rs index 5af59ec6d2b..713f79c5d08 100644 --- a/src/libstd/sys/common/net2.rs +++ b/src/libstd/sys/common/net2.rs @@ -121,7 +121,7 @@ impl Drop for LookupHost { pub fn lookup_host(host: &str) -> io::Result<LookupHost> { init(); - let c_host = CString::from_slice(host.as_bytes()); + let c_host = try!(CString::new(host)); let mut res = 0 as *mut _; unsafe { try!(cvt_gai(getaddrinfo(c_host.as_ptr(), 0 as *const _, 0 as *const _, diff --git a/src/libstd/sys/common/wtf8.rs b/src/libstd/sys/common/wtf8.rs index b610f6c370b..ca3ae1a7a34 100644 --- a/src/libstd/sys/common/wtf8.rs +++ b/src/libstd/sys/common/wtf8.rs @@ -31,8 +31,9 @@ use ascii::*; use borrow::Cow; use cmp; use fmt; -use hash::{Hash, Writer, Hasher}; -use iter::FromIterator; +use hash::{Hash, Hasher}; +#[cfg(stage0)] use hash::Writer; +use iter::{FromIterator, IntoIterator}; use mem; use num::Int; use ops; @@ -356,9 +357,9 @@ impl Wtf8Buf { /// This replaces surrogate code point pairs with supplementary code points, /// like concatenating ill-formed UTF-16 strings effectively would. impl FromIterator<CodePoint> for Wtf8Buf { - fn from_iter<T: Iterator<Item=CodePoint>>(iterator: T) -> Wtf8Buf { + fn from_iter<T: IntoIterator<Item=CodePoint>>(iter: T) -> Wtf8Buf { let mut string = Wtf8Buf::new(); - string.extend(iterator); + string.extend(iter); string } } @@ -368,7 +369,8 @@ impl FromIterator<CodePoint> for Wtf8Buf { /// This replaces surrogate code point pairs with supplementary code points, /// like concatenating ill-formed UTF-16 strings effectively would. impl Extend<CodePoint> for Wtf8Buf { - fn extend<T: Iterator<Item=CodePoint>>(&mut self, iterator: T) { + fn extend<T: IntoIterator<Item=CodePoint>>(&mut self, iterable: T) { + let iterator = iterable.into_iter(); let (low, _high) = iterator.size_hint(); // Lower bound of one byte per code point (ASCII only) self.bytes.reserve(low); @@ -794,13 +796,22 @@ impl<'a> Iterator for EncodeWide<'a> { } } +#[cfg(stage0)] impl<S: Writer + Hasher> Hash<S> for CodePoint { #[inline] fn hash(&self, state: &mut S) { self.value.hash(state) } } +#[cfg(not(stage0))] +impl Hash for CodePoint { + #[inline] + fn hash<H: Hasher>(&self, state: &mut H) { + self.value.hash(state) + } +} +#[cfg(stage0)] impl<S: Writer + Hasher> Hash<S> for Wtf8Buf { #[inline] fn hash(&self, state: &mut S) { @@ -808,7 +819,16 @@ impl<S: Writer + Hasher> Hash<S> for Wtf8Buf { 0xfeu8.hash(state) } } +#[cfg(not(stage0))] +impl Hash for Wtf8Buf { + #[inline] + fn hash<H: Hasher>(&self, state: &mut H) { + state.write(&self.bytes); + 0xfeu8.hash(state) + } +} +#[cfg(stage0)] impl<'a, S: Writer + Hasher> Hash<S> for Wtf8 { #[inline] fn hash(&self, state: &mut S) { @@ -816,6 +836,14 @@ impl<'a, S: Writer + Hasher> Hash<S> for Wtf8 { 0xfeu8.hash(state) } } +#[cfg(not(stage0))] +impl Hash for Wtf8 { + #[inline] + fn hash<H: Hasher>(&self, state: &mut H) { + state.write(&self.bytes); + 0xfeu8.hash(state) + } +} impl AsciiExt for Wtf8 { type Owned = Wtf8Buf; diff --git a/src/libstd/sys/unix/backtrace.rs b/src/libstd/sys/unix/backtrace.rs index 5e512e9261b..8b560339f30 100644 --- a/src/libstd/sys/unix/backtrace.rs +++ b/src/libstd/sys/unix/backtrace.rs @@ -85,7 +85,7 @@ use prelude::v1::*; -use ffi; +use ffi::CStr; use old_io::IoResult; use libc; use mem; @@ -233,7 +233,7 @@ fn print(w: &mut Writer, idx: int, addr: *mut libc::c_void) -> IoResult<()> { output(w, idx,addr, None) } else { output(w, idx, addr, Some(unsafe { - ffi::c_str_to_bytes(&info.dli_sname) + CStr::from_ptr(info.dli_sname).to_bytes() })) } } @@ -364,7 +364,7 @@ fn print(w: &mut Writer, idx: int, addr: *mut libc::c_void) -> IoResult<()> { if ret == 0 || data.is_null() { output(w, idx, addr, None) } else { - output(w, idx, addr, Some(unsafe { ffi::c_str_to_bytes(&data) })) + output(w, idx, addr, Some(unsafe { CStr::from_ptr(data).to_bytes() })) } } diff --git a/src/libstd/sys/unix/ext.rs b/src/libstd/sys/unix/ext.rs index bbbe022fbaf..b8b9dcfb3c6 100644 --- a/src/libstd/sys/unix/ext.rs +++ b/src/libstd/sys/unix/ext.rs @@ -33,7 +33,7 @@ use prelude::v1::*; -use ffi::{CString, OsStr, OsString}; +use ffi::{CString, NulError, OsStr, OsString}; use fs::{self, Permissions, OpenOptions}; use net; use mem; @@ -155,7 +155,7 @@ pub trait OsStrExt { fn as_bytes(&self) -> &[u8]; /// Convert the `OsStr` slice into a `CString`. - fn to_cstring(&self) -> CString; + fn to_cstring(&self) -> Result<CString, NulError>; } impl OsStrExt for OsStr { @@ -166,8 +166,8 @@ impl OsStrExt for OsStr { &self.as_inner().inner } - fn to_cstring(&self) -> CString { - CString::from_slice(self.as_bytes()) + fn to_cstring(&self) -> Result<CString, NulError> { + CString::new(self.as_bytes()) } } @@ -249,5 +249,7 @@ impl ExitStatusExt for process::ExitStatus { /// Includes all extension traits, and some important type definitions. pub mod prelude { #[doc(no_inline)] - pub use super::{Fd, AsRawFd, OsStrExt, OsStringExt, PermissionsExt, CommandExt, ExitStatusExt}; + pub use super::{Fd, AsRawFd, OsStrExt, OsStringExt, PermissionsExt}; + #[doc(no_inline)] + pub use super::{CommandExt, ExitStatusExt}; } diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index 0ee2b5b6809..5c847002d23 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -12,7 +12,7 @@ use prelude::v1::*; -use ffi::{self, CString}; +use ffi::{CString, CStr}; use old_io::{FilePermission, Write, UnstableFileStat, Open, FileAccess, FileMode}; use old_io::{IoResult, FileStat, SeekStyle}; use old_io::{Read, Truncate, SeekCur, SeekSet, ReadWrite, SeekEnd, Append}; @@ -151,8 +151,8 @@ impl Drop for FileDesc { } } -fn cstr(path: &Path) -> CString { - CString::from_slice(path.as_vec()) +fn cstr(path: &Path) -> IoResult<CString> { + Ok(try!(CString::new(path.as_vec()))) } pub fn open(path: &Path, fm: FileMode, fa: FileAccess) -> IoResult<FileDesc> { @@ -170,7 +170,7 @@ pub fn open(path: &Path, fm: FileMode, fa: FileAccess) -> IoResult<FileDesc> { libc::S_IRUSR | libc::S_IWUSR), }; - let path = cstr(path); + let path = try!(cstr(path)); match retry(|| unsafe { libc::open(path.as_ptr(), flags, mode) }) { -1 => Err(super::last_error()), fd => Ok(FileDesc::new(fd, true)), @@ -178,7 +178,7 @@ pub fn open(path: &Path, fm: FileMode, fa: FileAccess) -> IoResult<FileDesc> { } pub fn mkdir(p: &Path, mode: uint) -> IoResult<()> { - let p = cstr(p); + let p = try!(cstr(p)); mkerr_libc(unsafe { libc::mkdir(p.as_ptr(), mode as libc::mode_t) }) } @@ -203,7 +203,7 @@ pub fn readdir(p: &Path) -> IoResult<Vec<Path>> { let mut buf = Vec::<u8>::with_capacity(size as uint); let ptr = buf.as_mut_ptr() as *mut dirent_t; - let p = CString::from_slice(p.as_vec()); + let p = try!(CString::new(p.as_vec())); let dir_ptr = unsafe {opendir(p.as_ptr())}; if dir_ptr as uint != 0 { @@ -212,7 +212,7 @@ pub fn readdir(p: &Path) -> IoResult<Vec<Path>> { while unsafe { readdir_r(dir_ptr, ptr, &mut entry_ptr) == 0 } { if entry_ptr.is_null() { break } paths.push(unsafe { - Path::new(ffi::c_str_to_bytes(&rust_list_dir_val(entry_ptr))) + Path::new(CStr::from_ptr(rust_list_dir_val(entry_ptr)).to_bytes()) }); } assert_eq!(unsafe { closedir(dir_ptr) }, 0); @@ -223,39 +223,39 @@ pub fn readdir(p: &Path) -> IoResult<Vec<Path>> { } pub fn unlink(p: &Path) -> IoResult<()> { - let p = cstr(p); + let p = try!(cstr(p)); mkerr_libc(unsafe { libc::unlink(p.as_ptr()) }) } pub fn rename(old: &Path, new: &Path) -> IoResult<()> { - let old = cstr(old); - let new = cstr(new); + let old = try!(cstr(old)); + let new = try!(cstr(new)); mkerr_libc(unsafe { libc::rename(old.as_ptr(), new.as_ptr()) }) } pub fn chmod(p: &Path, mode: uint) -> IoResult<()> { - let p = cstr(p); + let p = try!(cstr(p)); mkerr_libc(retry(|| unsafe { libc::chmod(p.as_ptr(), mode as libc::mode_t) })) } pub fn rmdir(p: &Path) -> IoResult<()> { - let p = cstr(p); + let p = try!(cstr(p)); mkerr_libc(unsafe { libc::rmdir(p.as_ptr()) }) } pub fn chown(p: &Path, uid: int, gid: int) -> IoResult<()> { - let p = cstr(p); + let p = try!(cstr(p)); mkerr_libc(retry(|| unsafe { libc::chown(p.as_ptr(), uid as libc::uid_t, gid as libc::gid_t) })) } pub fn readlink(p: &Path) -> IoResult<Path> { - let c_path = cstr(p); + let c_path = try!(cstr(p)); let p = c_path.as_ptr(); let mut len = unsafe { libc::pathconf(p as *mut _, libc::_PC_NAME_MAX) }; if len == -1 { @@ -276,14 +276,14 @@ pub fn readlink(p: &Path) -> IoResult<Path> { } pub fn symlink(src: &Path, dst: &Path) -> IoResult<()> { - let src = cstr(src); - let dst = cstr(dst); + let src = try!(cstr(src)); + let dst = try!(cstr(dst)); mkerr_libc(unsafe { libc::symlink(src.as_ptr(), dst.as_ptr()) }) } pub fn link(src: &Path, dst: &Path) -> IoResult<()> { - let src = cstr(src); - let dst = cstr(dst); + let src = try!(cstr(src)); + let dst = try!(cstr(dst)); mkerr_libc(unsafe { libc::link(src.as_ptr(), dst.as_ptr()) }) } @@ -331,7 +331,7 @@ fn mkstat(stat: &libc::stat) -> FileStat { } pub fn stat(p: &Path) -> IoResult<FileStat> { - let p = cstr(p); + let p = try!(cstr(p)); let mut stat: libc::stat = unsafe { mem::zeroed() }; match unsafe { libc::stat(p.as_ptr(), &mut stat) } { 0 => Ok(mkstat(&stat)), @@ -340,7 +340,7 @@ pub fn stat(p: &Path) -> IoResult<FileStat> { } pub fn lstat(p: &Path) -> IoResult<FileStat> { - let p = cstr(p); + let p = try!(cstr(p)); let mut stat: libc::stat = unsafe { mem::zeroed() }; match unsafe { libc::lstat(p.as_ptr(), &mut stat) } { 0 => Ok(mkstat(&stat)), @@ -349,7 +349,7 @@ pub fn lstat(p: &Path) -> IoResult<FileStat> { } pub fn utime(p: &Path, atime: u64, mtime: u64) -> IoResult<()> { - let p = cstr(p); + let p = try!(cstr(p)); let buf = libc::utimbuf { actime: (atime / 1000) as libc::time_t, modtime: (mtime / 1000) as libc::time_t, diff --git a/src/libstd/sys/unix/fs2.rs b/src/libstd/sys/unix/fs2.rs index e5904b074bc..92a47c6c385 100644 --- a/src/libstd/sys/unix/fs2.rs +++ b/src/libstd/sys/unix/fs2.rs @@ -12,7 +12,7 @@ use core::prelude::*; use io::prelude::*; use os::unix::prelude::*; -use ffi::{self, CString, OsString, AsOsStr, OsStr}; +use ffi::{CString, CStr, OsString, AsOsStr, OsStr}; use io::{self, Error, Seek, SeekFrom}; use libc::{self, c_int, c_void, size_t, off_t, c_char, mode_t}; use mem; @@ -147,8 +147,7 @@ impl DirEntry { fn rust_list_dir_val(ptr: *mut libc::dirent_t) -> *const c_char; } unsafe { - let ptr = rust_list_dir_val(self.dirent); - ffi::c_str_to_bytes(mem::copy_lifetime(self, &ptr)) + CStr::from_ptr(rust_list_dir_val(self.dirent)).to_bytes() } } } @@ -204,7 +203,7 @@ impl File { (true, false) | (false, false) => libc::O_RDONLY, }; - let path = cstr(path); + let path = try!(cstr(path)); let fd = try!(cvt_r(|| unsafe { libc::open(path.as_ptr(), flags, opts.mode) })); @@ -268,19 +267,20 @@ impl File { pub fn fd(&self) -> &FileDesc { &self.0 } } -fn cstr(path: &Path) -> CString { - CString::from_slice(path.as_os_str().as_bytes()) +fn cstr(path: &Path) -> io::Result<CString> { + let cstring = try!(path.as_os_str().to_cstring()); + Ok(cstring) } pub fn mkdir(p: &Path) -> io::Result<()> { - let p = cstr(p); + let p = try!(cstr(p)); try!(cvt(unsafe { libc::mkdir(p.as_ptr(), 0o777) })); Ok(()) } pub fn readdir(p: &Path) -> io::Result<ReadDir> { let root = Rc::new(p.to_path_buf()); - let p = cstr(p); + let p = try!(cstr(p)); unsafe { let ptr = libc::opendir(p.as_ptr()); if ptr.is_null() { @@ -292,32 +292,32 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> { } pub fn unlink(p: &Path) -> io::Result<()> { - let p = cstr(p); + let p = try!(cstr(p)); try!(cvt(unsafe { libc::unlink(p.as_ptr()) })); Ok(()) } pub fn rename(old: &Path, new: &Path) -> io::Result<()> { - let old = cstr(old); - let new = cstr(new); + let old = try!(cstr(old)); + let new = try!(cstr(new)); try!(cvt(unsafe { libc::rename(old.as_ptr(), new.as_ptr()) })); Ok(()) } pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> { - let p = cstr(p); + let p = try!(cstr(p)); try!(cvt_r(|| unsafe { libc::chmod(p.as_ptr(), perm.mode) })); Ok(()) } pub fn rmdir(p: &Path) -> io::Result<()> { - let p = cstr(p); + let p = try!(cstr(p)); try!(cvt(unsafe { libc::rmdir(p.as_ptr()) })); Ok(()) } pub fn chown(p: &Path, uid: isize, gid: isize) -> io::Result<()> { - let p = cstr(p); + let p = try!(cstr(p)); try!(cvt_r(|| unsafe { libc::chown(p.as_ptr(), uid as libc::uid_t, gid as libc::gid_t) })); @@ -325,7 +325,7 @@ pub fn chown(p: &Path, uid: isize, gid: isize) -> io::Result<()> { } pub fn readlink(p: &Path) -> io::Result<PathBuf> { - let c_path = cstr(p); + let c_path = try!(cstr(p)); let p = c_path.as_ptr(); let mut len = unsafe { libc::pathconf(p as *mut _, libc::_PC_NAME_MAX) }; if len < 0 { @@ -343,35 +343,35 @@ pub fn readlink(p: &Path) -> io::Result<PathBuf> { } pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> { - let src = cstr(src); - let dst = cstr(dst); + let src = try!(cstr(src)); + let dst = try!(cstr(dst)); try!(cvt(unsafe { libc::symlink(src.as_ptr(), dst.as_ptr()) })); Ok(()) } pub fn link(src: &Path, dst: &Path) -> io::Result<()> { - let src = cstr(src); - let dst = cstr(dst); + let src = try!(cstr(src)); + let dst = try!(cstr(dst)); try!(cvt(unsafe { libc::link(src.as_ptr(), dst.as_ptr()) })); Ok(()) } pub fn stat(p: &Path) -> io::Result<FileAttr> { - let p = cstr(p); + let p = try!(cstr(p)); let mut stat: libc::stat = unsafe { mem::zeroed() }; try!(cvt(unsafe { libc::stat(p.as_ptr(), &mut stat) })); Ok(FileAttr { stat: stat }) } pub fn lstat(p: &Path) -> io::Result<FileAttr> { - let p = cstr(p); + let p = try!(cstr(p)); let mut stat: libc::stat = unsafe { mem::zeroed() }; try!(cvt(unsafe { libc::lstat(p.as_ptr(), &mut stat) })); Ok(FileAttr { stat: stat }) } pub fn utimes(p: &Path, atime: u64, mtime: u64) -> io::Result<()> { - let p = cstr(p); + let p = try!(cstr(p)); let buf = [super::ms_to_timeval(atime), super::ms_to_timeval(mtime)]; try!(cvt(unsafe { c::utimes(p.as_ptr(), buf.as_ptr()) })); Ok(()) diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index 850189140d1..b79ad7031fa 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -17,7 +17,7 @@ use prelude::v1::*; -use ffi; +use ffi::CStr; use io::{self, ErrorKind}; use libc; use num::{Int, SignedInt}; @@ -91,7 +91,8 @@ pub fn last_gai_error(s: libc::c_int) -> IoError { let mut err = decode_error(s); err.detail = Some(unsafe { - str::from_utf8(ffi::c_str_to_bytes(&gai_strerror(s))).unwrap().to_string() + let data = CStr::from_ptr(gai_strerror(s)); + str::from_utf8(data.to_bytes()).unwrap().to_string() }); err } diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index 54aec7cf4b1..83b6a14b78d 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -10,7 +10,7 @@ use prelude::v1::*; -use ffi; +use ffi::CStr; use io; use libc::{self, c_int, size_t}; use str; @@ -31,7 +31,7 @@ pub fn cvt_gai(err: c_int) -> io::Result<()> { if err == 0 { return Ok(()) } let detail = unsafe { - str::from_utf8(ffi::c_str_to_bytes(&c::gai_strerror(err))).unwrap() + str::from_utf8(CStr::from_ptr(c::gai_strerror(err)).to_bytes()).unwrap() .to_string() }; Err(io::Error::new(io::ErrorKind::Other, diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index 5fe84cafb71..3d1ef3a2c37 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -14,7 +14,7 @@ use prelude::v1::*; use os::unix::*; use error::Error as StdError; -use ffi::{self, CString, OsString, OsStr, AsOsStr}; +use ffi::{CString, CStr, OsString, OsStr, AsOsStr}; use fmt; use iter; use libc::{self, c_int, c_char, c_void}; @@ -88,7 +88,7 @@ pub fn error_string(errno: i32) -> String { } let p = p as *const _; - str::from_utf8(ffi::c_str_to_bytes(&p)).unwrap().to_string() + str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap().to_string() } } @@ -98,13 +98,13 @@ pub fn getcwd() -> IoResult<Path> { if libc::getcwd(buf.as_mut_ptr(), buf.len() as libc::size_t).is_null() { Err(IoError::last_error()) } else { - Ok(Path::new(ffi::c_str_to_bytes(&buf.as_ptr()))) + Ok(Path::new(CStr::from_ptr(buf.as_ptr()).to_bytes())) } } } pub fn chdir(p: &Path) -> IoResult<()> { - let p = CString::from_slice(p.as_vec()); + let p = CString::new(p.as_vec()).unwrap(); unsafe { match libc::chdir(p.as_ptr()) == (0 as c_int) { true => Ok(()), @@ -211,7 +211,7 @@ pub fn current_exe() -> IoResult<Path> { if v.is_null() { Err(IoError::last_error()) } else { - Ok(Path::new(ffi::c_str_to_bytes(&v).to_vec())) + Ok(Path::new(CStr::from_ptr(&v).to_bytes().to_vec())) } } } @@ -266,7 +266,7 @@ pub fn args() -> Args { let (argc, argv) = (*_NSGetArgc() as isize, *_NSGetArgv() as *const *const c_char); range(0, argc as isize).map(|i| { - let bytes = ffi::c_str_to_bytes(&*argv.offset(i)).to_vec(); + let bytes = CStr::from_ptr(*argv.offset(i)).to_bytes().to_vec(); OsStringExt::from_vec(bytes) }).collect::<Vec<_>>() }; @@ -324,7 +324,7 @@ pub fn args() -> Args { 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 = ffi::c_str_to_bytes(&utf_c_str); + let bytes = CStr::from_ptr(utf_c_str).to_bytes(); res.push(OsString::from_str(str::from_utf8(bytes).unwrap())) } } @@ -380,7 +380,7 @@ pub fn env() -> Env { } let mut result = Vec::new(); while *environ != ptr::null() { - result.push(parse(ffi::c_str_to_bytes(&*environ))); + result.push(parse(CStr::from_ptr(*environ).to_bytes())); environ = environ.offset(1); } Env { iter: result.into_iter(), _dont_send_or_sync_me: 0 as *mut _ } @@ -397,20 +397,20 @@ pub fn env() -> Env { pub fn getenv(k: &OsStr) -> Option<OsString> { unsafe { - let s = CString::from_slice(k.as_bytes()); + let s = k.to_cstring().unwrap(); let s = libc::getenv(s.as_ptr()) as *const _; if s.is_null() { None } else { - Some(OsStringExt::from_vec(ffi::c_str_to_bytes(&s).to_vec())) + Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec())) } } } pub fn setenv(k: &OsStr, v: &OsStr) { unsafe { - let k = CString::from_slice(k.as_bytes()); - let v = CString::from_slice(v.as_bytes()); + let k = k.to_cstring().unwrap(); + let v = v.to_cstring().unwrap(); if libc::funcs::posix01::unistd::setenv(k.as_ptr(), v.as_ptr(), 1) != 0 { panic!("failed setenv: {}", IoError::last_error()); } @@ -419,7 +419,7 @@ pub fn setenv(k: &OsStr, v: &OsStr) { pub fn unsetenv(n: &OsStr) { unsafe { - let nbuf = CString::from_slice(n.as_bytes()); + let nbuf = n.to_cstring().unwrap(); if libc::funcs::posix01::unistd::unsetenv(nbuf.as_ptr()) != 0 { panic!("failed unsetenv: {}", IoError::last_error()); } @@ -480,7 +480,7 @@ pub fn home_dir() -> Option<Path> { _ => return None } let ptr = passwd.pw_dir as *const _; - let bytes = ffi::c_str_to_bytes(&ptr).to_vec(); + let bytes = CStr::from_ptr(ptr).to_bytes().to_vec(); return Some(OsStringExt::from_vec(bytes)) } } diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index 45d5b1506c3..3c9cdc65975 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -38,7 +38,7 @@ fn addr_to_sockaddr_un(addr: &CString, mem::size_of::<libc::sockaddr_un>()); let s = unsafe { &mut *(storage as *mut _ as *mut libc::sockaddr_un) }; - let len = addr.len(); + let len = addr.as_bytes().len(); if len > s.sun_path.len() - 1 { return Err(IoError { kind: old_io::InvalidInput, @@ -47,8 +47,8 @@ fn addr_to_sockaddr_un(addr: &CString, }) } s.sun_family = libc::AF_UNIX as libc::sa_family_t; - for (slot, value) in s.sun_path.iter_mut().zip(addr.iter()) { - *slot = *value; + for (slot, value) in s.sun_path.iter_mut().zip(addr.as_bytes().iter()) { + *slot = *value as libc::c_char; } // count the null terminator diff --git a/src/libstd/sys/unix/process.rs b/src/libstd/sys/unix/process.rs index f954024b0e9..b30ac889120 100644 --- a/src/libstd/sys/unix/process.rs +++ b/src/libstd/sys/unix/process.rs @@ -12,6 +12,7 @@ use prelude::v1::*; use self::Req::*; use collections::HashMap; +#[cfg(stage0)] use collections::hash_map::Hasher; use ffi::CString; use hash::Hash; @@ -63,6 +64,7 @@ impl Process { mkerr_libc(r) } + #[cfg(stage0)] pub fn spawn<K, V, C, P>(cfg: &C, in_fd: Option<P>, out_fd: Option<P>, err_fd: Option<P>) -> IoResult<Process> @@ -278,6 +280,214 @@ impl Process { }) }) } + #[cfg(not(stage0))] + pub fn spawn<K, V, C, P>(cfg: &C, in_fd: Option<P>, + out_fd: Option<P>, err_fd: Option<P>) + -> IoResult<Process> + where C: ProcessConfig<K, V>, P: AsInner<FileDesc>, + K: BytesContainer + Eq + Hash, V: BytesContainer + { + use libc::funcs::posix88::unistd::{fork, dup2, close, chdir, execvp}; + use libc::funcs::bsd44::getdtablesize; + + mod rustrt { + extern { + pub fn rust_unset_sigprocmask(); + } + } + + unsafe fn set_cloexec(fd: c_int) { + let ret = c::ioctl(fd, c::FIOCLEX); + assert_eq!(ret, 0); + } + + let dirp = cfg.cwd().map(|c| c.as_ptr()).unwrap_or(ptr::null()); + + // temporary until unboxed closures land + let cfg = unsafe { + mem::transmute::<&ProcessConfig<K,V>,&'static ProcessConfig<K,V>>(cfg) + }; + + with_envp(cfg.env(), move|envp: *const c_void| { + with_argv(cfg.program(), cfg.args(), move|argv: *const *const libc::c_char| unsafe { + let (input, mut output) = try!(sys::os::pipe()); + + // We may use this in the child, so perform allocations before the + // fork + let devnull = b"/dev/null\0"; + + set_cloexec(output.fd()); + + let pid = fork(); + if pid < 0 { + return Err(super::last_error()) + } else if pid > 0 { + #[inline] + 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 + } + + let p = Process{ pid: pid }; + drop(output); + let mut bytes = [0; 8]; + return match input.read(&mut bytes) { + 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(0).is_ok(), "wait(0) should either return Ok or panic"); + Err(super::decode_error(errno)) + } + Err(ref e) if e.kind == EndOfFile => Ok(p), + Err(e) => { + assert!(p.wait(0).is_ok(), "wait(0) 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(0).is_ok(), "wait(0) should either return Ok or panic"); + panic!("short read on the CLOEXEC pipe") + } + }; + } + + // 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) + let _ = libc::close(input.fd()); + + fn fail(output: &mut FileDesc) -> ! { + let errno = sys::os::errno() 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 + assert!(output.write(&bytes).is_ok()); + unsafe { libc::_exit(1) } + } + + rustrt::rust_unset_sigprocmask(); + + // If a stdio file descriptor is set to be ignored (via a -1 file + // descriptor), then we don't actually close it, but rather open + // up /dev/null into that file descriptor. Otherwise, the first file + // descriptor opened up in the child would be numbered as one of the + // stdio file descriptors, which is likely to wreak havoc. + let setup = |src: Option<P>, dst: c_int| { + let src = match src { + None => { + let flags = if dst == libc::STDIN_FILENO { + libc::O_RDONLY + } else { + libc::O_RDWR + }; + libc::open(devnull.as_ptr() as *const _, flags, 0) + } + Some(obj) => { + let fd = obj.as_inner().fd(); + // Leak the memory and the file descriptor. We're in the + // child now an all our resources are going to be + // cleaned up very soon + mem::forget(obj); + fd + } + }; + src != -1 && retry(|| dup2(src, dst)) != -1 + }; + + if !setup(in_fd, libc::STDIN_FILENO) { fail(&mut output) } + if !setup(out_fd, libc::STDOUT_FILENO) { fail(&mut output) } + if !setup(err_fd, libc::STDERR_FILENO) { fail(&mut output) } + + // close all other fds + for fd in (3..getdtablesize()).rev() { + if fd != output.fd() { + let _ = close(fd as c_int); + } + } + + match cfg.gid() { + Some(u) => { + if libc::setgid(u as libc::gid_t) != 0 { + fail(&mut output); + } + } + None => {} + } + match cfg.uid() { + Some(u) => { + // When dropping privileges from root, the `setgroups` call + // will remove any extraneous groups. If we don't call this, + // then even though our uid has dropped, we may still have + // groups that enable us to do super-user things. This will + // fail if we aren't root, so don't bother checking the + // return value, this is just done as an optimistic + // privilege dropping function. + extern { + fn setgroups(ngroups: libc::c_int, + ptr: *const libc::c_void) -> libc::c_int; + } + let _ = setgroups(0, ptr::null()); + + if libc::setuid(u as libc::uid_t) != 0 { + fail(&mut output); + } + } + None => {} + } + if cfg.detach() { + // Don't check the error of setsid because it fails if we're the + // process leader already. We just forked so it shouldn't return + // error, but ignore it anyway. + let _ = libc::setsid(); + } + if !dirp.is_null() && chdir(dirp) == -1 { + fail(&mut output); + } + if !envp.is_null() { + *sys::os::environ() = envp as *const _; + } + let _ = execvp(*argv, argv as *mut _); + fail(&mut output); + }) + }) + } pub fn wait(&self, deadline: u64) -> IoResult<ProcessExit> { use cmp; @@ -556,6 +766,7 @@ fn with_argv<T,F>(prog: &CString, args: &[CString], cb(ptrs.as_ptr()) } +#[cfg(stage0)] fn with_envp<K,V,T,F>(env: Option<&HashMap<K, V>>, cb: F) -> T @@ -593,6 +804,44 @@ fn with_envp<K,V,T,F>(env: Option<&HashMap<K, V>>, _ => cb(ptr::null()) } } +#[cfg(not(stage0))] +fn with_envp<K,V,T,F>(env: Option<&HashMap<K, V>>, + cb: F) + -> T + where F : FnOnce(*const c_void) -> T, + K : BytesContainer + Eq + Hash, + V : BytesContainer +{ + // On posixy systems we can pass a char** for envp, which is a + // null-terminated array of "k=v\0" strings. Since we must create + // these strings locally, yet expose a raw pointer to them, we + // create a temporary vector to own the CStrings that outlives the + // call to cb. + match env { + Some(env) => { + let mut tmps = Vec::with_capacity(env.len()); + + for pair in env { + let mut kv = Vec::new(); + kv.push_all(pair.0.container_as_bytes()); + kv.push('=' as u8); + kv.push_all(pair.1.container_as_bytes()); + kv.push(0); // terminating null + tmps.push(kv); + } + + // As with `with_argv`, this is unsafe, since cb could leak the pointers. + let mut ptrs: Vec<*const libc::c_char> = + tmps.iter() + .map(|tmp| tmp.as_ptr() as *const libc::c_char) + .collect(); + ptrs.push(ptr::null()); + + cb(ptrs.as_ptr() as *const c_void) + } + _ => cb(ptr::null()) + } +} fn translate_status(status: c_int) -> ProcessExit { #![allow(non_snake_case)] diff --git a/src/libstd/sys/unix/process2.rs b/src/libstd/sys/unix/process2.rs index 5e2c207f375..06fa5c4bba7 100644 --- a/src/libstd/sys/unix/process2.rs +++ b/src/libstd/sys/unix/process2.rs @@ -11,7 +11,6 @@ use prelude::v1::*; use collections::HashMap; -use collections::hash_map::Hasher; use env; use ffi::{OsString, OsStr, CString}; use fmt; @@ -46,7 +45,7 @@ pub struct Command { impl Command { pub fn new(program: &OsStr) -> Command { Command { - program: program.to_cstring(), + program: program.to_cstring().unwrap(), args: Vec::new(), env: None, cwd: None, @@ -57,10 +56,10 @@ impl Command { } pub fn arg(&mut self, arg: &OsStr) { - self.args.push(arg.to_cstring()) + self.args.push(arg.to_cstring().unwrap()) } pub fn args<'a, I: Iterator<Item = &'a OsStr>>(&mut self, args: I) { - self.args.extend(args.map(OsStrExt::to_cstring)) + self.args.extend(args.map(|s| OsStrExt::to_cstring(s).unwrap())) } fn init_env_map(&mut self) { if self.env.is_none() { @@ -79,7 +78,7 @@ impl Command { self.env = Some(HashMap::new()) } pub fn cwd(&mut self, dir: &OsStr) { - self.cwd = Some(dir.to_cstring()) + self.cwd = Some(dir.to_cstring().unwrap()) } } diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index 82c52471d10..c90ba7645fe 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -237,7 +237,7 @@ pub unsafe fn create(stack: uint, p: Thunk) -> io::Result<rust_thread> { pub unsafe fn set_name(name: &str) { // pthread_setname_np() since glibc 2.12 // availability autodetected via weak linkage - let cname = CString::from_slice(name.as_bytes()); + let cname = CString::new(name).unwrap(); type F = unsafe extern "C" fn(libc::pthread_t, *const libc::c_char) -> libc::c_int; extern { #[linkage = "extern_weak"] @@ -255,14 +255,14 @@ pub unsafe fn set_name(name: &str) { target_os = "openbsd"))] pub unsafe fn set_name(name: &str) { // pthread_set_name_np() since almost forever on all BSDs - let cname = CString::from_slice(name.as_bytes()); + let cname = CString::new(name).unwrap(); pthread_set_name_np(pthread_self(), cname.as_ptr()); } #[cfg(any(target_os = "macos", target_os = "ios"))] pub unsafe fn set_name(name: &str) { // pthread_setname_np() since OS X 10.6 and iOS 3.2 - let cname = CString::from_slice(name.as_bytes()); + let cname = CString::new(name).unwrap(); pthread_setname_np(cname.as_ptr()); } diff --git a/src/libstd/sys/windows/backtrace.rs b/src/libstd/sys/windows/backtrace.rs index 92e309da34b..51cf3032423 100644 --- a/src/libstd/sys/windows/backtrace.rs +++ b/src/libstd/sys/windows/backtrace.rs @@ -25,7 +25,7 @@ #![allow(dead_code)] use dynamic_lib::DynamicLibrary; -use ffi; +use ffi::CStr; use intrinsics; use old_io::{IoResult, Writer}; use libc; @@ -362,7 +362,7 @@ pub fn write(w: &mut Writer) -> IoResult<()> { if ret == libc::TRUE { try!(write!(w, " - ")); let ptr = info.Name.as_ptr() as *const libc::c_char; - let bytes = unsafe { ffi::c_str_to_bytes(&ptr) }; + let bytes = unsafe { CStr::from_ptr(ptr).to_bytes() }; match str::from_utf8(bytes) { Ok(s) => try!(demangle(w, s)), Err(..) => try!(w.write_all(&bytes[..bytes.len()-1])), diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index f861255a00a..2d1a5e10bd6 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -283,7 +283,7 @@ pub mod compat { fallback: usize) -> usize { let mut module: Vec<u16> = module.utf16_units().collect(); module.push(0); - let symbol = CString::from_slice(symbol.as_bytes()); + let symbol = CString::new(symbol).unwrap(); let func = unsafe { let handle = GetModuleHandleW(module.as_ptr()); GetProcAddress(handle, symbol.as_ptr()) as usize diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index 4d6d033deee..a756fb29f81 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -265,12 +265,12 @@ fn fill_utf16_buf_base<F1, F2, T>(mut f1: F1, f2: F2) -> Result<T, ()> let mut n = stack_buf.len(); loop { let buf = if n <= stack_buf.len() { - &mut stack_buf[] + &mut stack_buf[..] } else { let extra = n - heap_buf.len(); heap_buf.reserve(extra); heap_buf.set_len(n); - &mut heap_buf[] + &mut heap_buf[..] }; // This function is typically called on windows API functions which diff --git a/src/libstd/sys/windows/os.rs b/src/libstd/sys/windows/os.rs index 502d70d4e1a..6520d30487c 100644 --- a/src/libstd/sys/windows/os.rs +++ b/src/libstd/sys/windows/os.rs @@ -114,7 +114,7 @@ impl Iterator for Env { let (k, v) = match s.iter().position(|&b| b == '=' as u16) { Some(n) => (&s[..n], &s[n+1..]), - None => (s, &[][]), + None => (s, &[][..]), }; Some((OsStringExt::from_wide(k), OsStringExt::from_wide(v))) } @@ -186,7 +186,7 @@ impl<'a> Iterator for SplitPaths<'a> { if !must_yield && in_progress.is_empty() { None } else { - Some(super::os2path(&in_progress[])) + Some(super::os2path(&in_progress[..])) } } } @@ -208,14 +208,14 @@ pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError> return Err(JoinPathsError) } else if v.contains(&sep) { joined.push(b'"' as u16); - joined.push_all(&v[]); + joined.push_all(&v[..]); joined.push(b'"' as u16); } else { - joined.push_all(&v[]); + joined.push_all(&v[..]); } } - Ok(OsStringExt::from_wide(&joined[])) + Ok(OsStringExt::from_wide(&joined[..])) } impl fmt::Display for JoinPathsError { diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index 96ffc4daddd..60d24e6174f 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -10,7 +10,7 @@ use prelude::v1::*; -use collections::hash_map::Hasher; +#[cfg(stage0)] use collections::hash_map::Hasher; use collections; use env; use ffi::CString; @@ -106,6 +106,7 @@ impl Process { } #[allow(deprecated)] + #[cfg(stage0)] pub fn spawn<K, V, C, P>(cfg: &C, in_fd: Option<P>, out_fd: Option<P>, err_fd: Option<P>) -> IoResult<Process> @@ -267,6 +268,169 @@ impl Process { }) } } + #[allow(deprecated)] + #[cfg(not(stage0))] + pub fn spawn<K, V, C, P>(cfg: &C, in_fd: Option<P>, + out_fd: Option<P>, err_fd: Option<P>) + -> IoResult<Process> + where C: ProcessConfig<K, V>, P: AsInner<FileDesc>, + K: BytesContainer + Eq + Hash, V: BytesContainer + { + use libc::types::os::arch::extra::{DWORD, HANDLE, STARTUPINFO}; + use libc::consts::os::extra::{ + TRUE, FALSE, + STARTF_USESTDHANDLES, + INVALID_HANDLE_VALUE, + DUPLICATE_SAME_ACCESS + }; + use libc::funcs::extra::kernel32::{ + GetCurrentProcess, + DuplicateHandle, + CloseHandle, + CreateProcessW + }; + use libc::funcs::extra::msvcrt::get_osfhandle; + + use mem; + use iter::IteratorExt; + use str::StrExt; + + if cfg.gid().is_some() || cfg.uid().is_some() { + return Err(IoError { + kind: old_io::IoUnavailable, + desc: "unsupported gid/uid requested on windows", + detail: None, + }) + } + + // To have the spawning semantics of unix/windows stay the same, we need to + // read the *child's* PATH if one is provided. See #15149 for more details. + let program = cfg.env().and_then(|env| { + for (key, v) in env { + if b"PATH" != key.container_as_bytes() { continue } + + // Split the value and test each path to see if the + // program exists. + for path in os::split_paths(v.container_as_bytes()) { + let path = path.join(cfg.program().as_bytes()) + .with_extension(env::consts::EXE_EXTENSION); + if path.exists() { + return Some(CString::from_slice(path.as_vec())) + } + } + break + } + None + }); + + unsafe { + let mut si = zeroed_startupinfo(); + si.cb = mem::size_of::<STARTUPINFO>() as DWORD; + si.dwFlags = STARTF_USESTDHANDLES; + + let cur_proc = GetCurrentProcess(); + + // Similarly to unix, we don't actually leave holes for the stdio file + // descriptors, but rather open up /dev/null equivalents. These + // equivalents are drawn from libuv's windows process spawning. + let set_fd = |fd: &Option<P>, slot: &mut HANDLE, + is_stdin: bool| { + match *fd { + None => { + let access = if is_stdin { + libc::FILE_GENERIC_READ + } else { + libc::FILE_GENERIC_WRITE | libc::FILE_READ_ATTRIBUTES + }; + let size = mem::size_of::<libc::SECURITY_ATTRIBUTES>(); + let mut sa = libc::SECURITY_ATTRIBUTES { + nLength: size as libc::DWORD, + lpSecurityDescriptor: ptr::null_mut(), + bInheritHandle: 1, + }; + let mut filename: Vec<u16> = "NUL".utf16_units().collect(); + filename.push(0); + *slot = libc::CreateFileW(filename.as_ptr(), + access, + libc::FILE_SHARE_READ | + libc::FILE_SHARE_WRITE, + &mut sa, + libc::OPEN_EXISTING, + 0, + ptr::null_mut()); + if *slot == INVALID_HANDLE_VALUE { + return Err(super::last_error()) + } + } + Some(ref fd) => { + let orig = get_osfhandle(fd.as_inner().fd()) as HANDLE; + if orig == INVALID_HANDLE_VALUE { + return Err(super::last_error()) + } + if DuplicateHandle(cur_proc, orig, cur_proc, slot, + 0, TRUE, DUPLICATE_SAME_ACCESS) == FALSE { + return Err(super::last_error()) + } + } + } + Ok(()) + }; + + try!(set_fd(&in_fd, &mut si.hStdInput, true)); + try!(set_fd(&out_fd, &mut si.hStdOutput, false)); + try!(set_fd(&err_fd, &mut si.hStdError, false)); + + let cmd_str = make_command_line(program.as_ref().unwrap_or(cfg.program()), + cfg.args()); + let mut pi = zeroed_process_information(); + let mut create_err = None; + + // stolen from the libuv code. + let mut flags = libc::CREATE_UNICODE_ENVIRONMENT; + if cfg.detach() { + flags |= libc::DETACHED_PROCESS | libc::CREATE_NEW_PROCESS_GROUP; + } + + with_envp(cfg.env(), |envp| { + with_dirp(cfg.cwd(), |dirp| { + let mut cmd_str: Vec<u16> = cmd_str.utf16_units().collect(); + cmd_str.push(0); + let _lock = CREATE_PROCESS_LOCK.lock().unwrap(); + let created = CreateProcessW(ptr::null(), + cmd_str.as_mut_ptr(), + ptr::null_mut(), + ptr::null_mut(), + TRUE, + flags, envp, dirp, + &mut si, &mut pi); + if created == FALSE { + create_err = Some(super::last_error()); + } + }) + }); + + assert!(CloseHandle(si.hStdInput) != 0); + assert!(CloseHandle(si.hStdOutput) != 0); + assert!(CloseHandle(si.hStdError) != 0); + + match create_err { + Some(err) => return Err(err), + None => {} + } + + // We close the thread handle because we don't care about keeping the + // thread id valid, and we aren't keeping the thread handle around to be + // able to close it later. We don't close the process handle however + // because std::we want the process id to stay valid at least until the + // calling code closes the process handle. + assert!(CloseHandle(pi.hThread) != 0); + + Ok(Process { + pid: pi.dwProcessId as pid_t, + handle: pi.hProcess as *mut () + }) + } + } /// Waits for a process to exit and returns the exit code, failing /// if there is no process with the specified id. @@ -425,6 +589,7 @@ fn make_command_line(prog: &CString, args: &[CString]) -> String { } } +#[cfg(stage0)] fn with_envp<K, V, T, F>(env: Option<&collections::HashMap<K, V>>, cb: F) -> T where K: BytesContainer + Eq + Hash<Hasher>, V: BytesContainer, @@ -452,6 +617,34 @@ fn with_envp<K, V, T, F>(env: Option<&collections::HashMap<K, V>>, cb: F) -> T _ => cb(ptr::null_mut()) } } +#[cfg(not(stage0))] +fn with_envp<K, V, T, F>(env: Option<&collections::HashMap<K, V>>, cb: F) -> T + where K: BytesContainer + Eq + Hash, + V: BytesContainer, + F: FnOnce(*mut c_void) -> T, +{ + // On Windows we pass an "environment block" which is not a char**, but + // rather a concatenation of null-terminated k=v\0 sequences, with a final + // \0 to terminate. + match env { + Some(env) => { + let mut blk = Vec::new(); + + for pair in env { + let kv = format!("{}={}", + pair.0.container_as_str().unwrap(), + pair.1.container_as_str().unwrap()); + blk.extend(kv.utf16_units()); + blk.push(0); + } + + blk.push(0); + + cb(blk.as_mut_ptr() as *mut c_void) + } + _ => cb(ptr::null_mut()) + } +} fn with_dirp<T, F>(d: Option<&CString>, cb: F) -> T where F: FnOnce(*const u16) -> T, |
