2014-05-30 11:07:16 -05:00
|
|
|
// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
|
2013-06-09 01:29:32 -05:00
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2014-11-25 20:17:11 -06:00
|
|
|
//! Dynamic library facilities.
|
|
|
|
//!
|
|
|
|
//! A simple wrapper over the platform's dynamic library facilities
|
2014-04-29 13:38:51 -05:00
|
|
|
|
2015-01-22 20:22:03 -06:00
|
|
|
#![unstable(feature = "std_misc")]
|
2014-10-27 17:37:07 -05:00
|
|
|
#![allow(missing_docs)]
|
2014-06-08 22:12:10 -05:00
|
|
|
|
2014-12-22 11:04:23 -06:00
|
|
|
use prelude::v1::*;
|
|
|
|
|
2014-11-25 15:28:35 -06:00
|
|
|
use ffi::CString;
|
core: Remove the cast module
This commit revisits the `cast` module in libcore and libstd, and scrutinizes
all functions inside of it. The result was to remove the `cast` module entirely,
folding all functionality into the `mem` module. Specifically, this is the fate
of each function in the `cast` module.
* transmute - This function was moved to `mem`, but it is now marked as
#[unstable]. This is due to planned changes to the `transmute`
function and how it can be invoked (see the #[unstable] comment).
For more information, see RFC 5 and #12898
* transmute_copy - This function was moved to `mem`, with clarification that is
is not an error to invoke it with T/U that are different
sizes, but rather that it is strongly discouraged. This
function is now #[stable]
* forget - This function was moved to `mem` and marked #[stable]
* bump_box_refcount - This function was removed due to the deprecation of
managed boxes as well as its questionable utility.
* transmute_mut - This function was previously deprecated, and removed as part
of this commit.
* transmute_mut_unsafe - This function doesn't serve much of a purpose when it
can be achieved with an `as` in safe code, so it was
removed.
* transmute_lifetime - This function was removed because it is likely a strong
indication that code is incorrect in the first place.
* transmute_mut_lifetime - This function was removed for the same reasons as
`transmute_lifetime`
* copy_lifetime - This function was moved to `mem`, but it is marked
`#[unstable]` now due to the likelihood of being removed in
the future if it is found to not be very useful.
* copy_mut_lifetime - This function was also moved to `mem`, but had the same
treatment as `copy_lifetime`.
* copy_lifetime_vec - This function was removed because it is not used today,
and its existence is not necessary with DST
(copy_lifetime will suffice).
In summary, the cast module was stripped down to these functions, and then the
functions were moved to the `mem` module.
transmute - #[unstable]
transmute_copy - #[stable]
forget - #[stable]
copy_lifetime - #[unstable]
copy_mut_lifetime - #[unstable]
[breaking-change]
2014-05-09 12:34:51 -05:00
|
|
|
use mem;
|
2014-04-29 13:38:51 -05:00
|
|
|
use os;
|
|
|
|
use str;
|
2013-06-09 01:29:32 -05:00
|
|
|
|
librustc: Make `Copy` opt-in.
This change makes the compiler no longer infer whether types (structures
and enumerations) implement the `Copy` trait (and thus are implicitly
copyable). Rather, you must implement `Copy` yourself via `impl Copy for
MyType {}`.
A new warning has been added, `missing_copy_implementations`, to warn
you if a non-generic public type has been added that could have
implemented `Copy` but didn't.
For convenience, you may *temporarily* opt out of this behavior by using
`#![feature(opt_out_copy)]`. Note though that this feature gate will never be
accepted and will be removed by the time that 1.0 is released, so you should
transition your code away from using it.
This breaks code like:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
Change this code to:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
impl Copy for Point2D {}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
This is the backwards-incompatible part of #13231.
Part of RFC #3.
[breaking-change]
2014-12-05 19:01:33 -06:00
|
|
|
#[allow(missing_copy_implementations)]
|
|
|
|
pub struct DynamicLibrary {
|
|
|
|
handle: *mut u8
|
|
|
|
}
|
2013-06-09 01:29:32 -05:00
|
|
|
|
|
|
|
impl Drop for DynamicLibrary {
|
2013-09-16 20:18:07 -05:00
|
|
|
fn drop(&mut self) {
|
2013-11-20 16:17:12 -06:00
|
|
|
match dl::check_for_errors_in(|| {
|
2013-06-09 01:29:32 -05:00
|
|
|
unsafe {
|
|
|
|
dl::close(self.handle)
|
|
|
|
}
|
2013-11-20 16:17:12 -06:00
|
|
|
}) {
|
2013-08-01 16:58:37 -05:00
|
|
|
Ok(()) => {},
|
2014-10-09 14:17:22 -05:00
|
|
|
Err(str) => panic!("{}", str)
|
2013-06-09 01:29:32 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl DynamicLibrary {
|
2014-05-05 16:53:57 -05:00
|
|
|
// FIXME (#12938): Until DST lands, we cannot decompose &str into
|
|
|
|
// & and str, so we cannot usefully take ToCStr arguments by
|
|
|
|
// reference (without forcing an additional & around &str). So we
|
|
|
|
// are instead temporarily adding an instance for &Path, so that
|
|
|
|
// we can take ToCStr as owned. When DST lands, the &Path instance
|
|
|
|
// should be removed, and arguments bound by ToCStr should be
|
|
|
|
// passed by reference. (Here: in the `open` method.)
|
|
|
|
|
2013-06-09 01:29:32 -05:00
|
|
|
/// Lazily open a dynamic library. When passed None it gives a
|
|
|
|
/// handle to the calling process
|
2014-11-25 15:28:35 -06:00
|
|
|
pub fn open(filename: Option<&Path>) -> Result<DynamicLibrary, String> {
|
2015-01-10 07:53:22 -06:00
|
|
|
let maybe_library = dl::open(filename.map(|path| path.as_vec()));
|
|
|
|
|
|
|
|
// The dynamic library must not be constructed if there is
|
|
|
|
// an error opening the library so the destructor does not
|
|
|
|
// run.
|
|
|
|
match maybe_library {
|
|
|
|
Err(err) => Err(err),
|
|
|
|
Ok(handle) => Ok(DynamicLibrary { handle: handle })
|
2013-06-09 01:29:32 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-15 12:28:46 -05:00
|
|
|
/// Prepends a path to this process's search path for dynamic libraries
|
|
|
|
pub fn prepend_search_path(path: &Path) {
|
|
|
|
let mut search_path = DynamicLibrary::search_path();
|
|
|
|
search_path.insert(0, path.clone());
|
|
|
|
let newval = DynamicLibrary::create_path(search_path.as_slice());
|
|
|
|
os::setenv(DynamicLibrary::envvar(),
|
|
|
|
str::from_utf8(newval.as_slice()).unwrap());
|
|
|
|
}
|
|
|
|
|
|
|
|
/// From a slice of paths, create a new vector which is suitable to be an
|
|
|
|
/// environment variable for this platforms dylib search path.
|
|
|
|
pub fn create_path(path: &[Path]) -> Vec<u8> {
|
|
|
|
let mut newvar = Vec::new();
|
|
|
|
for (i, path) in path.iter().enumerate() {
|
|
|
|
if i > 0 { newvar.push(DynamicLibrary::separator()); }
|
|
|
|
newvar.push_all(path.as_vec());
|
|
|
|
}
|
|
|
|
return newvar;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the environment variable for this process's dynamic library
|
|
|
|
/// search path
|
|
|
|
pub fn envvar() -> &'static str {
|
|
|
|
if cfg!(windows) {
|
|
|
|
"PATH"
|
2014-04-29 13:38:51 -05:00
|
|
|
} else if cfg!(target_os = "macos") {
|
2014-05-15 12:28:46 -05:00
|
|
|
"DYLD_LIBRARY_PATH"
|
2014-04-29 13:38:51 -05:00
|
|
|
} else {
|
2014-05-15 12:28:46 -05:00
|
|
|
"LD_LIBRARY_PATH"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn separator() -> u8 {
|
2014-08-06 01:02:50 -05:00
|
|
|
if cfg!(windows) {b';'} else {b':'}
|
2014-05-15 12:28:46 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the current search path for dynamic libraries being used by this
|
|
|
|
/// process
|
|
|
|
pub fn search_path() -> Vec<Path> {
|
|
|
|
let mut ret = Vec::new();
|
|
|
|
match os::getenv_as_bytes(DynamicLibrary::envvar()) {
|
|
|
|
Some(env) => {
|
2014-05-20 01:19:56 -05:00
|
|
|
for portion in
|
|
|
|
env.as_slice()
|
|
|
|
.split(|a| *a == DynamicLibrary::separator()) {
|
2014-05-15 12:28:46 -05:00
|
|
|
ret.push(Path::new(portion));
|
|
|
|
}
|
|
|
|
}
|
2014-05-08 08:33:22 -05:00
|
|
|
None => {}
|
|
|
|
}
|
2014-05-15 12:28:46 -05:00
|
|
|
return ret;
|
2014-04-29 13:38:51 -05:00
|
|
|
}
|
|
|
|
|
2013-06-09 01:29:32 -05:00
|
|
|
/// Access the value at the symbol of the dynamic library
|
2014-06-25 14:47:34 -05:00
|
|
|
pub unsafe fn symbol<T>(&self, symbol: &str) -> Result<*mut T, String> {
|
2013-12-10 01:16:18 -06:00
|
|
|
// This function should have a lifetime constraint of 'a on
|
2013-06-09 01:29:32 -05:00
|
|
|
// T but that feature is still unimplemented
|
|
|
|
|
2015-01-05 21:13:38 -06:00
|
|
|
let raw_string = CString::from_slice(symbol.as_bytes());
|
2013-11-20 16:17:12 -06:00
|
|
|
let maybe_symbol_value = dl::check_for_errors_in(|| {
|
2014-11-25 15:28:35 -06:00
|
|
|
dl::symbol(self.handle, raw_string.as_ptr())
|
2013-11-20 16:17:12 -06:00
|
|
|
});
|
2013-06-09 01:29:32 -05:00
|
|
|
|
2013-08-01 16:58:37 -05:00
|
|
|
// The value must not be constructed if there is an error so
|
|
|
|
// the destructor does not run.
|
|
|
|
match maybe_symbol_value {
|
|
|
|
Err(err) => Err(err),
|
core: Remove the cast module
This commit revisits the `cast` module in libcore and libstd, and scrutinizes
all functions inside of it. The result was to remove the `cast` module entirely,
folding all functionality into the `mem` module. Specifically, this is the fate
of each function in the `cast` module.
* transmute - This function was moved to `mem`, but it is now marked as
#[unstable]. This is due to planned changes to the `transmute`
function and how it can be invoked (see the #[unstable] comment).
For more information, see RFC 5 and #12898
* transmute_copy - This function was moved to `mem`, with clarification that is
is not an error to invoke it with T/U that are different
sizes, but rather that it is strongly discouraged. This
function is now #[stable]
* forget - This function was moved to `mem` and marked #[stable]
* bump_box_refcount - This function was removed due to the deprecation of
managed boxes as well as its questionable utility.
* transmute_mut - This function was previously deprecated, and removed as part
of this commit.
* transmute_mut_unsafe - This function doesn't serve much of a purpose when it
can be achieved with an `as` in safe code, so it was
removed.
* transmute_lifetime - This function was removed because it is likely a strong
indication that code is incorrect in the first place.
* transmute_mut_lifetime - This function was removed for the same reasons as
`transmute_lifetime`
* copy_lifetime - This function was moved to `mem`, but it is marked
`#[unstable]` now due to the likelihood of being removed in
the future if it is found to not be very useful.
* copy_mut_lifetime - This function was also moved to `mem`, but had the same
treatment as `copy_lifetime`.
* copy_lifetime_vec - This function was removed because it is not used today,
and its existence is not necessary with DST
(copy_lifetime will suffice).
In summary, the cast module was stripped down to these functions, and then the
functions were moved to the `mem` module.
transmute - #[unstable]
transmute_copy - #[stable]
forget - #[stable]
copy_lifetime - #[unstable]
copy_mut_lifetime - #[unstable]
[breaking-change]
2014-05-09 12:34:51 -05:00
|
|
|
Ok(symbol_value) => Ok(mem::transmute(symbol_value))
|
2013-06-09 01:29:32 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-29 00:31:50 -05:00
|
|
|
#[cfg(all(test, not(target_os = "ios")))]
|
2013-08-01 16:58:37 -05:00
|
|
|
mod test {
|
|
|
|
use super::*;
|
2014-12-22 11:04:23 -06:00
|
|
|
use prelude::v1::*;
|
2013-08-01 16:58:37 -05:00
|
|
|
use libc;
|
2014-06-12 23:34:32 -05:00
|
|
|
use mem;
|
2013-08-01 16:58:37 -05:00
|
|
|
|
|
|
|
#[test]
|
2014-08-03 19:41:58 -05:00
|
|
|
#[cfg_attr(any(windows, target_os = "android"), ignore)] // FIXME #8818, #10379
|
2013-08-01 16:58:37 -05:00
|
|
|
fn test_loading_cosine() {
|
|
|
|
// The math library does not need to be loaded since it is already
|
|
|
|
// statically linked in
|
2014-11-25 15:28:35 -06:00
|
|
|
let none: Option<&Path> = None; // appease the typechecker
|
2014-05-05 16:53:57 -05:00
|
|
|
let libm = match DynamicLibrary::open(none) {
|
2014-10-09 14:17:22 -05:00
|
|
|
Err(error) => panic!("Could not load self as module: {}", error),
|
2013-08-01 16:58:37 -05:00
|
|
|
Ok(libm) => libm
|
|
|
|
};
|
|
|
|
|
|
|
|
let cosine: extern fn(libc::c_double) -> libc::c_double = unsafe {
|
|
|
|
match libm.symbol("cos") {
|
2014-10-09 14:17:22 -05:00
|
|
|
Err(error) => panic!("Could not load function cos: {}", error),
|
2014-06-25 14:47:34 -05:00
|
|
|
Ok(cosine) => mem::transmute::<*mut u8, _>(cosine)
|
2013-08-01 16:58:37 -05:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
let argument = 0.0;
|
|
|
|
let expected_result = 1.0;
|
|
|
|
let result = cosine(argument);
|
|
|
|
if result != expected_result {
|
2014-10-09 14:17:22 -05:00
|
|
|
panic!("cos({}) != {} but equaled {} instead", argument,
|
2013-10-03 23:34:35 -05:00
|
|
|
expected_result, result)
|
2013-08-01 16:58:37 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
2014-09-29 00:31:50 -05:00
|
|
|
#[cfg(any(target_os = "linux",
|
|
|
|
target_os = "macos",
|
|
|
|
target_os = "freebsd",
|
|
|
|
target_os = "dragonfly"))]
|
2013-08-01 16:58:37 -05:00
|
|
|
fn test_errors_do_not_crash() {
|
|
|
|
// Open /dev/null as a library to get an error, and make sure
|
|
|
|
// that only causes an error, and not a crash.
|
2014-05-05 16:53:57 -05:00
|
|
|
let path = Path::new("/dev/null");
|
2013-08-01 16:58:37 -05:00
|
|
|
match DynamicLibrary::open(Some(&path)) {
|
|
|
|
Err(_) => {}
|
2014-10-09 14:17:22 -05:00
|
|
|
Ok(_) => panic!("Successfully opened the empty library.")
|
2013-06-09 01:29:32 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-29 00:31:50 -05:00
|
|
|
#[cfg(any(target_os = "linux",
|
|
|
|
target_os = "android",
|
|
|
|
target_os = "macos",
|
|
|
|
target_os = "ios",
|
|
|
|
target_os = "freebsd",
|
|
|
|
target_os = "dragonfly"))]
|
2015-01-10 07:53:22 -06:00
|
|
|
mod dl {
|
2014-12-22 11:04:23 -06:00
|
|
|
use prelude::v1::*;
|
2014-11-25 15:28:35 -06:00
|
|
|
|
|
|
|
use ffi::{self, CString};
|
|
|
|
use str;
|
2013-06-09 01:29:32 -05:00
|
|
|
use libc;
|
|
|
|
use ptr;
|
|
|
|
|
2015-01-10 07:53:22 -06:00
|
|
|
pub fn open(filename: Option<&[u8]>) -> Result<*mut u8, String> {
|
|
|
|
check_for_errors_in(|| {
|
|
|
|
unsafe {
|
|
|
|
match filename {
|
|
|
|
Some(filename) => open_external(filename),
|
|
|
|
None => open_internal(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
const LAZY: libc::c_int = 1;
|
|
|
|
|
|
|
|
unsafe fn open_external(filename: &[u8]) -> *mut u8 {
|
2014-11-25 15:28:35 -06:00
|
|
|
let s = CString::from_slice(filename);
|
2015-01-10 07:53:22 -06:00
|
|
|
dlopen(s.as_ptr(), LAZY) as *mut u8
|
2013-06-15 03:10:49 -05:00
|
|
|
}
|
|
|
|
|
2015-01-10 07:53:22 -06:00
|
|
|
unsafe fn open_internal() -> *mut u8 {
|
|
|
|
dlopen(ptr::null(), LAZY) as *mut u8
|
2013-06-09 01:29:32 -05:00
|
|
|
}
|
|
|
|
|
2014-12-07 13:15:25 -06:00
|
|
|
pub fn check_for_errors_in<T, F>(f: F) -> Result<T, String> where
|
|
|
|
F: FnOnce() -> T,
|
|
|
|
{
|
2014-11-24 13:16:40 -06:00
|
|
|
use sync::{StaticMutex, MUTEX_INIT};
|
|
|
|
static LOCK: StaticMutex = MUTEX_INIT;
|
2013-06-09 01:29:32 -05:00
|
|
|
unsafe {
|
2013-10-03 23:34:35 -05:00
|
|
|
// dlerror isn't thread safe, so we need to lock around this entire
|
2013-12-12 19:27:37 -06:00
|
|
|
// sequence
|
2014-10-10 23:59:10 -05:00
|
|
|
let _guard = LOCK.lock();
|
2013-12-05 19:34:37 -06:00
|
|
|
let _old_error = dlerror();
|
|
|
|
|
|
|
|
let result = f();
|
|
|
|
|
2014-06-25 14:47:34 -05:00
|
|
|
let last_error = dlerror() as *const _;
|
2013-12-05 19:34:37 -06:00
|
|
|
let ret = if ptr::null() == last_error {
|
|
|
|
Ok(result)
|
|
|
|
} else {
|
2014-11-25 15:28:35 -06:00
|
|
|
let s = ffi::c_str_to_bytes(&last_error);
|
|
|
|
Err(str::from_utf8(s).unwrap().to_string())
|
2013-12-05 19:34:37 -06:00
|
|
|
};
|
2014-02-13 00:17:50 -06:00
|
|
|
|
2013-12-05 19:34:37 -06:00
|
|
|
ret
|
2013-06-09 01:29:32 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-06-25 14:47:34 -05:00
|
|
|
pub unsafe fn symbol(handle: *mut u8,
|
|
|
|
symbol: *const libc::c_char) -> *mut u8 {
|
|
|
|
dlsym(handle as *mut libc::c_void, symbol) as *mut u8
|
2013-06-09 01:29:32 -05:00
|
|
|
}
|
2014-06-25 14:47:34 -05:00
|
|
|
pub unsafe fn close(handle: *mut u8) {
|
|
|
|
dlclose(handle as *mut libc::c_void); ()
|
2013-06-09 01:29:32 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[link_name = "dl"]
|
|
|
|
extern {
|
2014-06-25 14:47:34 -05:00
|
|
|
fn dlopen(filename: *const libc::c_char,
|
|
|
|
flag: libc::c_int) -> *mut libc::c_void;
|
|
|
|
fn dlerror() -> *mut libc::c_char;
|
|
|
|
fn dlsym(handle: *mut libc::c_void,
|
|
|
|
symbol: *const libc::c_char) -> *mut libc::c_void;
|
|
|
|
fn dlclose(handle: *mut libc::c_void) -> libc::c_int;
|
2013-06-09 01:29:32 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-10 23:26:45 -05:00
|
|
|
#[cfg(target_os = "windows")]
|
2015-01-10 07:53:22 -06:00
|
|
|
mod dl {
|
2014-11-06 11:32:37 -06:00
|
|
|
use iter::IteratorExt;
|
2013-06-09 01:29:32 -05:00
|
|
|
use libc;
|
2015-01-10 07:53:22 -06:00
|
|
|
use libc::consts::os::extra::ERROR_CALL_NOT_IMPLEMENTED;
|
2014-12-13 14:09:33 -06:00
|
|
|
use ops::FnOnce;
|
2014-01-06 21:05:53 -06:00
|
|
|
use os;
|
2015-01-10 07:53:22 -06:00
|
|
|
use option::Option::{self, Some, None};
|
2013-06-15 03:10:49 -05:00
|
|
|
use ptr;
|
2014-11-28 10:57:41 -06:00
|
|
|
use result::Result;
|
|
|
|
use result::Result::{Ok, Err};
|
2014-12-11 11:44:17 -06:00
|
|
|
use slice::SliceExt;
|
2014-12-10 21:46:38 -06:00
|
|
|
use str::StrExt;
|
2014-05-05 16:53:57 -05:00
|
|
|
use str;
|
2014-06-02 16:51:58 -05:00
|
|
|
use string::String;
|
2014-05-31 06:02:29 -05:00
|
|
|
use vec::Vec;
|
2015-01-10 07:53:22 -06:00
|
|
|
use sys::c::compat::kernel32::SetThreadErrorMode;
|
|
|
|
|
|
|
|
pub fn open(filename: Option<&[u8]>) -> Result<*mut u8, String> {
|
|
|
|
// disable "dll load failed" error dialog.
|
|
|
|
let mut use_thread_mode = true;
|
|
|
|
let prev_error_mode = unsafe {
|
|
|
|
// SEM_FAILCRITICALERRORS 0x01
|
|
|
|
let new_error_mode = 1;
|
|
|
|
let mut prev_error_mode = 0;
|
|
|
|
// Windows >= 7 supports thread error mode.
|
|
|
|
let result = SetThreadErrorMode(new_error_mode, &mut prev_error_mode);
|
|
|
|
if result == 0 {
|
|
|
|
let err = os::errno();
|
|
|
|
if err as libc::c_int == ERROR_CALL_NOT_IMPLEMENTED {
|
|
|
|
use_thread_mode = false;
|
|
|
|
// SetThreadErrorMode not found. use fallback solution: SetErrorMode()
|
|
|
|
// Note that SetErrorMode is process-wide so this can cause race condition!
|
|
|
|
// However, since even Windows APIs do not care of such problem (#20650),
|
|
|
|
// we just assume SetErrorMode race is not a great deal.
|
|
|
|
prev_error_mode = SetErrorMode(new_error_mode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
prev_error_mode
|
|
|
|
};
|
2013-06-09 01:29:32 -05:00
|
|
|
|
2015-01-10 07:53:22 -06:00
|
|
|
unsafe {
|
|
|
|
SetLastError(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
let result = match filename {
|
|
|
|
Some(filename) => {
|
|
|
|
let filename_str = str::from_utf8(filename).unwrap();
|
|
|
|
let mut filename_str: Vec<u16> = filename_str.utf16_units().collect();
|
|
|
|
filename_str.push(0);
|
|
|
|
let result = unsafe {
|
|
|
|
LoadLibraryW(filename_str.as_ptr() as *const libc::c_void)
|
|
|
|
};
|
|
|
|
// beware: Vec/String may change errno during drop!
|
|
|
|
// so we get error here.
|
|
|
|
if result == ptr::null_mut() {
|
|
|
|
let errno = os::errno();
|
|
|
|
Err(os::error_string(errno))
|
|
|
|
} else {
|
|
|
|
Ok(result as *mut u8)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
None => {
|
|
|
|
let mut handle = ptr::null_mut();
|
|
|
|
let succeeded = unsafe {
|
|
|
|
GetModuleHandleExW(0 as libc::DWORD, ptr::null(), &mut handle)
|
|
|
|
};
|
|
|
|
if succeeded == libc::FALSE {
|
|
|
|
let errno = os::errno();
|
|
|
|
Err(os::error_string(errno))
|
|
|
|
} else {
|
|
|
|
Ok(handle as *mut u8)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
if use_thread_mode {
|
|
|
|
SetThreadErrorMode(prev_error_mode, ptr::null_mut());
|
|
|
|
} else {
|
|
|
|
SetErrorMode(prev_error_mode);
|
|
|
|
}
|
|
|
|
}
|
2013-06-15 03:10:49 -05:00
|
|
|
|
2015-01-10 07:53:22 -06:00
|
|
|
result
|
2013-06-09 01:29:32 -05:00
|
|
|
}
|
|
|
|
|
2014-12-07 13:15:25 -06:00
|
|
|
pub fn check_for_errors_in<T, F>(f: F) -> Result<T, String> where
|
|
|
|
F: FnOnce() -> T,
|
|
|
|
{
|
2013-06-09 01:29:32 -05:00
|
|
|
unsafe {
|
2013-12-05 19:34:37 -06:00
|
|
|
SetLastError(0);
|
2013-06-09 01:29:32 -05:00
|
|
|
|
2013-12-05 19:34:37 -06:00
|
|
|
let result = f();
|
2013-06-09 01:29:32 -05:00
|
|
|
|
2013-12-05 19:34:37 -06:00
|
|
|
let error = os::errno();
|
|
|
|
if 0 == error {
|
|
|
|
Ok(result)
|
|
|
|
} else {
|
|
|
|
Err(format!("Error code {}", error))
|
|
|
|
}
|
2013-06-09 01:29:32 -05:00
|
|
|
}
|
|
|
|
}
|
2013-10-03 23:34:35 -05:00
|
|
|
|
2014-06-25 14:47:34 -05:00
|
|
|
pub unsafe fn symbol(handle: *mut u8, symbol: *const libc::c_char) -> *mut u8 {
|
|
|
|
GetProcAddress(handle as *mut libc::c_void, symbol) as *mut u8
|
2013-06-09 01:29:32 -05:00
|
|
|
}
|
2014-06-25 14:47:34 -05:00
|
|
|
pub unsafe fn close(handle: *mut u8) {
|
|
|
|
FreeLibrary(handle as *mut libc::c_void); ()
|
2013-06-09 01:29:32 -05:00
|
|
|
}
|
|
|
|
|
2014-07-18 07:45:17 -05:00
|
|
|
#[allow(non_snake_case)]
|
2013-11-10 16:57:53 -06:00
|
|
|
extern "system" {
|
2013-12-12 15:27:26 -06:00
|
|
|
fn SetLastError(error: libc::size_t);
|
2014-06-25 14:47:34 -05:00
|
|
|
fn LoadLibraryW(name: *const libc::c_void) -> *mut libc::c_void;
|
|
|
|
fn GetModuleHandleExW(dwFlags: libc::DWORD, name: *const u16,
|
2015-01-10 07:53:22 -06:00
|
|
|
handle: *mut *mut libc::c_void) -> libc::BOOL;
|
2014-06-25 14:47:34 -05:00
|
|
|
fn GetProcAddress(handle: *mut libc::c_void,
|
|
|
|
name: *const libc::c_char) -> *mut libc::c_void;
|
|
|
|
fn FreeLibrary(handle: *mut libc::c_void);
|
2015-01-10 07:53:22 -06:00
|
|
|
fn SetErrorMode(uMode: libc::c_uint) -> libc::c_uint;
|
2013-08-12 01:27:46 -05:00
|
|
|
}
|
2013-06-09 01:29:32 -05:00
|
|
|
}
|