Skip to content

Continue work on #4812 #5322

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 9 commits into from
1 change: 1 addition & 0 deletions src/libcore/core.rc
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ Implicitly, all crates behave as if they included the following prologue:
#[cfg(target_os = "linux")]
pub mod linkhack {
#[link_args="-lrustrt -lrt"]
#[link_args = "-lpthread"]
extern {
}
}
Expand Down
38 changes: 36 additions & 2 deletions src/libcore/libc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,8 @@ pub mod types {

pub type LPCWSTR = *WCHAR;
pub type LPCSTR = *CHAR;
pub type LPCTSTR = *CHAR;
pub type LPTCH = *CHAR;

pub type LPWSTR = *mut WCHAR;
pub type LPSTR = *mut CHAR;
Expand Down Expand Up @@ -792,6 +794,7 @@ pub mod consts {

pub const ERROR_SUCCESS : int = 0;
pub const ERROR_INSUFFICIENT_BUFFER : int = 122;
pub const INVALID_HANDLE_VALUE: int = -1;
}
}

Expand Down Expand Up @@ -1115,6 +1118,7 @@ pub mod funcs {
pub mod string {
use libc::types::common::c95::c_void;
use libc::types::os::arch::c95::{c_char, c_int, size_t};
use libc::types::os::arch::c95::{wchar_t};

pub extern {
unsafe fn strcpy(dst: *c_char, src: *c_char) -> *c_char;
Expand All @@ -1138,6 +1142,7 @@ pub mod funcs {
unsafe fn strtok(s: *c_char, t: *c_char) -> *c_char;
unsafe fn strxfrm(s: *c_char, ct: *c_char, n: size_t)
-> size_t;
unsafe fn wcslen(buf: *wchar_t) -> size_t;

// These are fine to execute on the Rust stack. They must be,
// in fact, because LLVM generates calls to them!
Expand Down Expand Up @@ -1381,9 +1386,28 @@ pub mod funcs {
use libc::types::os::arch::c95::{c_char, c_int, c_long};

pub extern {
// default bindings for opendir and readdir in
// non-macos unix
#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
#[cfg(target_os = "freebsd")]
unsafe fn opendir(dirname: *c_char) -> *DIR;
unsafe fn closedir(dirp: *DIR) -> c_int;
#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
#[cfg(target_os = "freebsd")]
unsafe fn readdir(dirp: *DIR) -> *dirent_t;
// on OSX (particularly when running with a
// 64bit kernel), we have an issue where there
// are separate bindings for opendir and readdir,
// which we have to explicitly link, as below.
#[cfg(target_os = "macos")]
#[link_name = "opendir$INODE64"]
unsafe fn opendir(dirname: *c_char) -> *DIR;
#[cfg(target_os = "macos")]
#[link_name = "readdir$INODE64"]
unsafe fn readdir(dirp: *DIR) -> *dirent_t;

unsafe fn closedir(dirp: *DIR) -> c_int;
unsafe fn rewinddir(dirp: *DIR);
unsafe fn seekdir(dirp: *DIR, loc: c_long);
unsafe fn telldir(dirp: *DIR) -> c_long;
Expand Down Expand Up @@ -1594,8 +1618,9 @@ pub mod funcs {

pub mod kernel32 {
use libc::types::os::arch::extra::{BOOL, DWORD, HMODULE};
use libc::types::os::arch::extra::{LPCWSTR, LPWSTR};
use libc::types::os::arch::extra::{LPCWSTR, LPWSTR, LPTCH};
use libc::types::os::arch::extra::{LPSECURITY_ATTRIBUTES};
use libc::types::os::arch::extra::{HANDLE};

#[abi = "stdcall"]
pub extern {
Expand All @@ -1605,6 +1630,8 @@ pub mod funcs {
-> DWORD;
unsafe fn SetEnvironmentVariableW(n: LPCWSTR, v: LPCWSTR)
-> BOOL;
unsafe fn GetEnvironmentStringsA() -> LPTCH;
unsafe fn FreeEnvironmentStringsA(env_ptr: LPTCH) -> BOOL;

unsafe fn GetModuleFileNameW(hModule: HMODULE,
lpFilename: LPWSTR,
Expand All @@ -1623,6 +1650,13 @@ pub mod funcs {
unsafe fn SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL;

unsafe fn GetLastError() -> DWORD;
unsafe fn FindFirstFileW(fileName: *u16,
findFileData: HANDLE)
-> HANDLE;
unsafe fn FindNextFileW(findFile: HANDLE,
findFileData: HANDLE)
-> BOOL;
unsafe fn FindClose(findFile: HANDLE) -> BOOL;
}
}

Expand Down
176 changes: 156 additions & 20 deletions src/libcore/os.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,20 +58,25 @@ pub mod rustrt {
pub extern {
unsafe fn rust_get_argc() -> c_int;
unsafe fn rust_get_argv() -> **c_char;
unsafe fn rust_getcwd() -> ~str;
unsafe fn rust_path_is_dir(path: *libc::c_char) -> c_int;
unsafe fn rust_path_exists(path: *libc::c_char) -> c_int;
unsafe fn rust_list_files2(&&path: ~str) -> ~[~str];
unsafe fn rust_process_wait(handle: c_int) -> c_int;
unsafe fn rust_set_exit_status(code: libc::intptr_t);
}
}

pub const TMPBUF_SZ : uint = 1000u;
const BUF_BYTES : uint = 2048u;

pub fn getcwd() -> Path {
let buf = [0 as libc::c_char, ..BUF_BYTES];
unsafe {
Path(rustrt::rust_getcwd())
if(0 as *libc::c_char == libc::getcwd(
&buf[0],
BUF_BYTES as libc::size_t)) {
fail!();
}
Path(str::raw::from_c_str(&buf[0]))
}
}

Expand Down Expand Up @@ -164,20 +169,68 @@ fn with_env_lock<T>(f: &fn() -> T) -> T {
}

pub fn env() -> ~[(~str,~str)] {
extern {
unsafe fn rust_env_pairs() -> ~[~str];
}

unsafe {
do with_env_lock {
#[cfg(windows)]
unsafe fn get_env_pairs() -> ~[~str] {
use libc::types::os::arch::extra::LPTCH;
use libc::funcs::extra::kernel32::{
GetEnvironmentStringsA,
FreeEnvironmentStringsA
};
let ch = GetEnvironmentStringsA();
if (ch as uint == 0) {
fail!(fmt!("os::env() failure getting env string from OS: %s",
os::last_os_error()));
}
let mut curr_ptr: uint = ch as uint;
let mut result = ~[];
while(*(curr_ptr as *libc::c_char) != 0 as libc::c_char) {
let env_pair = str::raw::from_c_str(
curr_ptr as *libc::c_char);
result.push(env_pair);
curr_ptr +=
libc::strlen(curr_ptr as *libc::c_char) as uint
+ 1;
}
FreeEnvironmentStringsA(ch);
result
}
#[cfg(unix)]
unsafe fn get_env_pairs() -> ~[~str] {
extern mod rustrt {
unsafe fn rust_env_pairs() -> **libc::c_char;
}
let environ = rustrt::rust_env_pairs();
if (environ as uint == 0) {
fail!(fmt!("os::env() failure getting env string from OS: %s",
os::last_os_error()));
}
let mut result = ~[];
ptr::array_each(environ, |e| {
let env_pair = str::raw::from_c_str(e);
log(debug, fmt!("get_env_pairs: %s",
env_pair));
result.push(env_pair);
});
result
}

fn env_convert(input: ~[~str]) -> ~[(~str, ~str)] {
let mut pairs = ~[];
for vec::each(rust_env_pairs()) |p| {
let vs = str::splitn_char(*p, '=', 1u);
fail_unless!(vec::len(vs) == 2u);
for input.each |p| {
let vs = str::splitn_char(*p, '=', 1);
log(debug,
fmt!("splitting: len: %u",
vs.len()));
fail_unless!(vs.len() == 2);
pairs.push((copy vs[0], copy vs[1]));
}
pairs
}
do with_env_lock {
let unparsed_environ = get_env_pairs();
env_convert(unparsed_environ)
}
}
}

Expand Down Expand Up @@ -615,13 +668,97 @@ pub fn make_dir(p: &Path, mode: c_int) -> bool {
#[allow(non_implicitly_copyable_typarams)]
pub fn list_dir(p: &Path) -> ~[~str] {
unsafe {
#[cfg(unix)]
fn star(p: &Path) -> Path { copy *p }

#[cfg(target_os = "linux")]
#[cfg(target_os = "android")]
#[cfg(target_os = "freebsd")]
#[cfg(target_os = "macos")]
unsafe fn get_list(p: &Path) -> ~[~str] {
use libc::{DIR, dirent_t};
use libc::{opendir, readdir, closedir};
extern mod rustrt {
unsafe fn rust_list_dir_val(ptr: *dirent_t)
-> *libc::c_char;
}
let input = p.to_str();
let mut strings = ~[];
let input_ptr = ::cast::transmute(&input[0]);
log(debug, "os::list_dir -- BEFORE OPENDIR");
let dir_ptr = opendir(input_ptr);
if (dir_ptr as uint != 0) {
log(debug, "os::list_dir -- opendir() SUCCESS");
let mut entry_ptr = readdir(dir_ptr);
while (entry_ptr as uint != 0) {
strings.push(
str::raw::from_c_str(
rustrt::rust_list_dir_val(
entry_ptr)));
entry_ptr = readdir(dir_ptr);
}
closedir(dir_ptr);
}
else {
log(debug, "os::list_dir -- opendir() FAILURE");
}
log(debug,
fmt!("os::list_dir -- AFTER -- #: %?",
strings.len()));
strings
}
#[cfg(windows)]
fn star(p: &Path) -> Path { p.push("*") }

do rustrt::rust_list_files2(star(p).to_str()).filtered |filename| {
unsafe fn get_list(p: &Path) -> ~[~str] {
use libc::types::os::arch::extra::{LPCTSTR, HANDLE, BOOL};
use libc::consts::os::extra::INVALID_HANDLE_VALUE;
use libc::wcslen;
use libc::funcs::extra::kernel32::{
FindFirstFileW,
FindNextFileW,
FindClose,
};
use os::win32::{
as_utf16_p
};
use unstable::exchange_alloc::{malloc_raw, free_raw};
#[nolink]
extern mod rustrt {
unsafe fn rust_list_dir_wfd_size() -> libc::size_t;
unsafe fn rust_list_dir_wfd_fp_buf(wfd: *libc::c_void)
-> *u16;
}
fn star(p: &Path) -> Path { p.push("*") }
do as_utf16_p(star(p).to_str()) |path_ptr| {
let mut strings = ~[];
let wfd_ptr = malloc_raw(
rustrt::rust_list_dir_wfd_size() as uint);
let find_handle =
FindFirstFileW(
path_ptr,
::cast::transmute(wfd_ptr));
if find_handle as int != INVALID_HANDLE_VALUE {
let mut more_files = 1 as libc::c_int;
while more_files != 0 {
let fp_buf = rustrt::rust_list_dir_wfd_fp_buf(
wfd_ptr);
if fp_buf as uint == 0 {
fail!(~"os::list_dir() failure:"+
~" got null ptr from wfd");
}
else {
let fp_vec = vec::from_buf(
fp_buf, wcslen(fp_buf) as uint);
let fp_str = str::from_utf16(fp_vec);
strings.push(fp_str);
}
more_files = FindNextFileW(
find_handle,
::cast::transmute(wfd_ptr));
}
FindClose(find_handle);
free_raw(wfd_ptr);
}
strings
}
}
do get_list(p).filtered |filename| {
*filename != ~"." && *filename != ~".."
}
}
Expand Down Expand Up @@ -1274,9 +1411,8 @@ mod tests {
setenv(~"USERPROFILE", ~"/home/PaloAlto");
fail_unless!(os::homedir() == Some(Path("/home/MountainView")));

option::iter(&oldhome, |s| setenv(~"HOME", *s));
option::iter(&olduserprofile,
|s| setenv(~"USERPROFILE", *s));
oldhome.each(|s| {setenv(~"HOME", *s);true});
olduserprofile.each(|s| {setenv(~"USERPROFILE", *s);true});
}

#[test]
Expand Down
Loading