Refactor std::os to use sys::os
This commit is contained in:
parent
2b3477d373
commit
74d0769993
406
src/libstd/os.rs
406
src/libstd/os.rs
@ -46,7 +46,6 @@ use option::Option::{Some, None};
|
||||
use os;
|
||||
use path::{Path, GenericPath, BytesContainer};
|
||||
use sys;
|
||||
use sys::os as os_imp;
|
||||
use ptr::RawPtr;
|
||||
use ptr;
|
||||
use result::Result;
|
||||
@ -78,7 +77,6 @@ pub fn num_cpus() -> uint {
|
||||
}
|
||||
|
||||
pub const TMPBUF_SZ : uint = 1000u;
|
||||
const BUF_BYTES : uint = 2048u;
|
||||
|
||||
/// Returns the current working directory as a `Path`.
|
||||
///
|
||||
@ -96,118 +94,12 @@ const BUF_BYTES : uint = 2048u;
|
||||
/// ```rust
|
||||
/// use std::os;
|
||||
///
|
||||
/// // We assume that we are in a valid directory like "/home".
|
||||
/// // We assume that we are in a valid directory.
|
||||
/// let current_working_directory = os::getcwd().unwrap();
|
||||
/// println!("The current directory is {}", current_working_directory.display());
|
||||
/// // /home
|
||||
/// ```
|
||||
#[cfg(unix)]
|
||||
pub fn getcwd() -> IoResult<Path> {
|
||||
use c_str::CString;
|
||||
|
||||
let mut buf = [0 as c_char, ..BUF_BYTES];
|
||||
unsafe {
|
||||
if libc::getcwd(buf.as_mut_ptr(), buf.len() as libc::size_t).is_null() {
|
||||
Err(IoError::last_error())
|
||||
} else {
|
||||
Ok(Path::new(CString::new(buf.as_ptr(), false)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the current working directory as a `Path`.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an `Err` if the current working directory value is invalid.
|
||||
/// Possible cases:
|
||||
///
|
||||
/// * Current directory does not exist.
|
||||
/// * There are insufficient permissions to access the current directory.
|
||||
/// * The internal buffer is not large enough to hold the path.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use std::os;
|
||||
///
|
||||
/// // We assume that we are in a valid directory like "C:\\Windows".
|
||||
/// let current_working_directory = os::getcwd().unwrap();
|
||||
/// println!("The current directory is {}", current_working_directory.display());
|
||||
/// // C:\\Windows
|
||||
/// ```
|
||||
#[cfg(windows)]
|
||||
pub fn getcwd() -> IoResult<Path> {
|
||||
use libc::DWORD;
|
||||
use libc::GetCurrentDirectoryW;
|
||||
use io::OtherIoError;
|
||||
|
||||
let mut buf = [0 as u16, ..BUF_BYTES];
|
||||
unsafe {
|
||||
if libc::GetCurrentDirectoryW(buf.len() as DWORD, buf.as_mut_ptr()) == 0 as DWORD {
|
||||
return Err(IoError::last_error());
|
||||
}
|
||||
}
|
||||
|
||||
match String::from_utf16(::str::truncate_utf16_at_nul(&buf)) {
|
||||
Some(ref cwd) => Ok(Path::new(cwd)),
|
||||
None => Err(IoError {
|
||||
kind: OtherIoError,
|
||||
desc: "GetCurrentDirectoryW returned invalid UTF-16",
|
||||
detail: None,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub mod windoze {
|
||||
use libc::types::os::arch::extra::DWORD;
|
||||
use libc;
|
||||
use ops::FnMut;
|
||||
use option::Option;
|
||||
use option::Option::None;
|
||||
use option;
|
||||
use os::TMPBUF_SZ;
|
||||
use slice::SliceExt;
|
||||
use string::String;
|
||||
use str::StrPrelude;
|
||||
use vec::Vec;
|
||||
|
||||
pub fn fill_utf16_buf_and_decode<F>(mut f: F) -> Option<String> where
|
||||
F: FnMut(*mut u16, DWORD) -> DWORD,
|
||||
{
|
||||
|
||||
unsafe {
|
||||
let mut n = TMPBUF_SZ as DWORD;
|
||||
let mut res = None;
|
||||
let mut done = false;
|
||||
while !done {
|
||||
let mut buf = Vec::from_elem(n as uint, 0u16);
|
||||
let k = f(buf.as_mut_ptr(), n);
|
||||
if k == (0 as DWORD) {
|
||||
done = true;
|
||||
} else if k == n &&
|
||||
libc::GetLastError() ==
|
||||
libc::ERROR_INSUFFICIENT_BUFFER as DWORD {
|
||||
n *= 2 as DWORD;
|
||||
} else if k >= n {
|
||||
n = k;
|
||||
} else {
|
||||
done = true;
|
||||
}
|
||||
if k != 0 && done {
|
||||
let sub = buf.slice(0, k as uint);
|
||||
// We want to explicitly catch the case when the
|
||||
// closure returned invalid UTF-16, rather than
|
||||
// set `res` to None and continue.
|
||||
let s = String::from_utf16(sub)
|
||||
.expect("fill_utf16_buf_and_decode: closure created invalid UTF-16");
|
||||
res = option::Option::Some(s)
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
sys::os::getcwd()
|
||||
}
|
||||
|
||||
/*
|
||||
@ -253,71 +145,6 @@ pub fn env() -> Vec<(String,String)> {
|
||||
/// environment variables of the current process.
|
||||
pub fn env_as_bytes() -> Vec<(Vec<u8>,Vec<u8>)> {
|
||||
unsafe {
|
||||
#[cfg(windows)]
|
||||
unsafe fn get_env_pairs() -> Vec<Vec<u8>> {
|
||||
use slice;
|
||||
|
||||
use libc::funcs::extra::kernel32::{
|
||||
GetEnvironmentStringsW,
|
||||
FreeEnvironmentStringsW
|
||||
};
|
||||
let ch = GetEnvironmentStringsW();
|
||||
if ch as uint == 0 {
|
||||
panic!("os::env() failure getting env string from OS: {}",
|
||||
os::last_os_error());
|
||||
}
|
||||
// Here, we lossily decode the string as UTF16.
|
||||
//
|
||||
// The docs suggest that the result should be in Unicode, but
|
||||
// Windows doesn't guarantee it's actually UTF16 -- it doesn't
|
||||
// validate the environment string passed to CreateProcess nor
|
||||
// SetEnvironmentVariable. Yet, it's unlikely that returning a
|
||||
// raw u16 buffer would be of practical use since the result would
|
||||
// be inherently platform-dependent and introduce additional
|
||||
// complexity to this code.
|
||||
//
|
||||
// Using the non-Unicode version of GetEnvironmentStrings is even
|
||||
// worse since the result is in an OEM code page. Characters that
|
||||
// can't be encoded in the code page would be turned into question
|
||||
// marks.
|
||||
let mut result = Vec::new();
|
||||
let mut i = 0;
|
||||
while *ch.offset(i) != 0 {
|
||||
let p = &*ch.offset(i);
|
||||
let mut len = 0;
|
||||
while *(p as *const _).offset(len) != 0 {
|
||||
len += 1;
|
||||
}
|
||||
let p = p as *const u16;
|
||||
let s = slice::from_raw_buf(&p, len as uint);
|
||||
result.push(String::from_utf16_lossy(s).into_bytes());
|
||||
i += len as int + 1;
|
||||
}
|
||||
FreeEnvironmentStringsW(ch);
|
||||
result
|
||||
}
|
||||
#[cfg(unix)]
|
||||
unsafe fn get_env_pairs() -> Vec<Vec<u8>> {
|
||||
use c_str::CString;
|
||||
|
||||
extern {
|
||||
fn rust_env_pairs() -> *const *const c_char;
|
||||
}
|
||||
let mut environ = rust_env_pairs();
|
||||
if environ as uint == 0 {
|
||||
panic!("os::env() failure getting env string from OS: {}",
|
||||
os::last_os_error());
|
||||
}
|
||||
let mut result = Vec::new();
|
||||
while *environ != 0 as *const _ {
|
||||
let env_pair =
|
||||
CString::new(*environ, false).as_bytes_no_nul().to_vec();
|
||||
result.push(env_pair);
|
||||
environ = environ.offset(1);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fn env_convert(input: Vec<Vec<u8>>) -> Vec<(Vec<u8>, Vec<u8>)> {
|
||||
let mut pairs = Vec::new();
|
||||
for p in input.iter() {
|
||||
@ -330,7 +157,7 @@ pub fn env_as_bytes() -> Vec<(Vec<u8>,Vec<u8>)> {
|
||||
pairs
|
||||
}
|
||||
with_env_lock(|| {
|
||||
let unparsed_environ = get_env_pairs();
|
||||
let unparsed_environ = sys::os::get_env_pairs();
|
||||
env_convert(unparsed_environ)
|
||||
})
|
||||
}
|
||||
@ -390,7 +217,7 @@ pub fn getenv_as_bytes(n: &str) -> Option<Vec<u8>> {
|
||||
pub fn getenv(n: &str) -> Option<String> {
|
||||
unsafe {
|
||||
with_env_lock(|| {
|
||||
use os::windoze::{fill_utf16_buf_and_decode};
|
||||
use sys::os::fill_utf16_buf_and_decode;
|
||||
let mut n: Vec<u16> = n.utf16_units().collect();
|
||||
n.push(0);
|
||||
fill_utf16_buf_and_decode(|buf, sz| {
|
||||
@ -506,52 +333,7 @@ pub fn unsetenv(n: &str) {
|
||||
/// }
|
||||
/// ```
|
||||
pub fn split_paths<T: BytesContainer>(unparsed: T) -> Vec<Path> {
|
||||
#[cfg(unix)]
|
||||
fn _split_paths<T: BytesContainer>(unparsed: T) -> Vec<Path> {
|
||||
unparsed.container_as_bytes()
|
||||
.split(|b| *b == b':')
|
||||
.map(Path::new)
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn _split_paths<T: BytesContainer>(unparsed: T) -> Vec<Path> {
|
||||
// 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 mut parsed = Vec::new();
|
||||
let mut in_progress = Vec::new();
|
||||
let mut in_quote = false;
|
||||
|
||||
for b in unparsed.container_as_bytes().iter() {
|
||||
match *b {
|
||||
b';' if !in_quote => {
|
||||
parsed.push(Path::new(in_progress.as_slice()));
|
||||
in_progress.truncate(0)
|
||||
}
|
||||
b'"' => {
|
||||
in_quote = !in_quote;
|
||||
}
|
||||
_ => {
|
||||
in_progress.push(*b);
|
||||
}
|
||||
}
|
||||
}
|
||||
parsed.push(Path::new(in_progress));
|
||||
parsed
|
||||
}
|
||||
|
||||
_split_paths(unparsed)
|
||||
sys::os::split_paths(unparsed.container_as_bytes())
|
||||
}
|
||||
|
||||
/// Joins a collection of `Path`s appropriately for the `PATH`
|
||||
@ -576,42 +358,7 @@ pub fn split_paths<T: BytesContainer>(unparsed: T) -> Vec<Path> {
|
||||
/// os::setenv(key, os::join_paths(paths.as_slice()).unwrap());
|
||||
/// ```
|
||||
pub fn join_paths<T: BytesContainer>(paths: &[T]) -> Result<Vec<u8>, &'static str> {
|
||||
#[cfg(windows)]
|
||||
fn _join_paths<T: BytesContainer>(paths: &[T]) -> Result<Vec<u8>, &'static str> {
|
||||
let mut joined = Vec::new();
|
||||
let sep = b';';
|
||||
|
||||
for (i, path) in paths.iter().map(|p| p.container_as_bytes()).enumerate() {
|
||||
if i > 0 { joined.push(sep) }
|
||||
if path.contains(&b'"') {
|
||||
return Err("path segment contains `\"`");
|
||||
} else if path.contains(&sep) {
|
||||
joined.push(b'"');
|
||||
joined.push_all(path);
|
||||
joined.push(b'"');
|
||||
} else {
|
||||
joined.push_all(path);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(joined)
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn _join_paths<T: BytesContainer>(paths: &[T]) -> Result<Vec<u8>, &'static str> {
|
||||
let mut joined = Vec::new();
|
||||
let sep = b':';
|
||||
|
||||
for (i, path) in paths.iter().map(|p| p.container_as_bytes()).enumerate() {
|
||||
if i > 0 { joined.push(sep) }
|
||||
if path.contains(&sep) { return Err("path segment contains separator `:`") }
|
||||
joined.push_all(path);
|
||||
}
|
||||
|
||||
Ok(joined)
|
||||
}
|
||||
|
||||
_join_paths(paths)
|
||||
sys::os::join_paths(paths)
|
||||
}
|
||||
|
||||
/// A low-level OS in-memory pipe.
|
||||
@ -664,69 +411,7 @@ pub fn dll_filename(base: &str) -> String {
|
||||
/// };
|
||||
/// ```
|
||||
pub fn self_exe_name() -> Option<Path> {
|
||||
|
||||
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
|
||||
fn load_self() -> Option<Vec<u8>> {
|
||||
unsafe {
|
||||
use libc::funcs::bsd44::*;
|
||||
use libc::consts::os::extra::*;
|
||||
let mut mib = vec![CTL_KERN as c_int,
|
||||
KERN_PROC as c_int,
|
||||
KERN_PROC_PATHNAME as c_int,
|
||||
-1 as c_int];
|
||||
let mut sz: libc::size_t = 0;
|
||||
let err = sysctl(mib.as_mut_ptr(), mib.len() as ::libc::c_uint,
|
||||
ptr::null_mut(), &mut sz, ptr::null_mut(),
|
||||
0u as libc::size_t);
|
||||
if err != 0 { return None; }
|
||||
if sz == 0 { return None; }
|
||||
let mut v: Vec<u8> = Vec::with_capacity(sz as uint);
|
||||
let err = sysctl(mib.as_mut_ptr(), mib.len() as ::libc::c_uint,
|
||||
v.as_mut_ptr() as *mut c_void, &mut sz,
|
||||
ptr::null_mut(), 0u as libc::size_t);
|
||||
if err != 0 { return None; }
|
||||
if sz == 0 { return None; }
|
||||
v.set_len(sz as uint - 1); // chop off trailing NUL
|
||||
Some(v)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
fn load_self() -> Option<Vec<u8>> {
|
||||
use std::io;
|
||||
|
||||
match io::fs::readlink(&Path::new("/proc/self/exe")) {
|
||||
Ok(path) => Some(path.into_vec()),
|
||||
Err(..) => None
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
fn load_self() -> Option<Vec<u8>> {
|
||||
unsafe {
|
||||
use libc::funcs::extra::_NSGetExecutablePath;
|
||||
let mut sz: u32 = 0;
|
||||
_NSGetExecutablePath(ptr::null_mut(), &mut sz);
|
||||
if sz == 0 { return None; }
|
||||
let mut v: Vec<u8> = Vec::with_capacity(sz as uint);
|
||||
let err = _NSGetExecutablePath(v.as_mut_ptr() as *mut i8, &mut sz);
|
||||
if err != 0 { return None; }
|
||||
v.set_len(sz as uint - 1); // chop off trailing NUL
|
||||
Some(v)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn load_self() -> Option<Vec<u8>> {
|
||||
unsafe {
|
||||
use os::windoze::fill_utf16_buf_and_decode;
|
||||
fill_utf16_buf_and_decode(|buf, sz| {
|
||||
libc::GetModuleFileNameW(0u as libc::DWORD, buf, sz)
|
||||
}).map(|s| s.into_string().into_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
load_self().and_then(Path::new_opt)
|
||||
sys::os::load_self().and_then(Path::new_opt)
|
||||
}
|
||||
|
||||
/// Optionally returns the filesystem path to the current executable which is
|
||||
@ -842,7 +527,6 @@ pub fn tmpdir() -> Path {
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// Convert a relative path to an absolute path
|
||||
///
|
||||
/// If the given path is relative, return it prepended with the current working
|
||||
@ -887,37 +571,12 @@ pub fn make_absolute(p: &Path) -> IoResult<Path> {
|
||||
/// println!("Successfully changed working directory to {}!", root.display());
|
||||
/// ```
|
||||
pub fn change_dir(p: &Path) -> IoResult<()> {
|
||||
return chdir(p);
|
||||
|
||||
#[cfg(windows)]
|
||||
fn chdir(p: &Path) -> IoResult<()> {
|
||||
let mut p = p.as_str().unwrap().utf16_units().collect::<Vec<u16>>();
|
||||
p.push(0);
|
||||
|
||||
unsafe {
|
||||
match libc::SetCurrentDirectoryW(p.as_ptr()) != (0 as libc::BOOL) {
|
||||
true => Ok(()),
|
||||
false => Err(IoError::last_error()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn chdir(p: &Path) -> IoResult<()> {
|
||||
p.with_c_str(|buf| {
|
||||
unsafe {
|
||||
match libc::chdir(buf) == (0 as c_int) {
|
||||
true => Ok(()),
|
||||
false => Err(IoError::last_error()),
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
return sys::os::chdir(p);
|
||||
}
|
||||
|
||||
/// Returns the platform-specific value of errno
|
||||
pub fn errno() -> uint {
|
||||
os_imp::errno() as uint
|
||||
sys::os::errno() as uint
|
||||
}
|
||||
|
||||
/// Return the string corresponding to an `errno()` value of `errnum`.
|
||||
@ -930,7 +589,7 @@ pub fn errno() -> uint {
|
||||
/// println!("{}", os::error_string(os::errno() as uint));
|
||||
/// ```
|
||||
pub fn error_string(errnum: uint) -> String {
|
||||
return os_imp::error_string(errnum as i32);
|
||||
return sys::os::error_string(errnum as i32);
|
||||
}
|
||||
|
||||
/// Get a string representing the platform-dependent last error
|
||||
@ -1144,38 +803,9 @@ extern {
|
||||
pub fn _NSGetArgv() -> *mut *mut *mut c_char;
|
||||
}
|
||||
|
||||
// Round up `from` to be divisible by `to`
|
||||
fn round_up(from: uint, to: uint) -> uint {
|
||||
let r = if from % to == 0 {
|
||||
from
|
||||
} else {
|
||||
from + to - (from % to)
|
||||
};
|
||||
if r == 0 {
|
||||
to
|
||||
} else {
|
||||
r
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the page size of the current architecture in bytes.
|
||||
#[cfg(unix)]
|
||||
pub fn page_size() -> uint {
|
||||
unsafe {
|
||||
libc::sysconf(libc::_SC_PAGESIZE) as uint
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the page size of the current architecture in bytes.
|
||||
#[cfg(windows)]
|
||||
pub fn page_size() -> uint {
|
||||
use mem;
|
||||
unsafe {
|
||||
let mut info = mem::zeroed();
|
||||
libc::GetSystemInfo(&mut info);
|
||||
|
||||
return info.dwPageSize as uint;
|
||||
}
|
||||
sys::os::page_size()
|
||||
}
|
||||
|
||||
/// A memory mapped file or chunk of memory. This is a very system-specific
|
||||
@ -1325,6 +955,20 @@ impl FromError<MapError> for Box<Error> {
|
||||
}
|
||||
}
|
||||
|
||||
// Round up `from` to be divisible by `to`
|
||||
fn round_up(from: uint, to: uint) -> uint {
|
||||
let r = if from % to == 0 {
|
||||
from
|
||||
} else {
|
||||
from + to - (from % to)
|
||||
};
|
||||
if r == 0 {
|
||||
to
|
||||
} else {
|
||||
r
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
impl MemoryMap {
|
||||
/// Create a new mapping with the given `options`, at least `min_len` bytes
|
||||
|
@ -8,14 +8,24 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use libc;
|
||||
use libc::{c_int, c_char};
|
||||
//! Implementation of `std::os` functionality for unix systems
|
||||
|
||||
use prelude::*;
|
||||
use io::IoResult;
|
||||
|
||||
use error::{FromError, Error};
|
||||
use fmt;
|
||||
use io::{IoError, IoResult};
|
||||
use libc::{mod, c_int, c_char, c_void};
|
||||
use path::{Path, GenericPath, BytesContainer};
|
||||
use ptr::{mod, RawPtr};
|
||||
use sync::atomic::{AtomicInt, INIT_ATOMIC_INT, SeqCst};
|
||||
use sys::fs::FileDesc;
|
||||
use os;
|
||||
|
||||
use os::TMPBUF_SZ;
|
||||
|
||||
const BUF_BYTES : uint = 2048u;
|
||||
|
||||
/// Returns the platform-specific value of errno
|
||||
pub fn errno() -> int {
|
||||
#[cfg(any(target_os = "macos",
|
||||
@ -110,3 +120,122 @@ pub unsafe fn pipe() -> IoResult<(FileDesc, FileDesc)> {
|
||||
Err(super::last_error())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getcwd() -> IoResult<Path> {
|
||||
use c_str::CString;
|
||||
|
||||
let mut buf = [0 as c_char, ..BUF_BYTES];
|
||||
unsafe {
|
||||
if libc::getcwd(buf.as_mut_ptr(), buf.len() as libc::size_t).is_null() {
|
||||
Err(IoError::last_error())
|
||||
} else {
|
||||
Ok(Path::new(CString::new(buf.as_ptr(), false)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn get_env_pairs() -> Vec<Vec<u8>> {
|
||||
use c_str::CString;
|
||||
|
||||
extern {
|
||||
fn rust_env_pairs() -> *const *const c_char;
|
||||
}
|
||||
let mut environ = rust_env_pairs();
|
||||
if environ as uint == 0 {
|
||||
panic!("os::env() failure getting env string from OS: {}",
|
||||
os::last_os_error());
|
||||
}
|
||||
let mut result = Vec::new();
|
||||
while *environ != 0 as *const _ {
|
||||
let env_pair =
|
||||
CString::new(*environ, false).as_bytes_no_nul().to_vec();
|
||||
result.push(env_pair);
|
||||
environ = environ.offset(1);
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
pub fn split_paths(unparsed: &[u8]) -> Vec<Path> {
|
||||
unparsed.split(|b| *b == b':').map(Path::new).collect()
|
||||
}
|
||||
|
||||
pub fn join_paths<T: BytesContainer>(paths: &[T]) -> Result<Vec<u8>, &'static str> {
|
||||
let mut joined = Vec::new();
|
||||
let sep = b':';
|
||||
|
||||
for (i, path) in paths.iter().map(|p| p.container_as_bytes()).enumerate() {
|
||||
if i > 0 { joined.push(sep) }
|
||||
if path.contains(&sep) { return Err("path segment contains separator `:`") }
|
||||
joined.push_all(path);
|
||||
}
|
||||
|
||||
Ok(joined)
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
|
||||
pub fn load_self() -> Option<Vec<u8>> {
|
||||
unsafe {
|
||||
use libc::funcs::bsd44::*;
|
||||
use libc::consts::os::extra::*;
|
||||
let mut mib = vec![CTL_KERN as c_int,
|
||||
KERN_PROC as c_int,
|
||||
KERN_PROC_PATHNAME as c_int,
|
||||
-1 as c_int];
|
||||
let mut sz: libc::size_t = 0;
|
||||
let err = sysctl(mib.as_mut_ptr(), mib.len() as ::libc::c_uint,
|
||||
ptr::null_mut(), &mut sz, ptr::null_mut(),
|
||||
0u as libc::size_t);
|
||||
if err != 0 { return None; }
|
||||
if sz == 0 { return None; }
|
||||
let mut v: Vec<u8> = Vec::with_capacity(sz as uint);
|
||||
let err = sysctl(mib.as_mut_ptr(), mib.len() as ::libc::c_uint,
|
||||
v.as_mut_ptr() as *mut c_void, &mut sz,
|
||||
ptr::null_mut(), 0u as libc::size_t);
|
||||
if err != 0 { return None; }
|
||||
if sz == 0 { return None; }
|
||||
v.set_len(sz as uint - 1); // chop off trailing NUL
|
||||
Some(v)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
pub fn load_self() -> Option<Vec<u8>> {
|
||||
use std::io;
|
||||
|
||||
match io::fs::readlink(&Path::new("/proc/self/exe")) {
|
||||
Ok(path) => Some(path.into_vec()),
|
||||
Err(..) => None
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "macos", target_os = "ios"))]
|
||||
pub fn load_self() -> Option<Vec<u8>> {
|
||||
unsafe {
|
||||
use libc::funcs::extra::_NSGetExecutablePath;
|
||||
let mut sz: u32 = 0;
|
||||
_NSGetExecutablePath(ptr::null_mut(), &mut sz);
|
||||
if sz == 0 { return None; }
|
||||
let mut v: Vec<u8> = Vec::with_capacity(sz as uint);
|
||||
let err = _NSGetExecutablePath(v.as_mut_ptr() as *mut i8, &mut sz);
|
||||
if err != 0 { return None; }
|
||||
v.set_len(sz as uint - 1); // chop off trailing NUL
|
||||
Some(v)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn chdir(p: &Path) -> IoResult<()> {
|
||||
p.with_c_str(|buf| {
|
||||
unsafe {
|
||||
match libc::chdir(buf) == (0 as c_int) {
|
||||
true => Ok(()),
|
||||
false => Err(IoError::last_error()),
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn page_size() -> uint {
|
||||
unsafe {
|
||||
libc::sysconf(libc::_SC_PAGESIZE) as uint
|
||||
}
|
||||
}
|
||||
|
@ -8,17 +8,27 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
//! Implementation of `std::os` functionality for Windows
|
||||
|
||||
// FIXME: move various extern bindings from here into liblibc or
|
||||
// something similar
|
||||
|
||||
use libc;
|
||||
use libc::{c_int, c_char, c_void};
|
||||
use prelude::*;
|
||||
|
||||
use fmt;
|
||||
use io::{IoResult, IoError};
|
||||
use libc::{c_int, c_char, c_void};
|
||||
use libc;
|
||||
use os;
|
||||
use path::{Path, GenericPath, BytesContainer};
|
||||
use ptr::{mod, RawPtr};
|
||||
use sync::atomic::{AtomicInt, INIT_ATOMIC_INT, SeqCst};
|
||||
use sys::fs::FileDesc;
|
||||
use ptr;
|
||||
|
||||
use os::TMPBUF_SZ;
|
||||
use libc::types::os::arch::extra::DWORD;
|
||||
|
||||
const BUF_BYTES : uint = 2048u;
|
||||
|
||||
pub fn errno() -> uint {
|
||||
use libc::types::os::arch::extra::DWORD;
|
||||
@ -101,3 +111,185 @@ pub unsafe fn pipe() -> IoResult<(FileDesc, FileDesc)> {
|
||||
_ => Err(IoError::last_error()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fill_utf16_buf_and_decode(f: |*mut u16, DWORD| -> DWORD) -> Option<String> {
|
||||
unsafe {
|
||||
let mut n = TMPBUF_SZ as DWORD;
|
||||
let mut res = None;
|
||||
let mut done = false;
|
||||
while !done {
|
||||
let mut buf = Vec::from_elem(n as uint, 0u16);
|
||||
let k = f(buf.as_mut_ptr(), n);
|
||||
if k == (0 as DWORD) {
|
||||
done = true;
|
||||
} else if k == n &&
|
||||
libc::GetLastError() ==
|
||||
libc::ERROR_INSUFFICIENT_BUFFER as DWORD {
|
||||
n *= 2 as DWORD;
|
||||
} else if k >= n {
|
||||
n = k;
|
||||
} else {
|
||||
done = true;
|
||||
}
|
||||
if k != 0 && done {
|
||||
let sub = buf.slice(0, k as uint);
|
||||
// We want to explicitly catch the case when the
|
||||
// closure returned invalid UTF-16, rather than
|
||||
// set `res` to None and continue.
|
||||
let s = String::from_utf16(sub)
|
||||
.expect("fill_utf16_buf_and_decode: closure created invalid UTF-16");
|
||||
res = option::Some(s)
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn getcwd() -> IoResult<Path> {
|
||||
use libc::DWORD;
|
||||
use libc::GetCurrentDirectoryW;
|
||||
use io::OtherIoError;
|
||||
|
||||
let mut buf = [0 as u16, ..BUF_BYTES];
|
||||
unsafe {
|
||||
if libc::GetCurrentDirectoryW(buf.len() as DWORD, buf.as_mut_ptr()) == 0 as DWORD {
|
||||
return Err(IoError::last_error());
|
||||
}
|
||||
}
|
||||
|
||||
match String::from_utf16(::str::truncate_utf16_at_nul(&buf)) {
|
||||
Some(ref cwd) => Ok(Path::new(cwd)),
|
||||
None => Err(IoError {
|
||||
kind: OtherIoError,
|
||||
desc: "GetCurrentDirectoryW returned invalid UTF-16",
|
||||
detail: None,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn get_env_pairs() -> Vec<Vec<u8>> {
|
||||
use libc::funcs::extra::kernel32::{
|
||||
GetEnvironmentStringsW,
|
||||
FreeEnvironmentStringsW
|
||||
};
|
||||
let ch = GetEnvironmentStringsW();
|
||||
if ch as uint == 0 {
|
||||
panic!("os::env() failure getting env string from OS: {}",
|
||||
os::last_os_error());
|
||||
}
|
||||
// Here, we lossily decode the string as UTF16.
|
||||
//
|
||||
// The docs suggest that the result should be in Unicode, but
|
||||
// Windows doesn't guarantee it's actually UTF16 -- it doesn't
|
||||
// validate the environment string passed to CreateProcess nor
|
||||
// SetEnvironmentVariable. Yet, it's unlikely that returning a
|
||||
// raw u16 buffer would be of practical use since the result would
|
||||
// be inherently platform-dependent and introduce additional
|
||||
// complexity to this code.
|
||||
//
|
||||
// Using the non-Unicode version of GetEnvironmentStrings is even
|
||||
// worse since the result is in an OEM code page. Characters that
|
||||
// can't be encoded in the code page would be turned into question
|
||||
// marks.
|
||||
let mut result = Vec::new();
|
||||
let mut i = 0;
|
||||
while *ch.offset(i) != 0 {
|
||||
let p = &*ch.offset(i);
|
||||
let mut len = 0;
|
||||
while *(p as *const _).offset(len) != 0 {
|
||||
len += 1;
|
||||
}
|
||||
let p = p as *const u16;
|
||||
let s = slice::from_raw_buf(&p, len as uint);
|
||||
result.push(String::from_utf16_lossy(s).into_bytes());
|
||||
i += len as int + 1;
|
||||
}
|
||||
FreeEnvironmentStringsW(ch);
|
||||
result
|
||||
}
|
||||
|
||||
pub fn split_paths(unparsed: &[u8]) -> Vec<Path> {
|
||||
// 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 mut parsed = Vec::new();
|
||||
let mut in_progress = Vec::new();
|
||||
let mut in_quote = false;
|
||||
|
||||
for b in unparsed.iter() {
|
||||
match *b {
|
||||
b';' if !in_quote => {
|
||||
parsed.push(Path::new(in_progress.as_slice()));
|
||||
in_progress.truncate(0)
|
||||
}
|
||||
b'"' => {
|
||||
in_quote = !in_quote;
|
||||
}
|
||||
_ => {
|
||||
in_progress.push(*b);
|
||||
}
|
||||
}
|
||||
}
|
||||
parsed.push(Path::new(in_progress));
|
||||
parsed
|
||||
}
|
||||
|
||||
pub fn join_paths<T: BytesContainer>(paths: &[T]) -> Result<Vec<u8>, &'static str> {
|
||||
let mut joined = Vec::new();
|
||||
let sep = b';';
|
||||
|
||||
for (i, path) in paths.iter().map(|p| p.container_as_bytes()).enumerate() {
|
||||
if i > 0 { joined.push(sep) }
|
||||
if path.contains(&b'"') {
|
||||
return Err("path segment contains `\"`");
|
||||
} else if path.contains(&sep) {
|
||||
joined.push(b'"');
|
||||
joined.push_all(path);
|
||||
joined.push(b'"');
|
||||
} else {
|
||||
joined.push_all(path);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(joined)
|
||||
}
|
||||
|
||||
pub fn load_self() -> Option<Vec<u8>> {
|
||||
unsafe {
|
||||
fill_utf16_buf_and_decode(|buf, sz| {
|
||||
libc::GetModuleFileNameW(0u as libc::DWORD, buf, sz)
|
||||
}).map(|s| s.into_string().into_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn chdir(p: &Path) -> IoResult<()> {
|
||||
let mut p = p.as_str().unwrap().utf16_units().collect::<Vec<u16>>();
|
||||
p.push(0);
|
||||
|
||||
unsafe {
|
||||
match libc::SetCurrentDirectoryW(p.as_ptr()) != (0 as libc::BOOL) {
|
||||
true => Ok(()),
|
||||
false => Err(IoError::last_error()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn page_size() -> uint {
|
||||
use mem;
|
||||
unsafe {
|
||||
let mut info = mem::zeroed();
|
||||
libc::GetSystemInfo(&mut info);
|
||||
|
||||
return info.dwPageSize as uint;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user