diff options
Diffstat (limited to 'ctr-std/src/sys/windows/os.rs')
| -rw-r--r-- | ctr-std/src/sys/windows/os.rs | 337 |
1 files changed, 0 insertions, 337 deletions
diff --git a/ctr-std/src/sys/windows/os.rs b/ctr-std/src/sys/windows/os.rs deleted file mode 100644 index b944824..0000000 --- a/ctr-std/src/sys/windows/os.rs +++ /dev/null @@ -1,337 +0,0 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Implementation of `std::os` functionality for Windows - -#![allow(bad_style)] - -use os::windows::prelude::*; - -use error::Error as StdError; -use ffi::{OsString, OsStr}; -use fmt; -use io; -use os::windows::ffi::EncodeWide; -use path::{self, PathBuf}; -use ptr; -use slice; -use sys::{c, cvt}; -use sys::handle::Handle; - -use super::to_u16s; - -pub fn errno() -> i32 { - unsafe { c::GetLastError() as i32 } -} - -/// Gets a detailed string description for the given error number. -pub fn error_string(mut errnum: i32) -> String { - // This value is calculated from the macro - // MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT) - let langId = 0x0800 as c::DWORD; - - let mut buf = [0 as c::WCHAR; 2048]; - - unsafe { - let mut module = ptr::null_mut(); - let mut flags = 0; - - // NTSTATUS errors may be encoded as HRESULT, which may returned from - // GetLastError. For more information about Windows error codes, see - // `[MS-ERREF]`: https://msdn.microsoft.com/en-us/library/cc231198.aspx - if (errnum & c::FACILITY_NT_BIT as i32) != 0 { - // format according to https://support.microsoft.com/en-us/help/259693 - const NTDLL_DLL: &'static [u16] = &['N' as _, 'T' as _, 'D' as _, 'L' as _, 'L' as _, - '.' as _, 'D' as _, 'L' as _, 'L' as _, 0]; - module = c::GetModuleHandleW(NTDLL_DLL.as_ptr()); - - if module != ptr::null_mut() { - errnum ^= c::FACILITY_NT_BIT as i32; - flags = c::FORMAT_MESSAGE_FROM_HMODULE; - } - } - - let res = c::FormatMessageW(flags | c::FORMAT_MESSAGE_FROM_SYSTEM | - c::FORMAT_MESSAGE_IGNORE_INSERTS, - module, - errnum as c::DWORD, - langId, - buf.as_mut_ptr(), - buf.len() as c::DWORD, - ptr::null()) as usize; - if res == 0 { - // Sometimes FormatMessageW can fail e.g. system doesn't like langId, - let fm_err = errno(); - return format!("OS Error {} (FormatMessageW() returned error {})", - errnum, fm_err); - } - - match String::from_utf16(&buf[..res]) { - Ok(mut msg) => { - // Trim trailing CRLF inserted by FormatMessageW - let len = msg.trim_right().len(); - msg.truncate(len); - msg - }, - Err(..) => format!("OS Error {} (FormatMessageW() returned \ - invalid UTF-16)", errnum), - } - } -} - -pub struct Env { - base: c::LPWCH, - cur: c::LPWCH, -} - -impl Iterator for Env { - type Item = (OsString, OsString); - - fn next(&mut self) -> Option<(OsString, OsString)> { - loop { - unsafe { - if *self.cur == 0 { return None } - let p = &*self.cur as *const u16; - let mut len = 0; - while *p.offset(len) != 0 { - len += 1; - } - let s = slice::from_raw_parts(p, len as usize); - self.cur = self.cur.offset(len + 1); - - // Windows allows environment variables to start with an equals - // symbol (in any other position, this is the separator between - // variable name and value). Since`s` has at least length 1 at - // this point (because the empty string terminates the array of - // environment variables), we can safely slice. - let pos = match s[1..].iter().position(|&u| u == b'=' as u16).map(|p| p + 1) { - Some(p) => p, - None => continue, - }; - return Some(( - OsStringExt::from_wide(&s[..pos]), - OsStringExt::from_wide(&s[pos+1..]), - )) - } - } - } -} - -impl Drop for Env { - fn drop(&mut self) { - unsafe { c::FreeEnvironmentStringsW(self.base); } - } -} - -pub fn env() -> Env { - unsafe { - let ch = c::GetEnvironmentStringsW(); - if ch as usize == 0 { - panic!("failure getting env string from OS: {}", - io::Error::last_os_error()); - } - Env { base: ch, cur: ch } - } -} - -pub struct SplitPaths<'a> { - data: EncodeWide<'a>, - must_yield: bool, -} - -pub fn split_paths(unparsed: &OsStr) -> SplitPaths { - SplitPaths { - data: unparsed.encode_wide(), - must_yield: true, - } -} - -impl<'a> Iterator for SplitPaths<'a> { - type Item = PathBuf; - fn next(&mut self) -> Option<PathBuf> { - // On Windows, the PATH environment variable is semicolon separated. - // Double quotes are used as a way of introducing literal semicolons - // (since c:\some;dir is a valid Windows path). Double quotes are not - // themselves permitted in path names, so there is no way to escape a - // double quote. Quoted regions can appear in arbitrary locations, so - // - // c:\foo;c:\som"e;di"r;c:\bar - // - // Should parse as [c:\foo, c:\some;dir, c:\bar]. - // - // (The above is based on testing; there is no clear reference available - // for the grammar.) - - - let must_yield = self.must_yield; - self.must_yield = false; - - let mut in_progress = Vec::new(); - let mut in_quote = false; - for b in self.data.by_ref() { - if b == '"' as u16 { - in_quote = !in_quote; - } else if b == ';' as u16 && !in_quote { - self.must_yield = true; - break - } else { - in_progress.push(b) - } - } - - if !must_yield && in_progress.is_empty() { - None - } else { - Some(super::os2path(&in_progress)) - } - } -} - -#[derive(Debug)] -pub struct JoinPathsError; - -pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError> - where I: Iterator<Item=T>, T: AsRef<OsStr> -{ - let mut joined = Vec::new(); - let sep = b';' as u16; - - for (i, path) in paths.enumerate() { - let path = path.as_ref(); - if i > 0 { joined.push(sep) } - let v = path.encode_wide().collect::<Vec<u16>>(); - if v.contains(&(b'"' as u16)) { - return Err(JoinPathsError) - } else if v.contains(&sep) { - joined.push(b'"' as u16); - joined.extend_from_slice(&v[..]); - joined.push(b'"' as u16); - } else { - joined.extend_from_slice(&v[..]); - } - } - - Ok(OsStringExt::from_wide(&joined[..])) -} - -impl fmt::Display for JoinPathsError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - "path segment contains `\"`".fmt(f) - } -} - -impl StdError for JoinPathsError { - fn description(&self) -> &str { "failed to join paths" } -} - -pub fn current_exe() -> io::Result<PathBuf> { - super::fill_utf16_buf(|buf, sz| unsafe { - c::GetModuleFileNameW(ptr::null_mut(), buf, sz) - }, super::os2path) -} - -pub fn getcwd() -> io::Result<PathBuf> { - super::fill_utf16_buf(|buf, sz| unsafe { - c::GetCurrentDirectoryW(sz, buf) - }, super::os2path) -} - -pub fn chdir(p: &path::Path) -> io::Result<()> { - let p: &OsStr = p.as_ref(); - let mut p = p.encode_wide().collect::<Vec<_>>(); - p.push(0); - - cvt(unsafe { - c::SetCurrentDirectoryW(p.as_ptr()) - }).map(|_| ()) -} - -pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> { - let k = to_u16s(k)?; - let res = super::fill_utf16_buf(|buf, sz| unsafe { - c::GetEnvironmentVariableW(k.as_ptr(), buf, sz) - }, |buf| { - OsStringExt::from_wide(buf) - }); - match res { - Ok(value) => Ok(Some(value)), - Err(e) => { - if e.raw_os_error() == Some(c::ERROR_ENVVAR_NOT_FOUND as i32) { - Ok(None) - } else { - Err(e) - } - } - } -} - -pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> { - let k = to_u16s(k)?; - let v = to_u16s(v)?; - - cvt(unsafe { - c::SetEnvironmentVariableW(k.as_ptr(), v.as_ptr()) - }).map(|_| ()) -} - -pub fn unsetenv(n: &OsStr) -> io::Result<()> { - let v = to_u16s(n)?; - cvt(unsafe { - c::SetEnvironmentVariableW(v.as_ptr(), ptr::null()) - }).map(|_| ()) -} - -pub fn temp_dir() -> PathBuf { - super::fill_utf16_buf(|buf, sz| unsafe { - c::GetTempPathW(sz, buf) - }, super::os2path).unwrap() -} - -pub fn home_dir() -> Option<PathBuf> { - ::env::var_os("HOME").or_else(|| { - ::env::var_os("USERPROFILE") - }).map(PathBuf::from).or_else(|| unsafe { - let me = c::GetCurrentProcess(); - let mut token = ptr::null_mut(); - if c::OpenProcessToken(me, c::TOKEN_READ, &mut token) == 0 { - return None - } - let _handle = Handle::new(token); - super::fill_utf16_buf(|buf, mut sz| { - match c::GetUserProfileDirectoryW(token, buf, &mut sz) { - 0 if c::GetLastError() != c::ERROR_INSUFFICIENT_BUFFER => 0, - 0 => sz, - _ => sz - 1, // sz includes the null terminator - } - }, super::os2path).ok() - }) -} - -pub fn exit(code: i32) -> ! { - unsafe { c::ExitProcess(code as c::UINT) } -} - -pub fn getpid() -> u32 { - unsafe { c::GetCurrentProcessId() as u32 } -} - -#[cfg(test)] -mod tests { - use io::Error; - use sys::c; - - // tests `error_string` above - #[test] - fn ntstatus_error() { - const STATUS_UNSUCCESSFUL: u32 = 0xc000_0001; - assert!(!Error::from_raw_os_error((STATUS_UNSUCCESSFUL | c::FACILITY_NT_BIT) as _) - .to_string().contains("FormatMessageW() returned error")); - } -} |