diff options
| author | Alex Crichton <alex@alexcrichton.com> | 2015-04-09 17:42:22 -0700 |
|---|---|---|
| committer | Alex Crichton <alex@alexcrichton.com> | 2015-04-14 10:14:11 -0700 |
| commit | bf4e77d4b543632ca4df8fdd7092850dffc3954b (patch) | |
| tree | c4b56d2a5974e1b3bf4bfc8b7ca1a62d64c2c341 /src/libstd/sys/windows/process.rs | |
| parent | dabf0c6371d3b193664f58746fa27c1835a010f3 (diff) | |
| download | rust-bf4e77d4b543632ca4df8fdd7092850dffc3954b.tar.gz rust-bf4e77d4b543632ca4df8fdd7092850dffc3954b.zip | |
std: Remove old_io/old_path/rand modules
This commit entirely removes the old I/O, path, and rand modules. All functionality has been deprecated and unstable for quite some time now!
Diffstat (limited to 'src/libstd/sys/windows/process.rs')
| -rw-r--r-- | src/libstd/sys/windows/process.rs | 518 |
1 files changed, 0 insertions, 518 deletions
diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs deleted file mode 100644 index b10042090dd..00000000000 --- a/src/libstd/sys/windows/process.rs +++ /dev/null @@ -1,518 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -#![allow(deprecated)] // this module itself is essentially deprecated - -use prelude::v1::*; - -use collections; -use env; -use ffi::CString; -use hash::Hash; -use libc::{pid_t, c_void}; -use libc; -use mem; -#[allow(deprecated)] use old_io::fs::PathExtensions; -use old_io::process::{ProcessExit, ExitStatus}; -use old_io::{IoResult, IoError}; -use old_io; -use fs::PathExt; -use old_path::{BytesContainer, GenericPath}; -use ptr; -use str; -use sync::{StaticMutex, MUTEX_INIT}; -use sys::fs::FileDesc; -use sys::timer; -use sys_common::{AsInner, timeout}; - -pub use sys_common::ProcessConfig; - -// `CreateProcess` is racy! -// http://support.microsoft.com/kb/315939 -static CREATE_PROCESS_LOCK: StaticMutex = MUTEX_INIT; - -/// A value representing a child process. -/// -/// The lifetime of this value is linked to the lifetime of the actual -/// process - the Process destructor calls self.finish() which waits -/// for the process to terminate. -pub struct Process { - /// The unique id of the process (this should never be negative). - pid: pid_t, - - /// A HANDLE to the process, which will prevent the pid being - /// re-used until the handle is closed. - handle: *mut (), -} - -impl Drop for Process { - fn drop(&mut self) { - free_handle(self.handle); - } -} - -impl Process { - pub fn id(&self) -> pid_t { - self.pid - } - - pub unsafe fn kill(&self, signal: isize) -> IoResult<()> { - Process::killpid(self.pid, signal) - } - - pub unsafe fn killpid(pid: pid_t, signal: isize) -> IoResult<()> { - let handle = libc::OpenProcess(libc::PROCESS_TERMINATE | - libc::PROCESS_QUERY_INFORMATION, - libc::FALSE, pid as libc::DWORD); - if handle.is_null() { - return Err(super::last_error()) - } - let ret = match signal { - // test for existence on signal 0 - 0 => { - let mut status = 0; - let ret = libc::GetExitCodeProcess(handle, &mut status); - if ret == 0 { - Err(super::last_error()) - } else if status != libc::STILL_ACTIVE { - Err(IoError { - kind: old_io::InvalidInput, - desc: "no process to kill", - detail: None, - }) - } else { - Ok(()) - } - } - 15 | 9 => { // sigterm or sigkill - let ret = libc::TerminateProcess(handle, 1); - super::mkerr_winbool(ret) - } - _ => Err(IoError { - kind: old_io::IoUnavailable, - desc: "unsupported signal on windows", - detail: None, - }) - }; - let _ = libc::CloseHandle(handle); - return ret; - } - - #[allow(deprecated)] - 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; - - 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 } - let v = match ::str::from_utf8(v.container_as_bytes()) { - Ok(s) => s, - Err(..) => continue, - }; - - // Split the value and test each path to see if the - // program exists. - for path in ::env::split_paths(v) { - let program = str::from_utf8(cfg.program().as_bytes()).unwrap(); - let path = path.join(program) - .with_extension(env::consts::EXE_EXTENSION); - if path.exists() { - return Some(CString::new(path.to_str().unwrap()).unwrap()) - } - } - 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. - /// - /// Note that this is private to avoid race conditions on unix where if - /// a user calls waitpid(some_process.get_id()) then some_process.finish() - /// and some_process.destroy() and some_process.finalize() will then either - /// operate on a none-existent process or, even worse, on a newer process - /// with the same id. - pub fn wait(&self, deadline: u64) -> IoResult<ProcessExit> { - use libc::types::os::arch::extra::DWORD; - use libc::consts::os::extra::{ - SYNCHRONIZE, - PROCESS_QUERY_INFORMATION, - FALSE, - STILL_ACTIVE, - INFINITE, - WAIT_TIMEOUT, - WAIT_OBJECT_0, - }; - use libc::funcs::extra::kernel32::{ - OpenProcess, - GetExitCodeProcess, - CloseHandle, - WaitForSingleObject, - }; - - unsafe { - let process = OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, - FALSE, - self.pid as DWORD); - if process.is_null() { - return Err(super::last_error()) - } - - loop { - let mut status = 0; - if GetExitCodeProcess(process, &mut status) == FALSE { - let err = Err(super::last_error()); - assert!(CloseHandle(process) != 0); - return err; - } - if status != STILL_ACTIVE { - assert!(CloseHandle(process) != 0); - return Ok(ExitStatus(status as isize)); - } - let interval = if deadline == 0 { - INFINITE - } else { - let now = timer::now(); - if deadline < now {0} else {(deadline - now) as u32} - }; - match WaitForSingleObject(process, interval) { - WAIT_OBJECT_0 => {} - WAIT_TIMEOUT => { - assert!(CloseHandle(process) != 0); - return Err(timeout("process wait timed out")) - } - _ => { - let err = Err(super::last_error()); - assert!(CloseHandle(process) != 0); - return err - } - } - } - } - } -} - -fn zeroed_startupinfo() -> libc::types::os::arch::extra::STARTUPINFO { - libc::types::os::arch::extra::STARTUPINFO { - cb: 0, - lpReserved: ptr::null_mut(), - lpDesktop: ptr::null_mut(), - lpTitle: ptr::null_mut(), - dwX: 0, - dwY: 0, - dwXSize: 0, - dwYSize: 0, - dwXCountChars: 0, - dwYCountCharts: 0, - dwFillAttribute: 0, - dwFlags: 0, - wShowWindow: 0, - cbReserved2: 0, - lpReserved2: ptr::null_mut(), - hStdInput: libc::INVALID_HANDLE_VALUE, - hStdOutput: libc::INVALID_HANDLE_VALUE, - hStdError: libc::INVALID_HANDLE_VALUE, - } -} - -fn zeroed_process_information() -> libc::types::os::arch::extra::PROCESS_INFORMATION { - libc::types::os::arch::extra::PROCESS_INFORMATION { - hProcess: ptr::null_mut(), - hThread: ptr::null_mut(), - dwProcessId: 0, - dwThreadId: 0 - } -} - -fn make_command_line(prog: &CString, args: &[CString]) -> String { - let mut cmd = String::new(); - append_arg(&mut cmd, str::from_utf8(prog.as_bytes()).ok() - .expect("expected program name to be utf-8 encoded")); - for arg in args { - cmd.push(' '); - append_arg(&mut cmd, str::from_utf8(arg.as_bytes()).ok() - .expect("expected argument to be utf-8 encoded")); - } - return cmd; - - fn append_arg(cmd: &mut String, arg: &str) { - // If an argument has 0 characters then we need to quote it to ensure - // that it actually gets passed through on the command line or otherwise - // it will be dropped entirely when parsed on the other end. - let quote = arg.chars().any(|c| c == ' ' || c == '\t') || arg.len() == 0; - if quote { - cmd.push('"'); - } - let argvec: Vec<char> = arg.chars().collect(); - for i in 0..argvec.len() { - append_char_at(cmd, &argvec, i); - } - if quote { - cmd.push('"'); - } - } - - fn append_char_at(cmd: &mut String, arg: &[char], i: usize) { - match arg[i] { - '"' => { - // Escape quotes. - cmd.push_str("\\\""); - } - '\\' => { - if backslash_run_ends_in_quote(arg, i) { - // Double all backslashes that are in runs before quotes. - cmd.push_str("\\\\"); - } else { - // Pass other backslashes through unescaped. - cmd.push('\\'); - } - } - c => { - cmd.push(c); - } - } - } - - fn backslash_run_ends_in_quote(s: &[char], mut i: usize) -> bool { - while i < s.len() && s[i] == '\\' { - i += 1; - } - return i < s.len() && s[i] == '"'; - } -} - -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, -{ - match d { - Some(dir) => { - let dir_str = str::from_utf8(dir.as_bytes()).ok() - .expect("expected workingdirectory to be utf-8 encoded"); - let mut dir_str: Vec<u16> = dir_str.utf16_units().collect(); - dir_str.push(0); - cb(dir_str.as_ptr()) - }, - None => cb(ptr::null()) - } -} - -fn free_handle(handle: *mut ()) { - assert!(unsafe { - libc::CloseHandle(mem::transmute(handle)) != 0 - }) -} - -#[cfg(test)] -mod tests { - use prelude::v1::*; - use str; - use ffi::CString; - use super::make_command_line; - - #[test] - fn test_make_command_line() { - fn test_wrapper(prog: &str, args: &[&str]) -> String { - make_command_line(&CString::new(prog).unwrap(), - &args.iter() - .map(|a| CString::new(*a).unwrap()) - .collect::<Vec<CString>>()) - } - - assert_eq!( - test_wrapper("prog", &["aaa", "bbb", "ccc"]), - "prog aaa bbb ccc" - ); - - assert_eq!( - test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa"]), - "\"C:\\Program Files\\blah\\blah.exe\" aaa" - ); - assert_eq!( - test_wrapper("C:\\Program Files\\test", &["aa\"bb"]), - "\"C:\\Program Files\\test\" aa\\\"bb" - ); - assert_eq!( - test_wrapper("echo", &["a b c"]), - "echo \"a b c\"" - ); - assert_eq!( - test_wrapper("\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}", &[]), - "\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}" - ); - } -} |
