2019-02-09 22:16:58 +00:00
|
|
|
//! Implementation of `std::os` functionality for Windows.
|
2014-11-24 16:21:39 -08:00
|
|
|
|
2018-08-29 08:21:01 -05:00
|
|
|
#![allow(nonstandard_style)]
|
2014-09-30 17:03:56 -07:00
|
|
|
|
2019-02-11 04:23:21 +09:00
|
|
|
use crate::os::windows::prelude::*;
|
|
|
|
|
|
|
|
|
|
use crate::error::Error as StdError;
|
2019-11-27 10:28:39 -08:00
|
|
|
use crate::ffi::{OsStr, OsString};
|
2019-02-11 04:23:21 +09:00
|
|
|
use crate::fmt;
|
|
|
|
|
use crate::io;
|
|
|
|
|
use crate::os::windows::ffi::EncodeWide;
|
|
|
|
|
use crate::path::{self, PathBuf};
|
|
|
|
|
use crate::ptr;
|
|
|
|
|
use crate::slice;
|
|
|
|
|
use crate::sys::{c, cvt};
|
2014-09-30 17:03:56 -07:00
|
|
|
|
2015-11-19 18:01:11 +00:00
|
|
|
use super::to_u16s;
|
|
|
|
|
|
2015-01-27 12:20:58 -08:00
|
|
|
pub fn errno() -> i32 {
|
2015-11-02 16:23:22 -08:00
|
|
|
unsafe { c::GetLastError() as i32 }
|
2014-09-30 17:03:56 -07:00
|
|
|
}
|
|
|
|
|
|
2015-04-13 10:21:32 -04:00
|
|
|
/// Gets a detailed string description for the given error number.
|
2017-05-03 10:19:23 -07:00
|
|
|
pub fn error_string(mut errnum: i32) -> String {
|
2014-09-30 17:03:56 -07:00
|
|
|
// This value is calculated from the macro
|
|
|
|
|
// MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT)
|
2015-11-02 16:23:22 -08:00
|
|
|
let langId = 0x0800 as c::DWORD;
|
2014-09-30 17:03:56 -07:00
|
|
|
|
2015-11-02 16:23:22 -08:00
|
|
|
let mut buf = [0 as c::WCHAR; 2048];
|
2014-09-30 17:03:56 -07:00
|
|
|
|
|
|
|
|
unsafe {
|
2017-05-03 10:19:23 -07:00
|
|
|
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
|
2019-11-27 10:28:39 -08:00
|
|
|
const NTDLL_DLL: &[u16] = &[
|
|
|
|
|
'N' as _, 'T' as _, 'D' as _, 'L' as _, 'L' as _, '.' as _, 'D' as _, 'L' as _,
|
|
|
|
|
'L' as _, 0,
|
|
|
|
|
];
|
2017-05-03 10:19:23 -07:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-27 10:28:39 -08:00
|
|
|
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;
|
2014-09-30 17:03:56 -07:00
|
|
|
if res == 0 {
|
2018-11-27 02:59:49 +00:00
|
|
|
// Sometimes FormatMessageW can fail e.g., system doesn't like langId,
|
2014-09-30 17:03:56 -07:00
|
|
|
let fm_err = errno();
|
2019-11-27 10:28:39 -08:00
|
|
|
return format!("OS Error {} (FormatMessageW() returned error {})", errnum, fm_err);
|
2014-09-30 17:03:56 -07:00
|
|
|
}
|
|
|
|
|
|
2015-08-25 18:26:29 +03:00
|
|
|
match String::from_utf16(&buf[..res]) {
|
2015-08-06 22:44:50 +02:00
|
|
|
Ok(mut msg) => {
|
|
|
|
|
// Trim trailing CRLF inserted by FormatMessageW
|
2018-12-05 06:42:56 -08:00
|
|
|
let len = msg.trim_end().len();
|
2015-08-06 22:44:50 +02:00
|
|
|
msg.truncate(len);
|
|
|
|
|
msg
|
2019-11-27 10:28:39 -08:00
|
|
|
}
|
|
|
|
|
Err(..) => format!(
|
|
|
|
|
"OS Error {} (FormatMessageW() returned \
|
|
|
|
|
invalid UTF-16)",
|
|
|
|
|
errnum
|
|
|
|
|
),
|
2014-09-30 17:03:56 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-27 12:20:58 -08:00
|
|
|
pub struct Env {
|
2015-11-02 16:23:22 -08:00
|
|
|
base: c::LPWCH,
|
|
|
|
|
cur: c::LPWCH,
|
2014-09-30 17:03:56 -07:00
|
|
|
}
|
2014-11-24 16:21:39 -08:00
|
|
|
|
2015-01-27 12:20:58 -08:00
|
|
|
impl Iterator for Env {
|
|
|
|
|
type Item = (OsString, OsString);
|
|
|
|
|
|
|
|
|
|
fn next(&mut self) -> Option<(OsString, OsString)> {
|
2015-11-17 23:33:34 +00:00
|
|
|
loop {
|
|
|
|
|
unsafe {
|
2019-11-27 10:28:39 -08:00
|
|
|
if *self.cur == 0 {
|
|
|
|
|
return None;
|
|
|
|
|
}
|
2015-11-17 23:33:34 +00:00
|
|
|
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,
|
2015-11-19 19:07:27 +00:00
|
|
|
};
|
2015-11-17 23:33:34 +00:00
|
|
|
return Some((
|
|
|
|
|
OsStringExt::from_wide(&s[..pos]),
|
2019-11-27 10:28:39 -08:00
|
|
|
OsStringExt::from_wide(&s[pos + 1..]),
|
|
|
|
|
));
|
2014-11-24 16:21:39 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-27 12:20:58 -08:00
|
|
|
impl Drop for Env {
|
|
|
|
|
fn drop(&mut self) {
|
2019-11-27 10:28:39 -08:00
|
|
|
unsafe {
|
|
|
|
|
c::FreeEnvironmentStringsW(self.base);
|
|
|
|
|
}
|
2015-01-27 12:20:58 -08:00
|
|
|
}
|
|
|
|
|
}
|
2014-11-24 16:21:39 -08:00
|
|
|
|
2015-01-27 12:20:58 -08:00
|
|
|
pub fn env() -> Env {
|
2014-11-24 16:21:39 -08:00
|
|
|
unsafe {
|
2015-11-02 16:23:22 -08:00
|
|
|
let ch = c::GetEnvironmentStringsW();
|
2015-01-27 12:20:58 -08:00
|
|
|
if ch as usize == 0 {
|
2019-11-27 10:28:39 -08:00
|
|
|
panic!("failure getting env string from OS: {}", io::Error::last_os_error());
|
2014-11-24 16:21:39 -08:00
|
|
|
}
|
2015-01-27 12:20:58 -08:00
|
|
|
Env { base: ch, cur: ch }
|
2014-11-24 16:21:39 -08:00
|
|
|
}
|
2015-01-27 12:20:58 -08:00
|
|
|
}
|
2014-11-24 16:21:39 -08:00
|
|
|
|
2015-01-27 12:20:58 -08:00
|
|
|
pub struct SplitPaths<'a> {
|
|
|
|
|
data: EncodeWide<'a>,
|
|
|
|
|
must_yield: bool,
|
2014-11-24 16:21:39 -08:00
|
|
|
}
|
|
|
|
|
|
2019-03-01 09:34:11 +01:00
|
|
|
pub fn split_paths(unparsed: &OsStr) -> SplitPaths<'_> {
|
2019-11-27 10:28:39 -08:00
|
|
|
SplitPaths { data: unparsed.encode_wide(), must_yield: true }
|
2014-11-24 16:21:39 -08:00
|
|
|
}
|
|
|
|
|
|
2015-01-27 12:20:58 -08:00
|
|
|
impl<'a> Iterator for SplitPaths<'a> {
|
2015-02-23 10:59:17 -08:00
|
|
|
type Item = PathBuf;
|
|
|
|
|
fn next(&mut self) -> Option<PathBuf> {
|
2015-01-27 12:20:58 -08:00
|
|
|
// 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 {
|
2014-11-24 16:21:39 -08:00
|
|
|
in_quote = !in_quote;
|
2015-01-27 12:20:58 -08:00
|
|
|
} else if b == ';' as u16 && !in_quote {
|
|
|
|
|
self.must_yield = true;
|
2019-11-27 10:28:39 -08:00
|
|
|
break;
|
2015-01-27 12:20:58 -08:00
|
|
|
} else {
|
|
|
|
|
in_progress.push(b)
|
2014-11-24 16:21:39 -08:00
|
|
|
}
|
2015-01-27 12:20:58 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if !must_yield && in_progress.is_empty() {
|
|
|
|
|
None
|
|
|
|
|
} else {
|
2015-02-23 10:59:17 -08:00
|
|
|
Some(super::os2path(&in_progress))
|
2014-11-24 16:21:39 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-02 21:39:14 -08:00
|
|
|
#[derive(Debug)]
|
2015-01-27 12:20:58 -08:00
|
|
|
pub struct JoinPathsError;
|
|
|
|
|
|
|
|
|
|
pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
|
2019-11-27 10:28:39 -08:00
|
|
|
where
|
|
|
|
|
I: Iterator<Item = T>,
|
|
|
|
|
T: AsRef<OsStr>,
|
2015-01-27 12:20:58 -08:00
|
|
|
{
|
2014-11-24 16:21:39 -08:00
|
|
|
let mut joined = Vec::new();
|
2015-01-27 12:20:58 -08:00
|
|
|
let sep = b';' as u16;
|
2014-11-24 16:21:39 -08:00
|
|
|
|
2015-01-27 12:20:58 -08:00
|
|
|
for (i, path) in paths.enumerate() {
|
2015-03-30 11:00:05 -07:00
|
|
|
let path = path.as_ref();
|
2019-11-27 10:28:39 -08:00
|
|
|
if i > 0 {
|
|
|
|
|
joined.push(sep)
|
|
|
|
|
}
|
2015-01-27 12:20:58 -08:00
|
|
|
let v = path.encode_wide().collect::<Vec<u16>>();
|
|
|
|
|
if v.contains(&(b'"' as u16)) {
|
2019-11-27 10:28:39 -08:00
|
|
|
return Err(JoinPathsError);
|
2015-01-27 12:20:58 -08:00
|
|
|
} else if v.contains(&sep) {
|
|
|
|
|
joined.push(b'"' as u16);
|
2015-12-02 17:31:49 -08:00
|
|
|
joined.extend_from_slice(&v[..]);
|
2015-01-27 12:20:58 -08:00
|
|
|
joined.push(b'"' as u16);
|
2014-11-24 16:21:39 -08:00
|
|
|
} else {
|
2015-12-02 17:31:49 -08:00
|
|
|
joined.extend_from_slice(&v[..]);
|
2014-11-24 16:21:39 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-18 14:48:57 -05:00
|
|
|
Ok(OsStringExt::from_wide(&joined[..]))
|
2014-11-24 16:21:39 -08:00
|
|
|
}
|
|
|
|
|
|
2015-01-27 12:20:58 -08:00
|
|
|
impl fmt::Display for JoinPathsError {
|
2019-03-01 09:34:11 +01:00
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2015-01-27 12:20:58 -08:00
|
|
|
"path segment contains `\"`".fmt(f)
|
2014-11-24 16:21:39 -08:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-01-27 12:20:58 -08:00
|
|
|
impl StdError for JoinPathsError {
|
2019-11-27 10:28:39 -08:00
|
|
|
fn description(&self) -> &str {
|
|
|
|
|
"failed to join paths"
|
|
|
|
|
}
|
2015-01-27 12:20:58 -08:00
|
|
|
}
|
|
|
|
|
|
2015-02-23 10:59:17 -08:00
|
|
|
pub fn current_exe() -> io::Result<PathBuf> {
|
2019-11-27 10:28:39 -08:00
|
|
|
super::fill_utf16_buf(
|
|
|
|
|
|buf, sz| unsafe { c::GetModuleFileNameW(ptr::null_mut(), buf, sz) },
|
|
|
|
|
super::os2path,
|
|
|
|
|
)
|
2015-01-27 12:20:58 -08:00
|
|
|
}
|
|
|
|
|
|
2015-02-23 10:59:17 -08:00
|
|
|
pub fn getcwd() -> io::Result<PathBuf> {
|
2019-11-27 10:28:39 -08:00
|
|
|
super::fill_utf16_buf(|buf, sz| unsafe { c::GetCurrentDirectoryW(sz, buf) }, super::os2path)
|
2015-01-27 12:20:58 -08:00
|
|
|
}
|
|
|
|
|
|
2015-02-23 10:59:17 -08:00
|
|
|
pub fn chdir(p: &path::Path) -> io::Result<()> {
|
2015-03-30 11:00:05 -07:00
|
|
|
let p: &OsStr = p.as_ref();
|
|
|
|
|
let mut p = p.encode_wide().collect::<Vec<_>>();
|
2014-11-24 16:21:39 -08:00
|
|
|
p.push(0);
|
|
|
|
|
|
2019-11-27 10:28:39 -08:00
|
|
|
cvt(unsafe { c::SetCurrentDirectoryW(p.as_ptr()) }).map(|_| ())
|
2014-11-24 16:21:39 -08:00
|
|
|
}
|
|
|
|
|
|
2015-10-25 10:19:35 -07:00
|
|
|
pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> {
|
2016-03-22 22:01:37 -05:00
|
|
|
let k = to_u16s(k)?;
|
2019-11-27 10:28:39 -08:00
|
|
|
let res = super::fill_utf16_buf(
|
|
|
|
|
|buf, sz| unsafe { c::GetEnvironmentVariableW(k.as_ptr(), buf, sz) },
|
|
|
|
|
|buf| OsStringExt::from_wide(buf),
|
|
|
|
|
);
|
2015-10-25 10:19:35 -07:00
|
|
|
match res {
|
|
|
|
|
Ok(value) => Ok(Some(value)),
|
2015-11-02 16:23:22 -08:00
|
|
|
Err(e) => {
|
|
|
|
|
if e.raw_os_error() == Some(c::ERROR_ENVVAR_NOT_FOUND as i32) {
|
|
|
|
|
Ok(None)
|
|
|
|
|
} else {
|
|
|
|
|
Err(e)
|
|
|
|
|
}
|
2015-10-25 10:19:35 -07:00
|
|
|
}
|
|
|
|
|
}
|
2015-01-27 12:20:58 -08:00
|
|
|
}
|
|
|
|
|
|
2015-10-25 10:19:35 -07:00
|
|
|
pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
|
2016-03-22 22:01:37 -05:00
|
|
|
let k = to_u16s(k)?;
|
|
|
|
|
let v = to_u16s(v)?;
|
2015-01-27 12:20:58 -08:00
|
|
|
|
2019-11-27 10:28:39 -08:00
|
|
|
cvt(unsafe { c::SetEnvironmentVariableW(k.as_ptr(), v.as_ptr()) }).map(|_| ())
|
2015-01-27 12:20:58 -08:00
|
|
|
}
|
2014-11-24 16:21:39 -08:00
|
|
|
|
2015-10-25 10:19:35 -07:00
|
|
|
pub fn unsetenv(n: &OsStr) -> io::Result<()> {
|
2016-03-22 22:01:37 -05:00
|
|
|
let v = to_u16s(n)?;
|
2019-11-27 10:28:39 -08:00
|
|
|
cvt(unsafe { c::SetEnvironmentVariableW(v.as_ptr(), ptr::null()) }).map(|_| ())
|
2014-11-24 16:21:39 -08:00
|
|
|
}
|
std: Stabilize the std::str module
This commit starts out by consolidating all `str` extension traits into one
`StrExt` trait to be included in the prelude. This means that
`UnicodeStrPrelude`, `StrPrelude`, and `StrAllocating` have all been merged into
one `StrExt` exported by the standard library. Some functionality is currently
duplicated with the `StrExt` present in libcore.
This commit also currently avoids any methods which require any form of pattern
to operate. These functions will be stabilized via a separate RFC.
Next, stability of methods and structures are as follows:
Stable
* from_utf8_unchecked
* CowString - after moving to std::string
* StrExt::as_bytes
* StrExt::as_ptr
* StrExt::bytes/Bytes - also made a struct instead of a typedef
* StrExt::char_indices/CharIndices - CharOffsets was renamed
* StrExt::chars/Chars
* StrExt::is_empty
* StrExt::len
* StrExt::lines/Lines
* StrExt::lines_any/LinesAny
* StrExt::slice_unchecked
* StrExt::trim
* StrExt::trim_left
* StrExt::trim_right
* StrExt::words/Words - also made a struct instead of a typedef
Unstable
* from_utf8 - the error type was changed to a `Result`, but the error type has
yet to prove itself
* from_c_str - this function will be handled by the c_str RFC
* FromStr - this trait will have an associated error type eventually
* StrExt::escape_default - needs iterators at least, unsure if it should make
the cut
* StrExt::escape_unicode - needs iterators at least, unsure if it should make
the cut
* StrExt::slice_chars - this function has yet to prove itself
* StrExt::slice_shift_char - awaiting conventions about slicing and shifting
* StrExt::graphemes/Graphemes - this functionality may only be in libunicode
* StrExt::grapheme_indices/GraphemeIndices - this functionality may only be in
libunicode
* StrExt::width - this functionality may only be in libunicode
* StrExt::utf16_units - this functionality may only be in libunicode
* StrExt::nfd_chars - this functionality may only be in libunicode
* StrExt::nfkd_chars - this functionality may only be in libunicode
* StrExt::nfc_chars - this functionality may only be in libunicode
* StrExt::nfkc_chars - this functionality may only be in libunicode
* StrExt::is_char_boundary - naming is uncertain with container conventions
* StrExt::char_range_at - naming is uncertain with container conventions
* StrExt::char_range_at_reverse - naming is uncertain with container conventions
* StrExt::char_at - naming is uncertain with container conventions
* StrExt::char_at_reverse - naming is uncertain with container conventions
* StrVector::concat - this functionality may be replaced with iterators, but
it's not certain at this time
* StrVector::connect - as with concat, may be deprecated in favor of iterators
Deprecated
* StrAllocating and UnicodeStrPrelude have been merged into StrExit
* eq_slice - compiler implementation detail
* from_str - use the inherent parse() method
* is_utf8 - call from_utf8 instead
* replace - call the method instead
* truncate_utf16_at_nul - this is an implementation detail of windows and does
not need to be exposed.
* utf8_char_width - moved to libunicode
* utf16_items - moved to libunicode
* is_utf16 - moved to libunicode
* Utf16Items - moved to libunicode
* Utf16Item - moved to libunicode
* Utf16Encoder - moved to libunicode
* AnyLines - renamed to LinesAny and made a struct
* SendStr - use CowString<'static> instead
* str::raw - all functionality is deprecated
* StrExt::into_string - call to_string() instead
* StrExt::repeat - use iterators instead
* StrExt::char_len - use .chars().count() instead
* StrExt::is_alphanumeric - use .chars().all(..)
* StrExt::is_whitespace - use .chars().all(..)
Pending deprecation -- while slicing syntax is being worked out, these methods
are all #[unstable]
* Str - while currently used for generic programming, this trait will be
replaced with one of [], deref coercions, or a generic conversion trait.
* StrExt::slice - use slicing syntax instead
* StrExt::slice_to - use slicing syntax instead
* StrExt::slice_from - use slicing syntax instead
* StrExt::lev_distance - deprecated with no replacement
Awaiting stabilization due to patterns and/or matching
* StrExt::contains
* StrExt::contains_char
* StrExt::split
* StrExt::splitn
* StrExt::split_terminator
* StrExt::rsplitn
* StrExt::match_indices
* StrExt::split_str
* StrExt::starts_with
* StrExt::ends_with
* StrExt::trim_chars
* StrExt::trim_left_chars
* StrExt::trim_right_chars
* StrExt::find
* StrExt::rfind
* StrExt::find_str
* StrExt::subslice_offset
2014-12-10 09:02:31 -08:00
|
|
|
|
2015-02-23 10:59:17 -08:00
|
|
|
pub fn temp_dir() -> PathBuf {
|
2019-11-27 10:28:39 -08:00
|
|
|
super::fill_utf16_buf(|buf, sz| unsafe { c::GetTempPathW(sz, buf) }, super::os2path).unwrap()
|
2015-01-27 12:20:58 -08:00
|
|
|
}
|
|
|
|
|
|
2019-05-27 17:07:33 +02:00
|
|
|
#[cfg(not(target_vendor = "uwp"))]
|
|
|
|
|
fn home_dir_crt() -> Option<PathBuf> {
|
|
|
|
|
unsafe {
|
|
|
|
|
use crate::sys::handle::Handle;
|
|
|
|
|
|
2015-01-27 12:20:58 -08:00
|
|
|
let me = c::GetCurrentProcess();
|
|
|
|
|
let mut token = ptr::null_mut();
|
|
|
|
|
if c::OpenProcessToken(me, c::TOKEN_READ, &mut token) == 0 {
|
2019-11-27 10:28:39 -08:00
|
|
|
return None;
|
2015-01-27 12:20:58 -08:00
|
|
|
}
|
std: Stabilize parts of std::os::platform::io
This commit stabilizes the platform-specific `io` modules, specifically around
the traits having to do with the raw representation of each object on each
platform.
Specifically, the following material was stabilized:
* `AsRaw{Fd,Socket,Handle}`
* `RawFd` (renamed from `Fd`)
* `RawHandle` (renamed from `Handle`)
* `RawSocket` (renamed from `Socket`)
* `AsRaw{Fd,Socket,Handle}` implementations
* `std::os::{unix, windows}::io`
The following material was added as `#[unstable]`:
* `FromRaw{Fd,Socket,Handle}`
* Implementations for various primitives
There are a number of future improvements that are possible to make to this
module, but this should cover a good bit of functionality desired from these
modules for now. Some specific future additions may include:
* `IntoRawXXX` traits to consume the raw representation and cancel the
auto-destructor.
* `Fd`, `Socket`, and `Handle` abstractions that behave like Rust objects and
have nice methods for various syscalls.
At this time though, these are considered backwards-compatible extensions and
will not be stabilized at this time.
This commit is a breaking change due to the addition of `Raw` in from of the
type aliases in each of the platform-specific modules.
[breaking-change]
2015-03-26 16:18:29 -07:00
|
|
|
let _handle = Handle::new(token);
|
2019-11-27 10:28:39 -08:00
|
|
|
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()
|
2019-05-27 17:07:33 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[cfg(target_vendor = "uwp")]
|
|
|
|
|
fn home_dir_crt() -> Option<PathBuf> {
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn home_dir() -> Option<PathBuf> {
|
2019-11-27 10:28:39 -08:00
|
|
|
crate::env::var_os("HOME")
|
|
|
|
|
.or_else(|| crate::env::var_os("USERPROFILE"))
|
|
|
|
|
.map(PathBuf::from)
|
|
|
|
|
.or_else(|| home_dir_crt())
|
2015-01-27 12:20:58 -08:00
|
|
|
}
|
2015-03-31 14:41:59 -07:00
|
|
|
|
|
|
|
|
pub fn exit(code: i32) -> ! {
|
2015-11-02 16:23:22 -08:00
|
|
|
unsafe { c::ExitProcess(code as c::UINT) }
|
2015-03-31 14:41:59 -07:00
|
|
|
}
|
2017-05-03 10:24:49 -07:00
|
|
|
|
2017-10-05 23:49:36 -06:00
|
|
|
pub fn getpid() -> u32 {
|
|
|
|
|
unsafe { c::GetCurrentProcessId() as u32 }
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-03 10:24:49 -07:00
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests {
|
2019-02-11 04:23:21 +09:00
|
|
|
use crate::io::Error;
|
|
|
|
|
use crate::sys::c;
|
2017-05-03 10:24:49 -07:00
|
|
|
|
|
|
|
|
// tests `error_string` above
|
|
|
|
|
#[test]
|
|
|
|
|
fn ntstatus_error() {
|
|
|
|
|
const STATUS_UNSUCCESSFUL: u32 = 0xc000_0001;
|
2019-11-27 10:28:39 -08:00
|
|
|
assert!(
|
|
|
|
|
!Error::from_raw_os_error((STATUS_UNSUCCESSFUL | c::FACILITY_NT_BIT) as _)
|
|
|
|
|
.to_string()
|
|
|
|
|
.contains("FormatMessageW() returned error")
|
|
|
|
|
);
|
2017-05-03 10:24:49 -07:00
|
|
|
}
|
|
|
|
|
}
|