2012-07-04 16:53:12 -05:00
|
|
|
/*!
|
|
|
|
* Higher-level interfaces to libc::* functions and operating system services.
|
|
|
|
*
|
|
|
|
* In general these take and return rust types, use rust idioms (enums,
|
|
|
|
* closures, vectors) rather than C idioms, and do more extensive safety
|
|
|
|
* checks.
|
|
|
|
*
|
|
|
|
* This module is not meant to only contain 1:1 mappings to libc entries; any
|
|
|
|
* os-interface code that is reasonably useful and broadly applicable can go
|
|
|
|
* here. Including utility routines that merely build on other os code.
|
|
|
|
*
|
|
|
|
* We assume the general case is that users do not care, and do not want to
|
|
|
|
* be made to care, which operating system they are on. While they may want
|
|
|
|
* to special case various special cases -- and so we will not _hide_ the
|
|
|
|
* facts of which OS the user is on -- they should be given the opportunity
|
|
|
|
* to write OS-ignorant code by default.
|
|
|
|
*/
|
2012-03-02 19:20:00 -06:00
|
|
|
|
2012-03-06 20:49:08 -06:00
|
|
|
import libc::{c_char, c_void, c_int, c_uint, size_t, ssize_t,
|
|
|
|
mode_t, pid_t, FILE};
|
2012-03-02 19:20:00 -06:00
|
|
|
import libc::{close, fclose};
|
|
|
|
|
2012-03-06 20:49:08 -06:00
|
|
|
import option::{some, none};
|
|
|
|
|
2012-03-02 19:20:00 -06:00
|
|
|
import getcwd = rustrt::rust_getcwd;
|
|
|
|
import consts::*;
|
2012-07-23 18:53:22 -05:00
|
|
|
import task::task_builder;
|
2012-03-02 19:20:00 -06:00
|
|
|
|
2012-03-12 22:04:27 -05:00
|
|
|
export close, fclose, fsync_fd, waitpid;
|
2012-03-02 19:20:00 -06:00
|
|
|
export env, getenv, setenv, fdopen, pipe;
|
|
|
|
export getcwd, dll_filename, self_exe_path;
|
2012-06-06 23:39:41 -05:00
|
|
|
export exe_suffix, dll_suffix, sysname, arch, family;
|
2012-04-01 10:39:17 -05:00
|
|
|
export homedir, list_dir, list_dir_path, path_is_dir, path_exists,
|
2012-04-02 16:07:07 -05:00
|
|
|
make_absolute, make_dir, remove_dir, change_dir, remove_file,
|
|
|
|
copy_file;
|
2012-04-19 03:23:00 -05:00
|
|
|
export last_os_error;
|
2012-04-19 03:26:17 -05:00
|
|
|
export set_exit_status;
|
2012-04-21 17:45:51 -05:00
|
|
|
export walk_dir;
|
2012-03-12 22:04:27 -05:00
|
|
|
|
2012-06-14 20:57:59 -05:00
|
|
|
// FIXME: move these to str perhaps? #2620
|
2012-03-12 22:04:27 -05:00
|
|
|
export as_c_charp, fill_charp_buf;
|
2012-03-02 19:20:00 -06:00
|
|
|
|
2012-07-03 18:11:00 -05:00
|
|
|
extern mod rustrt {
|
2012-07-14 00:57:48 -05:00
|
|
|
fn rust_getcwd() -> ~str;
|
2012-03-14 17:10:34 -05:00
|
|
|
fn rust_path_is_dir(path: *libc::c_char) -> c_int;
|
|
|
|
fn rust_path_exists(path: *libc::c_char) -> c_int;
|
2012-07-14 00:57:48 -05:00
|
|
|
fn rust_list_files(path: ~str) -> ~[~str];
|
2012-03-05 15:20:57 -06:00
|
|
|
fn rust_process_wait(handle: c_int) -> c_int;
|
2012-07-14 00:57:48 -05:00
|
|
|
fn last_os_error() -> ~str;
|
2012-04-19 03:26:17 -05:00
|
|
|
fn rust_set_exit_status(code: libc::intptr_t);
|
2012-03-02 19:20:00 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-03-06 20:49:08 -06:00
|
|
|
const tmpbuf_sz : uint = 1000u;
|
|
|
|
|
2012-07-14 00:57:48 -05:00
|
|
|
fn as_c_charp<T>(s: ~str, f: fn(*c_char) -> T) -> T {
|
2012-06-30 18:19:07 -05:00
|
|
|
str::as_c_str(s, |b| f(b as *c_char))
|
2012-03-02 19:20:00 -06:00
|
|
|
}
|
|
|
|
|
2012-03-26 20:35:18 -05:00
|
|
|
fn fill_charp_buf(f: fn(*mut c_char, size_t) -> bool)
|
2012-07-14 00:57:48 -05:00
|
|
|
-> option<~str> {
|
2012-03-12 17:52:30 -05:00
|
|
|
let buf = vec::to_mut(vec::from_elem(tmpbuf_sz, 0u8 as c_char));
|
2012-07-24 14:35:34 -05:00
|
|
|
do vec::as_mut_buf(buf) |b, sz| {
|
|
|
|
if f(b, sz as size_t) unsafe {
|
2012-03-19 17:25:26 -05:00
|
|
|
some(str::unsafe::from_buf(b as *u8))
|
2012-03-06 20:49:08 -06:00
|
|
|
} else {
|
|
|
|
none
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-07 23:38:25 -05:00
|
|
|
#[cfg(windows)]
|
2012-03-06 20:49:08 -06:00
|
|
|
mod win32 {
|
|
|
|
import dword = libc::types::os::arch::extra::DWORD;
|
|
|
|
|
2012-03-26 20:35:18 -05:00
|
|
|
fn fill_utf16_buf_and_decode(f: fn(*mut u16, dword) -> dword)
|
2012-07-14 12:05:49 -05:00
|
|
|
-> option<~str> {
|
2012-03-12 22:04:27 -05:00
|
|
|
|
2012-06-14 20:57:59 -05:00
|
|
|
// FIXME: remove these when export globs work properly. #1238
|
2012-03-12 22:04:27 -05:00
|
|
|
import libc::funcs::extra::kernel32::*;
|
|
|
|
import libc::consts::os::extra::*;
|
|
|
|
|
2012-06-04 19:26:17 -05:00
|
|
|
let mut n = tmpbuf_sz as dword;
|
2012-03-12 22:04:27 -05:00
|
|
|
let mut res = none;
|
|
|
|
let mut done = false;
|
|
|
|
while !done {
|
2012-06-04 19:26:17 -05:00
|
|
|
let buf = vec::to_mut(vec::from_elem(n as uint, 0u16));
|
2012-07-24 15:53:15 -05:00
|
|
|
do vec::as_mut_buf(buf) |b, _sz| {
|
2012-03-12 22:04:27 -05:00
|
|
|
let k : dword = f(b, tmpbuf_sz as dword);
|
|
|
|
if k == (0 as dword) {
|
|
|
|
done = true;
|
|
|
|
} else if (k == n &&
|
|
|
|
GetLastError() ==
|
|
|
|
ERROR_INSUFFICIENT_BUFFER as dword) {
|
|
|
|
n *= (2 as dword);
|
|
|
|
} else {
|
|
|
|
let sub = vec::slice(buf, 0u, k as uint);
|
2012-07-14 12:05:49 -05:00
|
|
|
res = option::some(str::from_utf16(sub));
|
2012-03-12 22:04:27 -05:00
|
|
|
done = true;
|
|
|
|
}
|
2012-03-06 20:49:08 -06:00
|
|
|
}
|
|
|
|
}
|
2012-08-01 19:30:05 -05:00
|
|
|
return res;
|
2012-03-06 20:49:08 -06:00
|
|
|
}
|
|
|
|
|
2012-07-14 12:05:49 -05:00
|
|
|
fn as_utf16_p<T>(s: ~str, f: fn(*u16) -> T) -> T {
|
2012-03-06 22:48:40 -06:00
|
|
|
let mut t = str::to_utf16(s);
|
2012-03-06 20:49:08 -06:00
|
|
|
// Null terminate before passing on.
|
2012-06-29 18:26:56 -05:00
|
|
|
t += ~[0u16];
|
2012-07-24 16:08:12 -05:00
|
|
|
vec::as_buf(t, |buf, _len| f(buf))
|
2012-03-06 20:49:08 -06:00
|
|
|
}
|
2012-03-06 18:00:29 -06:00
|
|
|
}
|
|
|
|
|
2012-07-14 00:57:48 -05:00
|
|
|
fn getenv(n: ~str) -> option<~str> {
|
2012-04-30 19:28:14 -05:00
|
|
|
global_env::getenv(n)
|
2012-03-02 19:20:00 -06:00
|
|
|
}
|
|
|
|
|
2012-07-14 00:57:48 -05:00
|
|
|
fn setenv(n: ~str, v: ~str) {
|
2012-04-30 19:28:14 -05:00
|
|
|
global_env::setenv(n, v)
|
2012-03-02 19:20:00 -06:00
|
|
|
}
|
|
|
|
|
2012-07-25 16:37:40 -05:00
|
|
|
fn env() -> ~[(~str,~str)] {
|
|
|
|
global_env::env()
|
|
|
|
}
|
|
|
|
|
2012-04-30 19:42:41 -05:00
|
|
|
mod global_env {
|
2012-07-04 16:53:12 -05:00
|
|
|
//! Internal module for serializing access to getenv/setenv
|
2012-04-30 19:42:41 -05:00
|
|
|
|
|
|
|
export getenv;
|
|
|
|
export setenv;
|
2012-07-25 16:37:40 -05:00
|
|
|
export env;
|
2012-04-30 19:42:41 -05:00
|
|
|
|
2012-07-03 18:11:00 -05:00
|
|
|
extern mod rustrt {
|
2012-04-30 19:42:41 -05:00
|
|
|
fn rust_global_env_chan_ptr() -> *libc::uintptr_t;
|
|
|
|
}
|
|
|
|
|
2012-08-14 15:38:35 -05:00
|
|
|
enum Msg {
|
|
|
|
MsgGetEnv(~str, comm::chan<option<~str>>),
|
|
|
|
MsgSetEnv(~str, ~str, comm::chan<()>),
|
|
|
|
MsgEnv(comm::chan<~[(~str,~str)]>)
|
2012-04-30 19:42:41 -05:00
|
|
|
}
|
|
|
|
|
2012-07-14 00:57:48 -05:00
|
|
|
fn getenv(n: ~str) -> option<~str> {
|
2012-04-30 19:42:41 -05:00
|
|
|
let env_ch = get_global_env_chan();
|
|
|
|
let po = comm::port();
|
2012-08-14 15:38:35 -05:00
|
|
|
comm::send(env_ch, MsgGetEnv(n, comm::chan(po)));
|
2012-04-30 19:42:41 -05:00
|
|
|
comm::recv(po)
|
|
|
|
}
|
|
|
|
|
2012-07-14 00:57:48 -05:00
|
|
|
fn setenv(n: ~str, v: ~str) {
|
2012-04-30 19:42:41 -05:00
|
|
|
let env_ch = get_global_env_chan();
|
|
|
|
let po = comm::port();
|
2012-08-14 15:38:35 -05:00
|
|
|
comm::send(env_ch, MsgSetEnv(n, v, comm::chan(po)));
|
2012-04-30 19:42:41 -05:00
|
|
|
comm::recv(po)
|
|
|
|
}
|
|
|
|
|
2012-07-25 16:37:40 -05:00
|
|
|
fn env() -> ~[(~str,~str)] {
|
|
|
|
let env_ch = get_global_env_chan();
|
|
|
|
let po = comm::port();
|
2012-08-14 15:38:35 -05:00
|
|
|
comm::send(env_ch, MsgEnv(comm::chan(po)));
|
2012-07-25 16:37:40 -05:00
|
|
|
comm::recv(po)
|
|
|
|
}
|
|
|
|
|
2012-08-14 15:38:35 -05:00
|
|
|
fn get_global_env_chan() -> comm::chan<Msg> {
|
2012-04-30 19:42:41 -05:00
|
|
|
let global_ptr = rustrt::rust_global_env_chan_ptr();
|
|
|
|
unsafe {
|
2012-08-10 20:15:08 -05:00
|
|
|
priv::chan_from_global_ptr(global_ptr, || {
|
|
|
|
// FIXME (#2621): This would be a good place to use a very
|
|
|
|
// small foreign stack
|
|
|
|
task::task().sched_mode(task::single_threaded).unlinked()
|
|
|
|
}, global_env_task)
|
2012-04-30 19:42:41 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-14 15:38:35 -05:00
|
|
|
fn global_env_task(msg_po: comm::port<Msg>) {
|
2012-06-24 22:18:18 -05:00
|
|
|
unsafe {
|
2012-06-30 18:19:07 -05:00
|
|
|
do priv::weaken_task |weak_po| {
|
2012-06-24 22:18:18 -05:00
|
|
|
loop {
|
2012-08-06 14:34:08 -05:00
|
|
|
match comm::select2(msg_po, weak_po) {
|
2012-08-14 15:38:35 -05:00
|
|
|
either::left(MsgGetEnv(n, resp_ch)) => {
|
2012-06-24 22:18:18 -05:00
|
|
|
comm::send(resp_ch, impl::getenv(n))
|
|
|
|
}
|
2012-08-14 15:38:35 -05:00
|
|
|
either::left(MsgSetEnv(n, v, resp_ch)) => {
|
2012-06-24 22:18:18 -05:00
|
|
|
comm::send(resp_ch, impl::setenv(n, v))
|
|
|
|
}
|
2012-08-14 15:38:35 -05:00
|
|
|
either::left(MsgEnv(resp_ch)) => {
|
2012-07-25 16:37:40 -05:00
|
|
|
comm::send(resp_ch, impl::env())
|
|
|
|
}
|
2012-08-03 21:59:04 -05:00
|
|
|
either::right(_) => break
|
2012-06-24 22:18:18 -05:00
|
|
|
}
|
2012-04-30 19:42:41 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mod impl {
|
2012-07-25 16:37:40 -05:00
|
|
|
extern mod rustrt {
|
|
|
|
fn rust_env_pairs() -> ~[~str];
|
|
|
|
}
|
|
|
|
|
|
|
|
fn env() -> ~[(~str,~str)] {
|
|
|
|
let mut pairs = ~[];
|
|
|
|
for vec::each(rustrt::rust_env_pairs()) |p| {
|
|
|
|
let vs = str::splitn_char(p, '=', 1u);
|
|
|
|
assert vec::len(vs) == 2u;
|
|
|
|
vec::push(pairs, (vs[0], vs[1]));
|
|
|
|
}
|
2012-08-01 19:30:05 -05:00
|
|
|
return pairs;
|
2012-07-25 16:37:40 -05:00
|
|
|
}
|
2012-04-30 19:42:41 -05:00
|
|
|
|
2012-06-07 23:38:25 -05:00
|
|
|
#[cfg(unix)]
|
2012-07-14 00:57:48 -05:00
|
|
|
fn getenv(n: ~str) -> option<~str> {
|
2012-06-24 22:18:18 -05:00
|
|
|
unsafe {
|
|
|
|
let s = str::as_c_str(n, libc::getenv);
|
2012-08-01 19:30:05 -05:00
|
|
|
return if unsafe::reinterpret_cast(s) == 0 {
|
2012-07-14 00:57:48 -05:00
|
|
|
option::none::<~str>
|
2012-06-24 22:18:18 -05:00
|
|
|
} else {
|
|
|
|
let s = unsafe::reinterpret_cast(s);
|
2012-07-14 00:57:48 -05:00
|
|
|
option::some::<~str>(str::unsafe::from_buf(s))
|
2012-06-24 22:18:18 -05:00
|
|
|
};
|
|
|
|
}
|
2012-04-30 19:42:41 -05:00
|
|
|
}
|
|
|
|
|
2012-06-07 23:38:25 -05:00
|
|
|
#[cfg(windows)]
|
2012-07-14 12:05:49 -05:00
|
|
|
fn getenv(n: ~str) -> option<~str> {
|
2012-04-30 19:42:41 -05:00
|
|
|
import libc::types::os::arch::extra::*;
|
|
|
|
import libc::funcs::extra::kernel32::*;
|
|
|
|
import win32::*;
|
2012-06-30 18:19:07 -05:00
|
|
|
do as_utf16_p(n) |u| {
|
|
|
|
do fill_utf16_buf_and_decode() |buf, sz| {
|
2012-04-30 19:42:41 -05:00
|
|
|
GetEnvironmentVariableW(u, buf, sz)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-07 23:38:25 -05:00
|
|
|
#[cfg(unix)]
|
2012-07-14 00:57:48 -05:00
|
|
|
fn setenv(n: ~str, v: ~str) {
|
2012-04-30 19:42:41 -05:00
|
|
|
|
2012-06-14 20:57:59 -05:00
|
|
|
// FIXME: remove this when export globs work properly. #1238
|
2012-04-30 19:42:41 -05:00
|
|
|
import libc::funcs::posix01::unistd::setenv;
|
2012-06-30 18:19:07 -05:00
|
|
|
do str::as_c_str(n) |nbuf| {
|
|
|
|
do str::as_c_str(v) |vbuf| {
|
2012-04-30 19:42:41 -05:00
|
|
|
setenv(nbuf, vbuf, 1i32);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-07 23:38:25 -05:00
|
|
|
#[cfg(windows)]
|
2012-07-14 12:05:49 -05:00
|
|
|
fn setenv(n: ~str, v: ~str) {
|
2012-06-14 20:57:59 -05:00
|
|
|
// FIXME: remove imports when export globs work properly. #1238
|
2012-04-30 19:42:41 -05:00
|
|
|
import libc::funcs::extra::kernel32::*;
|
|
|
|
import win32::*;
|
2012-06-30 18:19:07 -05:00
|
|
|
do as_utf16_p(n) |nbuf| {
|
|
|
|
do as_utf16_p(v) |vbuf| {
|
2012-04-30 19:42:41 -05:00
|
|
|
SetEnvironmentVariableW(nbuf, vbuf);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-02 19:20:00 -06:00
|
|
|
fn fdopen(fd: c_int) -> *FILE {
|
2012-08-01 19:30:05 -05:00
|
|
|
return do as_c_charp(~"r") |modebuf| {
|
2012-03-02 19:20:00 -06:00
|
|
|
libc::fdopen(fd, modebuf)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-03-05 15:20:57 -06:00
|
|
|
// fsync related
|
|
|
|
|
2012-06-07 23:38:25 -05:00
|
|
|
#[cfg(windows)]
|
2012-08-14 15:38:35 -05:00
|
|
|
fn fsync_fd(fd: c_int, _level: io::fsync::Level) -> c_int {
|
2012-03-05 15:20:57 -06:00
|
|
|
import libc::funcs::extra::msvcrt::*;
|
2012-08-01 19:30:05 -05:00
|
|
|
return commit(fd);
|
2012-03-05 15:20:57 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(target_os = "linux")]
|
2012-08-14 15:38:35 -05:00
|
|
|
fn fsync_fd(fd: c_int, level: io::fsync::Level) -> c_int {
|
2012-03-05 15:20:57 -06:00
|
|
|
import libc::funcs::posix01::unistd::*;
|
2012-08-06 14:34:08 -05:00
|
|
|
match level {
|
2012-08-14 15:38:35 -05:00
|
|
|
io::fsync::FSync
|
|
|
|
| io::fsync::FullFSync => return fsync(fd),
|
|
|
|
io::fsync::FDataSync => return fdatasync(fd)
|
2012-03-05 15:20:57 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(target_os = "macos")]
|
2012-08-14 15:38:35 -05:00
|
|
|
fn fsync_fd(fd: c_int, level: io::fsync::Level) -> c_int {
|
2012-03-05 15:20:57 -06:00
|
|
|
import libc::consts::os::extra::*;
|
|
|
|
import libc::funcs::posix88::fcntl::*;
|
|
|
|
import libc::funcs::posix01::unistd::*;
|
2012-08-06 14:34:08 -05:00
|
|
|
match level {
|
2012-08-14 15:38:35 -05:00
|
|
|
io::fsync::FSync => return fsync(fd),
|
2012-08-03 21:59:04 -05:00
|
|
|
_ => {
|
2012-03-05 15:20:57 -06:00
|
|
|
// According to man fnctl, the ok retval is only specified to be !=-1
|
|
|
|
if (fcntl(F_FULLFSYNC as c_int, fd) == -1 as c_int)
|
2012-08-01 19:30:05 -05:00
|
|
|
{ return -1 as c_int; }
|
2012-03-05 15:20:57 -06:00
|
|
|
else
|
2012-08-01 19:30:05 -05:00
|
|
|
{ return 0 as c_int; }
|
2012-03-05 15:20:57 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(target_os = "freebsd")]
|
2012-08-14 15:38:35 -05:00
|
|
|
fn fsync_fd(fd: c_int, _l: io::fsync::Level) -> c_int {
|
2012-03-05 15:20:57 -06:00
|
|
|
import libc::funcs::posix01::unistd::*;
|
2012-08-01 19:30:05 -05:00
|
|
|
return fsync(fd);
|
2012-03-05 15:20:57 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-06-07 23:38:25 -05:00
|
|
|
#[cfg(windows)]
|
2012-03-05 15:20:57 -06:00
|
|
|
fn waitpid(pid: pid_t) -> c_int {
|
2012-08-01 19:30:05 -05:00
|
|
|
return rustrt::rust_process_wait(pid);
|
2012-03-05 15:20:57 -06:00
|
|
|
}
|
|
|
|
|
2012-06-07 23:38:25 -05:00
|
|
|
#[cfg(unix)]
|
2012-03-05 15:20:57 -06:00
|
|
|
fn waitpid(pid: pid_t) -> c_int {
|
|
|
|
import libc::funcs::posix01::wait::*;
|
|
|
|
let status = 0 as c_int;
|
|
|
|
|
|
|
|
assert (waitpid(pid, ptr::mut_addr_of(status),
|
|
|
|
0 as c_int) != (-1 as c_int));
|
2012-08-01 19:30:05 -05:00
|
|
|
return status;
|
2012-03-05 15:20:57 -06:00
|
|
|
}
|
|
|
|
|
2012-03-02 19:20:00 -06:00
|
|
|
|
2012-06-07 23:38:25 -05:00
|
|
|
#[cfg(unix)]
|
2012-03-02 19:20:00 -06:00
|
|
|
fn pipe() -> {in: c_int, out: c_int} {
|
2012-03-26 20:35:18 -05:00
|
|
|
let fds = {mut in: 0 as c_int,
|
|
|
|
mut out: 0 as c_int };
|
2012-03-02 19:20:00 -06:00
|
|
|
assert (libc::pipe(ptr::mut_addr_of(fds.in)) == (0 as c_int));
|
2012-08-01 19:30:05 -05:00
|
|
|
return {in: fds.in, out: fds.out};
|
2012-03-02 19:20:00 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
2012-06-07 23:38:25 -05:00
|
|
|
#[cfg(windows)]
|
2012-03-02 19:20:00 -06:00
|
|
|
fn pipe() -> {in: c_int, out: c_int} {
|
2012-06-14 20:57:59 -05:00
|
|
|
// FIXME: remove this when export globs work properly. #1238
|
2012-03-02 19:20:00 -06:00
|
|
|
import libc::consts::os::extra::*;
|
|
|
|
// Windows pipes work subtly differently than unix pipes, and their
|
|
|
|
// inheritance has to be handled in a different way that I do not fully
|
|
|
|
// understand. Here we explicitly make the pipe non-inheritable, which
|
|
|
|
// means to pass it to a subprocess they need to be duplicated first, as
|
|
|
|
// in rust_run_program.
|
2012-03-26 20:35:18 -05:00
|
|
|
let fds = { mut in: 0 as c_int,
|
|
|
|
mut out: 0 as c_int };
|
2012-03-02 19:20:00 -06:00
|
|
|
let res = libc::pipe(ptr::mut_addr_of(fds.in),
|
|
|
|
1024 as c_uint,
|
|
|
|
(O_BINARY | O_NOINHERIT) as c_int);
|
|
|
|
assert (res == 0 as c_int);
|
|
|
|
assert (fds.in != -1 as c_int && fds.in != 0 as c_int);
|
|
|
|
assert (fds.out != -1 as c_int && fds.in != 0 as c_int);
|
2012-08-01 19:30:05 -05:00
|
|
|
return {in: fds.in, out: fds.out};
|
2012-03-02 19:20:00 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-14 00:57:48 -05:00
|
|
|
fn dll_filename(base: ~str) -> ~str {
|
2012-08-01 19:30:05 -05:00
|
|
|
return pre() + base + dll_suffix();
|
2012-03-02 19:20:00 -06:00
|
|
|
|
2012-06-07 23:38:25 -05:00
|
|
|
#[cfg(unix)]
|
2012-07-14 00:57:48 -05:00
|
|
|
fn pre() -> ~str { ~"lib" }
|
2012-03-02 19:20:00 -06:00
|
|
|
|
2012-06-07 23:38:25 -05:00
|
|
|
#[cfg(windows)]
|
2012-07-14 12:05:49 -05:00
|
|
|
fn pre() -> ~str { ~"" }
|
2012-03-02 19:20:00 -06:00
|
|
|
}
|
|
|
|
|
2012-03-06 20:49:08 -06:00
|
|
|
|
2012-08-14 15:38:35 -05:00
|
|
|
fn self_exe_path() -> option<Path> {
|
2012-03-02 19:20:00 -06:00
|
|
|
|
|
|
|
#[cfg(target_os = "freebsd")]
|
2012-08-14 15:38:35 -05:00
|
|
|
fn load_self() -> option<Path> {
|
2012-06-24 22:18:18 -05:00
|
|
|
unsafe {
|
|
|
|
import libc::funcs::bsd44::*;
|
|
|
|
import libc::consts::os::extra::*;
|
2012-06-30 18:19:07 -05:00
|
|
|
do fill_charp_buf() |buf, sz| {
|
2012-06-29 18:26:56 -05:00
|
|
|
let mib = ~[CTL_KERN as c_int,
|
2012-06-24 22:18:18 -05:00
|
|
|
KERN_PROC as c_int,
|
2012-06-29 18:26:56 -05:00
|
|
|
KERN_PROC_PATHNAME as c_int, -1 as c_int];
|
2012-06-24 22:18:18 -05:00
|
|
|
sysctl(vec::unsafe::to_ptr(mib), vec::len(mib) as c_uint,
|
|
|
|
buf as *mut c_void, ptr::mut_addr_of(sz),
|
|
|
|
ptr::null(), 0u as size_t) == (0 as c_int)
|
|
|
|
}
|
2012-03-06 20:49:08 -06:00
|
|
|
}
|
2012-03-02 19:20:00 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(target_os = "linux")]
|
2012-08-14 15:38:35 -05:00
|
|
|
fn load_self() -> option<Path> {
|
2012-03-02 19:20:00 -06:00
|
|
|
import libc::funcs::posix01::unistd::readlink;
|
2012-06-30 18:19:07 -05:00
|
|
|
do fill_charp_buf() |buf, sz| {
|
2012-07-14 00:57:48 -05:00
|
|
|
do as_c_charp(~"/proc/self/exe") |proc_self_buf| {
|
2012-03-06 20:49:08 -06:00
|
|
|
readlink(proc_self_buf, buf, sz) != (-1 as ssize_t)
|
|
|
|
}
|
2012-03-02 19:20:00 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-06 20:49:08 -06:00
|
|
|
#[cfg(target_os = "macos")]
|
2012-08-14 15:38:35 -05:00
|
|
|
fn load_self() -> option<Path> {
|
2012-06-14 20:57:59 -05:00
|
|
|
// FIXME: remove imports when export globs work properly. #1238
|
2012-03-06 20:49:08 -06:00
|
|
|
import libc::funcs::extra::*;
|
2012-06-30 18:19:07 -05:00
|
|
|
do fill_charp_buf() |buf, sz| {
|
2012-03-06 20:49:08 -06:00
|
|
|
_NSGetExecutablePath(buf, ptr::mut_addr_of(sz as u32))
|
|
|
|
== (0 as c_int)
|
|
|
|
}
|
2012-03-02 19:20:00 -06:00
|
|
|
}
|
|
|
|
|
2012-06-07 23:38:25 -05:00
|
|
|
#[cfg(windows)]
|
2012-08-14 15:38:35 -05:00
|
|
|
fn load_self() -> option<Path> {
|
2012-06-14 20:57:59 -05:00
|
|
|
// FIXME: remove imports when export globs work properly. #1238
|
2012-03-06 20:49:08 -06:00
|
|
|
import libc::types::os::arch::extra::*;
|
|
|
|
import libc::funcs::extra::kernel32::*;
|
|
|
|
import win32::*;
|
2012-06-30 18:19:07 -05:00
|
|
|
do fill_utf16_buf_and_decode() |buf, sz| {
|
2012-06-04 19:26:17 -05:00
|
|
|
GetModuleFileNameW(0u as dword, buf, sz)
|
2012-03-06 20:49:08 -06:00
|
|
|
}
|
2012-03-02 19:20:00 -06:00
|
|
|
}
|
|
|
|
|
2012-06-30 18:19:07 -05:00
|
|
|
do option::map(load_self()) |pth| {
|
2012-03-06 20:49:08 -06:00
|
|
|
path::dirname(pth) + path::path_sep()
|
|
|
|
}
|
2012-03-02 19:20:00 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/**
|
|
|
|
* Returns the path to the user's home directory, if known.
|
|
|
|
*
|
|
|
|
* On Unix, returns the value of the 'HOME' environment variable if it is set
|
|
|
|
* and not equal to the empty string.
|
|
|
|
*
|
|
|
|
* On Windows, returns the value of the 'HOME' environment variable if it is
|
|
|
|
* set and not equal to the empty string. Otherwise, returns the value of the
|
|
|
|
* 'USERPROFILE' environment variable if it is set and not equal to the empty
|
|
|
|
* string.
|
|
|
|
*
|
|
|
|
* Otherwise, homedir returns option::none.
|
|
|
|
*/
|
2012-08-14 15:38:35 -05:00
|
|
|
fn homedir() -> option<Path> {
|
2012-08-06 14:34:08 -05:00
|
|
|
return match getenv(~"HOME") {
|
2012-08-03 21:59:04 -05:00
|
|
|
some(p) => if !str::is_empty(p) {
|
|
|
|
some(p)
|
|
|
|
} else {
|
|
|
|
secondary()
|
2012-08-06 19:14:32 -05:00
|
|
|
},
|
2012-08-03 21:59:04 -05:00
|
|
|
none => secondary()
|
2012-03-02 19:20:00 -06:00
|
|
|
};
|
|
|
|
|
2012-06-07 23:38:25 -05:00
|
|
|
#[cfg(unix)]
|
2012-08-14 15:38:35 -05:00
|
|
|
fn secondary() -> option<Path> {
|
2012-03-02 19:20:00 -06:00
|
|
|
none
|
|
|
|
}
|
|
|
|
|
2012-06-07 23:38:25 -05:00
|
|
|
#[cfg(windows)]
|
2012-08-14 15:38:35 -05:00
|
|
|
fn secondary() -> option<Path> {
|
2012-07-14 12:05:49 -05:00
|
|
|
do option::chain(getenv(~"USERPROFILE")) |p| {
|
2012-03-02 19:20:00 -06:00
|
|
|
if !str::is_empty(p) {
|
|
|
|
some(p)
|
|
|
|
} else {
|
|
|
|
none
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/// Recursively walk a directory structure
|
2012-08-14 15:38:35 -05:00
|
|
|
fn walk_dir(p: Path, f: fn(Path) -> bool) {
|
2012-03-02 19:20:00 -06:00
|
|
|
|
2012-04-21 17:45:51 -05:00
|
|
|
walk_dir_(p, f);
|
|
|
|
|
2012-08-14 15:38:35 -05:00
|
|
|
fn walk_dir_(p: Path, f: fn(Path) -> bool) -> bool {
|
2012-04-21 17:45:51 -05:00
|
|
|
let mut keepgoing = true;
|
2012-06-30 18:19:07 -05:00
|
|
|
do list_dir(p).each |q| {
|
2012-04-21 17:45:51 -05:00
|
|
|
let path = path::connect(p, q);
|
|
|
|
if !f(path) {
|
|
|
|
keepgoing = false;
|
|
|
|
false
|
|
|
|
} else {
|
|
|
|
if path_is_dir(path) {
|
|
|
|
if !walk_dir_(path, f) {
|
|
|
|
keepgoing = false;
|
|
|
|
false
|
|
|
|
} else {
|
|
|
|
true
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-08-01 19:30:05 -05:00
|
|
|
return keepgoing;
|
2012-04-21 17:45:51 -05:00
|
|
|
}
|
|
|
|
}
|
2012-03-02 19:20:00 -06:00
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/// Indicates whether a path represents a directory
|
2012-08-14 15:38:35 -05:00
|
|
|
fn path_is_dir(p: Path) -> bool {
|
2012-06-30 18:19:07 -05:00
|
|
|
do str::as_c_str(p) |buf| {
|
2012-03-02 19:20:00 -06:00
|
|
|
rustrt::rust_path_is_dir(buf) != 0 as c_int
|
2012-03-06 20:49:08 -06:00
|
|
|
}
|
2012-03-02 19:20:00 -06:00
|
|
|
}
|
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/// Indicates whether a path exists
|
2012-08-14 15:38:35 -05:00
|
|
|
fn path_exists(p: Path) -> bool {
|
2012-06-30 18:19:07 -05:00
|
|
|
do str::as_c_str(p) |buf| {
|
2012-03-02 19:20:00 -06:00
|
|
|
rustrt::rust_path_exists(buf) != 0 as c_int
|
2012-03-06 20:49:08 -06:00
|
|
|
}
|
2012-03-02 19:20:00 -06:00
|
|
|
}
|
|
|
|
|
2012-06-21 18:44:10 -05:00
|
|
|
// FIXME (#2622): under Windows, we should prepend the current drive letter
|
|
|
|
// to paths that start with a slash.
|
2012-07-04 16:53:12 -05:00
|
|
|
/**
|
|
|
|
* Convert a relative path to an absolute path
|
|
|
|
*
|
|
|
|
* If the given path is relative, return it prepended with the current working
|
|
|
|
* directory. If the given path is already an absolute path, return it
|
|
|
|
* as is.
|
|
|
|
*/
|
2012-03-02 19:20:00 -06:00
|
|
|
// NB: this is here rather than in path because it is a form of environment
|
|
|
|
// querying; what it does depends on the process working directory, not just
|
|
|
|
// the input paths.
|
2012-08-14 15:38:35 -05:00
|
|
|
fn make_absolute(p: Path) -> Path {
|
2012-03-02 19:20:00 -06:00
|
|
|
if path::path_is_absolute(p) {
|
|
|
|
p
|
|
|
|
} else {
|
|
|
|
path::connect(getcwd(), p)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/// Creates a directory at the specified path
|
2012-08-14 15:38:35 -05:00
|
|
|
fn make_dir(p: Path, mode: c_int) -> bool {
|
2012-08-01 19:30:05 -05:00
|
|
|
return mkdir(p, mode);
|
2012-03-02 19:20:00 -06:00
|
|
|
|
2012-06-07 23:38:25 -05:00
|
|
|
#[cfg(windows)]
|
2012-08-14 15:38:35 -05:00
|
|
|
fn mkdir(p: Path, _mode: c_int) -> bool {
|
2012-06-14 20:57:59 -05:00
|
|
|
// FIXME: remove imports when export globs work properly. #1238
|
2012-03-06 20:49:08 -06:00
|
|
|
import libc::types::os::arch::extra::*;
|
|
|
|
import libc::funcs::extra::kernel32::*;
|
|
|
|
import win32::*;
|
2012-06-14 20:57:59 -05:00
|
|
|
// FIXME: turn mode into something useful? #2623
|
2012-06-30 18:19:07 -05:00
|
|
|
do as_utf16_p(p) |buf| {
|
2012-06-24 22:18:18 -05:00
|
|
|
CreateDirectoryW(buf, unsafe { unsafe::reinterpret_cast(0) })
|
2012-03-06 20:49:08 -06:00
|
|
|
!= (0 as BOOL)
|
|
|
|
}
|
2012-03-02 19:20:00 -06:00
|
|
|
}
|
|
|
|
|
2012-06-07 23:38:25 -05:00
|
|
|
#[cfg(unix)]
|
2012-08-14 15:38:35 -05:00
|
|
|
fn mkdir(p: Path, mode: c_int) -> bool {
|
2012-06-30 18:19:07 -05:00
|
|
|
do as_c_charp(p) |c| {
|
2012-03-02 19:20:00 -06:00
|
|
|
libc::mkdir(c, mode as mode_t) == (0 as c_int)
|
2012-03-06 20:49:08 -06:00
|
|
|
}
|
2012-03-02 19:20:00 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/// Lists the contents of a directory
|
2012-08-14 15:38:35 -05:00
|
|
|
fn list_dir(p: Path) -> ~[~str] {
|
2012-03-02 19:20:00 -06:00
|
|
|
|
2012-06-07 23:38:25 -05:00
|
|
|
#[cfg(unix)]
|
2012-07-14 00:57:48 -05:00
|
|
|
fn star(p: ~str) -> ~str { p }
|
2012-03-02 19:20:00 -06:00
|
|
|
|
2012-06-07 23:38:25 -05:00
|
|
|
#[cfg(windows)]
|
2012-07-14 12:27:09 -05:00
|
|
|
fn star(p: ~str) -> ~str {
|
2012-04-01 10:39:17 -05:00
|
|
|
let pl = str::len(p);
|
|
|
|
if pl == 0u || (p[pl - 1u] as char != path::consts::path_sep
|
2012-04-01 17:05:29 -05:00
|
|
|
|| p[pl - 1u] as char != path::consts::alt_path_sep) {
|
2012-07-14 12:05:49 -05:00
|
|
|
p + path::path_sep() + ~"*"
|
2012-04-01 10:39:17 -05:00
|
|
|
} else {
|
2012-07-14 12:05:49 -05:00
|
|
|
p + ~"*"
|
2012-04-01 10:39:17 -05:00
|
|
|
}
|
|
|
|
}
|
2012-03-02 19:20:00 -06:00
|
|
|
|
2012-06-30 18:19:07 -05:00
|
|
|
do rustrt::rust_list_files(star(p)).filter |filename| {
|
2012-08-02 17:42:56 -05:00
|
|
|
filename != ~"." && filename != ~".."
|
2012-04-01 10:39:17 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/**
|
|
|
|
* Lists the contents of a directory
|
|
|
|
*
|
|
|
|
* This version prepends each entry with the directory.
|
|
|
|
*/
|
2012-08-14 15:38:35 -05:00
|
|
|
fn list_dir_path(p: Path) -> ~[~str] {
|
2012-03-06 22:48:40 -06:00
|
|
|
let mut p = p;
|
2012-03-02 19:20:00 -06:00
|
|
|
let pl = str::len(p);
|
|
|
|
if pl == 0u || (p[pl - 1u] as char != path::consts::path_sep
|
|
|
|
&& p[pl - 1u] as char != path::consts::alt_path_sep) {
|
|
|
|
p += path::path_sep();
|
|
|
|
}
|
2012-06-30 18:19:07 -05:00
|
|
|
os::list_dir(p).map(|f| p + f)
|
2012-03-02 19:20:00 -06:00
|
|
|
}
|
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/// Removes a directory at the specified path
|
2012-08-14 15:38:35 -05:00
|
|
|
fn remove_dir(p: Path) -> bool {
|
2012-08-01 19:30:05 -05:00
|
|
|
return rmdir(p);
|
2012-03-02 19:20:00 -06:00
|
|
|
|
2012-06-07 23:38:25 -05:00
|
|
|
#[cfg(windows)]
|
2012-08-14 15:38:35 -05:00
|
|
|
fn rmdir(p: Path) -> bool {
|
2012-06-14 20:57:59 -05:00
|
|
|
// FIXME: remove imports when export globs work properly. #1238
|
2012-03-06 20:49:08 -06:00
|
|
|
import libc::funcs::extra::kernel32::*;
|
2012-03-02 19:20:00 -06:00
|
|
|
import libc::types::os::arch::extra::*;
|
2012-03-06 20:49:08 -06:00
|
|
|
import win32::*;
|
2012-08-01 19:30:05 -05:00
|
|
|
return do as_utf16_p(p) |buf| {
|
2012-03-06 20:49:08 -06:00
|
|
|
RemoveDirectoryW(buf) != (0 as BOOL)
|
2012-03-02 19:20:00 -06:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2012-06-07 23:38:25 -05:00
|
|
|
#[cfg(unix)]
|
2012-08-14 15:38:35 -05:00
|
|
|
fn rmdir(p: Path) -> bool {
|
2012-08-01 19:30:05 -05:00
|
|
|
return do as_c_charp(p) |buf| {
|
2012-03-02 19:20:00 -06:00
|
|
|
libc::rmdir(buf) == (0 as c_int)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-14 15:38:35 -05:00
|
|
|
fn change_dir(p: Path) -> bool {
|
2012-08-01 19:30:05 -05:00
|
|
|
return chdir(p);
|
2012-03-02 19:20:00 -06:00
|
|
|
|
2012-06-07 23:38:25 -05:00
|
|
|
#[cfg(windows)]
|
2012-08-14 15:38:35 -05:00
|
|
|
fn chdir(p: Path) -> bool {
|
2012-06-14 20:57:59 -05:00
|
|
|
// FIXME: remove imports when export globs work properly. #1238
|
2012-03-06 20:49:08 -06:00
|
|
|
import libc::funcs::extra::kernel32::*;
|
2012-03-02 19:20:00 -06:00
|
|
|
import libc::types::os::arch::extra::*;
|
2012-03-06 20:49:08 -06:00
|
|
|
import win32::*;
|
2012-08-01 19:30:05 -05:00
|
|
|
return do as_utf16_p(p) |buf| {
|
2012-03-06 20:49:08 -06:00
|
|
|
SetCurrentDirectoryW(buf) != (0 as BOOL)
|
2012-03-02 19:20:00 -06:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2012-06-07 23:38:25 -05:00
|
|
|
#[cfg(unix)]
|
2012-08-14 15:38:35 -05:00
|
|
|
fn chdir(p: Path) -> bool {
|
2012-08-01 19:30:05 -05:00
|
|
|
return do as_c_charp(p) |buf| {
|
2012-03-02 19:20:00 -06:00
|
|
|
libc::chdir(buf) == (0 as c_int)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/// Copies a file from one location to another
|
2012-08-14 15:38:35 -05:00
|
|
|
fn copy_file(from: Path, to: Path) -> bool {
|
2012-08-01 19:30:05 -05:00
|
|
|
return do_copy_file(from, to);
|
2012-04-02 16:07:07 -05:00
|
|
|
|
2012-06-07 23:38:25 -05:00
|
|
|
#[cfg(windows)]
|
2012-08-14 15:38:35 -05:00
|
|
|
fn do_copy_file(from: Path, to: Path) -> bool {
|
2012-06-14 20:57:59 -05:00
|
|
|
// FIXME: remove imports when export globs work properly. #1238
|
2012-04-02 16:07:07 -05:00
|
|
|
import libc::funcs::extra::kernel32::*;
|
|
|
|
import libc::types::os::arch::extra::*;
|
|
|
|
import win32::*;
|
2012-08-01 19:30:05 -05:00
|
|
|
return do as_utf16_p(from) |fromp| {
|
2012-06-30 18:19:07 -05:00
|
|
|
do as_utf16_p(to) |top| {
|
2012-04-02 16:07:07 -05:00
|
|
|
CopyFileW(fromp, top, (0 as BOOL)) != (0 as BOOL)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-07 23:38:25 -05:00
|
|
|
#[cfg(unix)]
|
2012-08-14 15:38:35 -05:00
|
|
|
fn do_copy_file(from: Path, to: Path) -> bool {
|
2012-06-30 18:19:07 -05:00
|
|
|
let istream = do as_c_charp(from) |fromp| {
|
2012-07-14 00:57:48 -05:00
|
|
|
do as_c_charp(~"rb") |modebuf| {
|
2012-04-02 16:07:07 -05:00
|
|
|
libc::fopen(fromp, modebuf)
|
|
|
|
}
|
|
|
|
};
|
|
|
|
if istream as uint == 0u {
|
2012-08-01 19:30:05 -05:00
|
|
|
return false;
|
2012-04-02 16:07:07 -05:00
|
|
|
}
|
2012-06-30 18:19:07 -05:00
|
|
|
let ostream = do as_c_charp(to) |top| {
|
2012-07-14 00:57:48 -05:00
|
|
|
do as_c_charp(~"w+b") |modebuf| {
|
2012-04-02 16:07:07 -05:00
|
|
|
libc::fopen(top, modebuf)
|
|
|
|
}
|
|
|
|
};
|
|
|
|
if ostream as uint == 0u {
|
|
|
|
fclose(istream);
|
2012-08-01 19:30:05 -05:00
|
|
|
return false;
|
2012-04-02 16:07:07 -05:00
|
|
|
}
|
2012-06-29 18:26:56 -05:00
|
|
|
let mut buf : ~[mut u8] = ~[mut];
|
2012-04-02 16:07:07 -05:00
|
|
|
let bufsize = 8192u;
|
|
|
|
vec::reserve(buf, bufsize);
|
|
|
|
let mut done = false;
|
|
|
|
let mut ok = true;
|
|
|
|
while !done {
|
2012-07-24 14:35:34 -05:00
|
|
|
do vec::as_mut_buf(buf) |b, _sz| {
|
2012-06-04 19:26:17 -05:00
|
|
|
let nread = libc::fread(b as *mut c_void, 1u as size_t,
|
|
|
|
bufsize as size_t,
|
|
|
|
istream);
|
2012-04-02 16:07:07 -05:00
|
|
|
if nread > 0 as size_t {
|
2012-06-04 19:26:17 -05:00
|
|
|
if libc::fwrite(b as *c_void, 1u as size_t, nread,
|
|
|
|
ostream) != nread {
|
|
|
|
ok = false;
|
|
|
|
done = true;
|
|
|
|
}
|
2012-04-02 16:07:07 -05:00
|
|
|
} else {
|
2012-06-04 19:26:17 -05:00
|
|
|
done = true;
|
2012-04-02 16:07:07 -05:00
|
|
|
}
|
2012-06-04 19:26:17 -05:00
|
|
|
}
|
2012-04-02 16:07:07 -05:00
|
|
|
}
|
|
|
|
fclose(istream);
|
|
|
|
fclose(ostream);
|
2012-08-01 19:30:05 -05:00
|
|
|
return ok;
|
2012-04-02 16:07:07 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/// Deletes an existing file
|
2012-08-14 15:38:35 -05:00
|
|
|
fn remove_file(p: Path) -> bool {
|
2012-08-01 19:30:05 -05:00
|
|
|
return unlink(p);
|
2012-03-05 15:20:57 -06:00
|
|
|
|
2012-06-07 23:38:25 -05:00
|
|
|
#[cfg(windows)]
|
2012-08-14 15:38:35 -05:00
|
|
|
fn unlink(p: Path) -> bool {
|
2012-06-21 18:44:10 -05:00
|
|
|
// FIXME (similar to Issue #2006): remove imports when export globs
|
|
|
|
// work properly.
|
2012-03-06 20:49:08 -06:00
|
|
|
import libc::funcs::extra::kernel32::*;
|
2012-03-05 15:20:57 -06:00
|
|
|
import libc::types::os::arch::extra::*;
|
2012-03-06 20:49:08 -06:00
|
|
|
import win32::*;
|
2012-08-01 19:30:05 -05:00
|
|
|
return do as_utf16_p(p) |buf| {
|
2012-03-06 20:49:08 -06:00
|
|
|
DeleteFileW(buf) != (0 as BOOL)
|
2012-03-05 15:20:57 -06:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2012-06-07 23:38:25 -05:00
|
|
|
#[cfg(unix)]
|
2012-08-14 15:38:35 -05:00
|
|
|
fn unlink(p: Path) -> bool {
|
2012-08-01 19:30:05 -05:00
|
|
|
return do as_c_charp(p) |buf| {
|
2012-03-05 15:20:57 -06:00
|
|
|
libc::unlink(buf) == (0 as c_int)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/// Get a string representing the platform-dependent last error
|
2012-07-14 00:57:48 -05:00
|
|
|
fn last_os_error() -> ~str {
|
2012-04-19 03:23:00 -05:00
|
|
|
rustrt::last_os_error()
|
|
|
|
}
|
2012-03-02 19:20:00 -06:00
|
|
|
|
2012-07-04 16:53:12 -05:00
|
|
|
/**
|
|
|
|
* Sets the process exit code
|
|
|
|
*
|
|
|
|
* Sets the exit code returned by the process if all supervised tasks
|
|
|
|
* terminate successfully (without failing). If the current root task fails
|
|
|
|
* and is supervised by the scheduler then any user-specified exit status is
|
|
|
|
* ignored and the process exits with the default failure status
|
|
|
|
*/
|
2012-04-19 03:26:17 -05:00
|
|
|
fn set_exit_status(code: int) {
|
|
|
|
rustrt::rust_set_exit_status(code as libc::intptr_t);
|
|
|
|
}
|
2012-03-02 19:20:00 -06:00
|
|
|
|
2012-06-07 23:38:25 -05:00
|
|
|
#[cfg(unix)]
|
2012-07-14 00:57:48 -05:00
|
|
|
fn family() -> ~str { ~"unix" }
|
2012-06-06 23:39:41 -05:00
|
|
|
|
2012-06-07 23:38:25 -05:00
|
|
|
#[cfg(windows)]
|
2012-07-14 12:05:49 -05:00
|
|
|
fn family() -> ~str { ~"windows" }
|
2012-06-06 23:39:41 -05:00
|
|
|
|
2012-03-02 19:20:00 -06:00
|
|
|
#[cfg(target_os = "macos")]
|
|
|
|
mod consts {
|
2012-07-14 12:05:49 -05:00
|
|
|
fn sysname() -> ~str { ~"macos" }
|
|
|
|
fn exe_suffix() -> ~str { ~"" }
|
|
|
|
fn dll_suffix() -> ~str { ~".dylib" }
|
2012-03-02 19:20:00 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(target_os = "freebsd")]
|
|
|
|
mod consts {
|
2012-07-14 12:05:49 -05:00
|
|
|
fn sysname() -> ~str { ~"freebsd" }
|
|
|
|
fn exe_suffix() -> ~str { ~"" }
|
|
|
|
fn dll_suffix() -> ~str { ~".so" }
|
2012-03-02 19:20:00 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(target_os = "linux")]
|
|
|
|
mod consts {
|
2012-07-14 00:57:48 -05:00
|
|
|
fn sysname() -> ~str { ~"linux" }
|
|
|
|
fn exe_suffix() -> ~str { ~"" }
|
|
|
|
fn dll_suffix() -> ~str { ~".so" }
|
2012-03-02 19:20:00 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(target_os = "win32")]
|
|
|
|
mod consts {
|
2012-07-14 12:05:49 -05:00
|
|
|
fn sysname() -> ~str { ~"win32" }
|
|
|
|
fn exe_suffix() -> ~str { ~".exe" }
|
|
|
|
fn dll_suffix() -> ~str { ~".dll" }
|
2012-03-02 19:20:00 -06:00
|
|
|
}
|
|
|
|
|
2012-04-27 03:36:22 -05:00
|
|
|
#[cfg(target_arch = "x86")]
|
2012-07-14 12:05:49 -05:00
|
|
|
fn arch() -> ~str { ~"x86" }
|
2012-03-02 19:20:00 -06:00
|
|
|
|
2012-04-27 03:36:22 -05:00
|
|
|
#[cfg(target_arch = "x86_64")]
|
2012-07-14 00:57:48 -05:00
|
|
|
fn arch() -> ~str { ~"x86_64" }
|
2012-03-02 19:20:00 -06:00
|
|
|
|
2012-04-27 03:36:22 -05:00
|
|
|
#[cfg(target_arch = "arm")]
|
2012-07-14 12:05:49 -05:00
|
|
|
fn arch() -> str { ~"arm" }
|
2012-03-02 19:20:00 -06:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
|
2012-04-19 03:23:00 -05:00
|
|
|
#[test]
|
|
|
|
fn last_os_error() {
|
|
|
|
log(debug, last_os_error());
|
|
|
|
}
|
2012-03-12 22:04:27 -05:00
|
|
|
|
2012-07-14 00:57:48 -05:00
|
|
|
fn make_rand_name() -> ~str {
|
2012-03-12 22:04:27 -05:00
|
|
|
import rand;
|
2012-08-14 15:38:35 -05:00
|
|
|
let rng: rand::Rng = rand::rng();
|
2012-07-14 00:57:48 -05:00
|
|
|
let n = ~"TEST" + rng.gen_str(10u);
|
2012-03-12 22:04:27 -05:00
|
|
|
assert option::is_none(getenv(n));
|
|
|
|
n
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_setenv() {
|
|
|
|
let n = make_rand_name();
|
2012-07-14 00:57:48 -05:00
|
|
|
setenv(n, ~"VALUE");
|
|
|
|
assert getenv(n) == option::some(~"VALUE");
|
2012-03-12 22:04:27 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2012-06-07 23:38:25 -05:00
|
|
|
#[ignore(cfg(windows))]
|
|
|
|
#[ignore]
|
2012-03-12 22:04:27 -05:00
|
|
|
fn test_setenv_overwrite() {
|
|
|
|
let n = make_rand_name();
|
2012-07-14 00:57:48 -05:00
|
|
|
setenv(n, ~"1");
|
|
|
|
setenv(n, ~"2");
|
|
|
|
assert getenv(n) == option::some(~"2");
|
|
|
|
setenv(n, ~"");
|
|
|
|
assert getenv(n) == option::some(~"");
|
2012-03-12 22:04:27 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Windows GetEnvironmentVariable requires some extra work to make sure
|
|
|
|
// the buffer the variable is copied into is the right size
|
|
|
|
#[test]
|
2012-06-07 23:38:25 -05:00
|
|
|
#[ignore(cfg(windows))]
|
|
|
|
#[ignore]
|
2012-03-12 22:04:27 -05:00
|
|
|
fn test_getenv_big() {
|
2012-07-14 00:57:48 -05:00
|
|
|
let mut s = ~"";
|
2012-03-22 10:39:41 -05:00
|
|
|
let mut i = 0;
|
2012-07-14 00:57:48 -05:00
|
|
|
while i < 100 { s += ~"aaaaaaaaaa"; i += 1; }
|
2012-03-12 22:04:27 -05:00
|
|
|
let n = make_rand_name();
|
|
|
|
setenv(n, s);
|
|
|
|
log(debug, s);
|
|
|
|
assert getenv(n) == option::some(s);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_self_exe_path() {
|
|
|
|
let path = os::self_exe_path();
|
|
|
|
assert option::is_some(path);
|
|
|
|
let path = option::get(path);
|
|
|
|
log(debug, path);
|
|
|
|
|
|
|
|
// Hard to test this function
|
2012-07-14 00:57:48 -05:00
|
|
|
if os::sysname() != ~"win32" {
|
2012-03-12 22:04:27 -05:00
|
|
|
assert str::starts_with(path, path::path_sep());
|
|
|
|
} else {
|
|
|
|
assert path[1] == ':' as u8;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2012-04-06 13:36:43 -05:00
|
|
|
#[ignore]
|
2012-03-12 22:04:27 -05:00
|
|
|
fn test_env_getenv() {
|
|
|
|
let e = env();
|
|
|
|
assert vec::len(e) > 0u;
|
2012-06-30 18:19:07 -05:00
|
|
|
for vec::each(e) |p| {
|
2012-03-27 08:14:12 -05:00
|
|
|
let (n, v) = p;
|
2012-03-12 22:04:27 -05:00
|
|
|
log(debug, n);
|
|
|
|
let v2 = getenv(n);
|
|
|
|
// MingW seems to set some funky environment variables like
|
|
|
|
// "=C:=C:\MinGW\msys\1.0\bin" and "!::=::\" that are returned
|
|
|
|
// from env() but not visible from getenv().
|
|
|
|
assert option::is_none(v2) || v2 == option::some(v);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_env_setenv() {
|
|
|
|
let n = make_rand_name();
|
|
|
|
|
2012-03-22 10:39:41 -05:00
|
|
|
let mut e = env();
|
2012-07-14 00:57:48 -05:00
|
|
|
setenv(n, ~"VALUE");
|
|
|
|
assert !vec::contains(e, (n, ~"VALUE"));
|
2012-03-12 22:04:27 -05:00
|
|
|
|
|
|
|
e = env();
|
2012-07-14 00:57:48 -05:00
|
|
|
assert vec::contains(e, (n, ~"VALUE"));
|
2012-03-12 22:04:27 -05:00
|
|
|
}
|
|
|
|
|
2012-03-02 19:20:00 -06:00
|
|
|
#[test]
|
|
|
|
fn test() {
|
2012-07-14 00:57:48 -05:00
|
|
|
assert (!path::path_is_absolute(~"test-path"));
|
2012-03-02 19:20:00 -06:00
|
|
|
|
2012-07-14 00:57:48 -05:00
|
|
|
log(debug, ~"Current working directory: " + getcwd());
|
2012-03-02 19:20:00 -06:00
|
|
|
|
2012-07-14 00:57:48 -05:00
|
|
|
log(debug, make_absolute(~"test-path"));
|
|
|
|
log(debug, make_absolute(~"/usr/bin"));
|
2012-03-02 19:20:00 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2012-06-07 23:38:25 -05:00
|
|
|
#[cfg(unix)]
|
2012-03-02 19:20:00 -06:00
|
|
|
fn homedir() {
|
2012-07-14 00:57:48 -05:00
|
|
|
let oldhome = getenv(~"HOME");
|
2012-03-02 19:20:00 -06:00
|
|
|
|
2012-07-14 00:57:48 -05:00
|
|
|
setenv(~"HOME", ~"/home/MountainView");
|
|
|
|
assert os::homedir() == some(~"/home/MountainView");
|
2012-03-02 19:20:00 -06:00
|
|
|
|
2012-07-14 00:57:48 -05:00
|
|
|
setenv(~"HOME", ~"");
|
2012-03-02 19:20:00 -06:00
|
|
|
assert os::homedir() == none;
|
|
|
|
|
2012-07-14 00:57:48 -05:00
|
|
|
option::iter(oldhome, |s| setenv(~"HOME", s));
|
2012-03-02 19:20:00 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2012-06-07 23:38:25 -05:00
|
|
|
#[cfg(windows)]
|
2012-03-02 19:20:00 -06:00
|
|
|
fn homedir() {
|
|
|
|
|
2012-07-14 13:05:10 -05:00
|
|
|
let oldhome = getenv(~"HOME");
|
|
|
|
let olduserprofile = getenv(~"USERPROFILE");
|
2012-03-02 19:20:00 -06:00
|
|
|
|
2012-07-14 13:05:10 -05:00
|
|
|
setenv(~"HOME", ~"");
|
|
|
|
setenv(~"USERPROFILE", ~"");
|
2012-03-02 19:20:00 -06:00
|
|
|
|
|
|
|
assert os::homedir() == none;
|
|
|
|
|
2012-07-14 13:05:10 -05:00
|
|
|
setenv(~"HOME", ~"/home/MountainView");
|
|
|
|
assert os::homedir() == some(~"/home/MountainView");
|
2012-03-02 19:20:00 -06:00
|
|
|
|
2012-07-14 13:05:10 -05:00
|
|
|
setenv(~"HOME", ~"");
|
2012-03-02 19:20:00 -06:00
|
|
|
|
2012-07-14 13:05:10 -05:00
|
|
|
setenv(~"USERPROFILE", ~"/home/MountainView");
|
|
|
|
assert os::homedir() == some(~"/home/MountainView");
|
2012-03-02 19:20:00 -06:00
|
|
|
|
2012-07-14 13:05:10 -05:00
|
|
|
setenv(~"USERPROFILE", ~"/home/MountainView");
|
|
|
|
assert os::homedir() == some(~"/home/MountainView");
|
2012-03-02 19:20:00 -06:00
|
|
|
|
2012-07-14 13:05:10 -05:00
|
|
|
setenv(~"HOME", ~"/home/MountainView");
|
|
|
|
setenv(~"USERPROFILE", ~"/home/PaloAlto");
|
|
|
|
assert os::homedir() == some(~"/home/MountainView");
|
2012-03-02 19:20:00 -06:00
|
|
|
|
2012-07-14 13:05:10 -05:00
|
|
|
option::iter(oldhome, |s| setenv(~"HOME", s));
|
2012-04-06 14:14:09 -05:00
|
|
|
option::iter(olduserprofile,
|
2012-07-14 13:05:10 -05:00
|
|
|
|s| setenv(~"USERPROFILE", s));
|
2012-03-02 19:20:00 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
// Issue #712
|
|
|
|
#[test]
|
2012-07-14 00:57:48 -05:00
|
|
|
fn test_list_dir_no_invalid_memory_access() { os::list_dir(~"."); }
|
2012-03-02 19:20:00 -06:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn list_dir() {
|
2012-07-14 00:57:48 -05:00
|
|
|
let dirs = os::list_dir(~".");
|
2012-03-02 19:20:00 -06:00
|
|
|
// Just assuming that we've got some contents in the current directory
|
|
|
|
assert (vec::len(dirs) > 0u);
|
|
|
|
|
2012-06-30 18:19:07 -05:00
|
|
|
for vec::each(dirs) |dir| { log(debug, dir); }
|
2012-03-02 19:20:00 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn path_is_dir() {
|
2012-07-14 00:57:48 -05:00
|
|
|
assert (os::path_is_dir(~"."));
|
|
|
|
assert (!os::path_is_dir(~"test/stdtest/fs.rs"));
|
2012-03-02 19:20:00 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn path_exists() {
|
2012-07-14 00:57:48 -05:00
|
|
|
assert (os::path_exists(~"."));
|
|
|
|
assert (!os::path_exists(~"test/nonexistent-bogus-path"));
|
2012-03-02 19:20:00 -06:00
|
|
|
}
|
|
|
|
|
2012-04-02 16:07:07 -05:00
|
|
|
#[test]
|
|
|
|
fn copy_file_does_not_exist() {
|
2012-07-14 00:57:48 -05:00
|
|
|
assert !os::copy_file(~"test/nonexistent-bogus-path",
|
|
|
|
~"test/other-bogus-path");
|
|
|
|
assert !os::path_exists(~"test/other-bogus-path");
|
2012-04-02 16:07:07 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn copy_file_ok() {
|
|
|
|
let tempdir = getcwd(); // would like to use $TMPDIR,
|
|
|
|
// doesn't seem to work on Linux
|
|
|
|
assert (str::len(tempdir) > 0u);
|
2012-07-14 00:57:48 -05:00
|
|
|
let in = tempdir + path::path_sep() + ~"in.txt";
|
|
|
|
let out = tempdir + path::path_sep() + ~"out.txt";
|
2012-04-02 16:07:07 -05:00
|
|
|
|
|
|
|
/* Write the temp input file */
|
2012-06-30 18:19:07 -05:00
|
|
|
let ostream = do as_c_charp(in) |fromp| {
|
2012-07-14 00:57:48 -05:00
|
|
|
do as_c_charp(~"w+b") |modebuf| {
|
2012-04-02 16:07:07 -05:00
|
|
|
libc::fopen(fromp, modebuf)
|
|
|
|
}
|
|
|
|
};
|
|
|
|
assert (ostream as uint != 0u);
|
2012-07-14 00:57:48 -05:00
|
|
|
let s = ~"hello";
|
2012-06-29 18:26:56 -05:00
|
|
|
let mut buf = vec::to_mut(str::bytes(s) + ~[0 as u8]);
|
2012-07-24 14:35:34 -05:00
|
|
|
do vec::as_mut_buf(buf) |b, _len| {
|
2012-06-04 19:26:17 -05:00
|
|
|
assert (libc::fwrite(b as *c_void, 1u as size_t,
|
|
|
|
(str::len(s) + 1u) as size_t, ostream)
|
|
|
|
== buf.len() as size_t)};
|
2012-04-02 16:07:07 -05:00
|
|
|
assert (libc::fclose(ostream) == (0u as c_int));
|
|
|
|
let rs = os::copy_file(in, out);
|
|
|
|
if (!os::path_exists(in)) {
|
2012-07-30 18:01:07 -05:00
|
|
|
fail (fmt!{"%s doesn't exist", in});
|
2012-04-02 16:07:07 -05:00
|
|
|
}
|
|
|
|
assert(rs);
|
2012-07-14 00:57:48 -05:00
|
|
|
let rslt = run::run_program(~"diff", ~[in, out]);
|
2012-04-02 16:07:07 -05:00
|
|
|
assert (rslt == 0);
|
|
|
|
assert (remove_file(in));
|
|
|
|
assert (remove_file(out));
|
|
|
|
}
|
2012-04-01 10:39:17 -05:00
|
|
|
}
|