diff options
| author | Alan Williams <mralert@gmail.com> | 2014-05-07 11:06:15 -0700 |
|---|---|---|
| committer | Alan Williams <mralert@gmail.com> | 2014-05-07 11:20:28 -0700 |
| commit | facd1270c636beb7c2c8153424ffd6dda4179d59 (patch) | |
| tree | b29d80f2b9677297d62fee4cccd2b1274ff4b921 /src/libnative | |
| parent | 8543e1b6ced6547057a07f43c413193deb3f9cb1 (diff) | |
| download | rust-facd1270c636beb7c2c8153424ffd6dda4179d59.tar.gz rust-facd1270c636beb7c2c8153424ffd6dda4179d59.zip | |
Move Windows compatibility layer to libnative
Diffstat (limited to 'src/libnative')
| -rw-r--r-- | src/libnative/io/c_win32.rs | 93 | ||||
| -rw-r--r-- | src/libnative/io/file_win32.rs | 4 | ||||
| -rw-r--r-- | src/libnative/lib.rs | 1 |
3 files changed, 96 insertions, 2 deletions
diff --git a/src/libnative/io/c_win32.rs b/src/libnative/io/c_win32.rs index 6c84424e97a..382746decd2 100644 --- a/src/libnative/io/c_win32.rs +++ b/src/libnative/io/c_win32.rs @@ -62,3 +62,96 @@ extern "system" { pub fn CancelIo(hFile: libc::HANDLE) -> libc::BOOL; } + +pub mod compat { + use std::intrinsics::{atomic_store_relaxed, transmute}; + use libc::types::os::arch::extra::{LPCWSTR, HMODULE, LPCSTR, LPVOID}; + use std::os::win32::as_utf16_p; + + extern "system" { + fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE; + fn GetProcAddress(hModule: HMODULE, lpProcName: LPCSTR) -> LPVOID; + } + + // store_func() is idempotent, so using relaxed ordering for the atomics should be enough. + // This way, calling a function in this compatibility layer (after it's loaded) shouldn't + // be any slower than a regular DLL call. + unsafe fn store_func<T: Copy>(ptr: *mut T, module: &str, symbol: &str, fallback: T) { + as_utf16_p(module, |module| { + symbol.with_c_str(|symbol| { + let handle = GetModuleHandleW(module); + let func: Option<T> = transmute(GetProcAddress(handle, symbol)); + atomic_store_relaxed(ptr, func.unwrap_or(fallback)) + }) + }) + } + + /// Macro for creating a compatibility fallback for a Windows function + /// + /// # Example + /// ``` + /// compat_fn!(adll32::SomeFunctionW(_arg: LPCWSTR) { + /// // Fallback implementation + /// }) + /// ``` + /// + /// Note that arguments unused by the fallback implementation should not be called `_` as + /// they are used to be passed to the real function if available. + macro_rules! compat_fn( + ($module:ident::$symbol:ident($($argname:ident: $argtype:ty),*) + -> $rettype:ty $fallback:block) => ( + #[inline(always)] + pub unsafe fn $symbol($($argname: $argtype),*) -> $rettype { + static mut ptr: extern "system" fn($($argname: $argtype),*) -> $rettype = thunk; + + extern "system" fn thunk($($argname: $argtype),*) -> $rettype { + unsafe { + ::io::c::compat::store_func(&mut ptr, + stringify!($module), + stringify!($symbol), + fallback); + ::std::intrinsics::atomic_load_relaxed(&ptr)($($argname),*) + } + } + + extern "system" fn fallback($($argname: $argtype),*) -> $rettype $fallback + + ::std::intrinsics::atomic_load_relaxed(&ptr)($($argname),*) + } + ); + + ($module:ident::$symbol:ident($($argname:ident: $argtype:ty),*) $fallback:block) => ( + compat_fn!($module::$symbol($($argname: $argtype),*) -> () $fallback) + ) + ) + + /// Compatibility layer for functions in `kernel32.dll` + /// + /// Latest versions of Windows this is needed for: + /// + /// * `CreateSymbolicLinkW`: Windows XP, Windows Server 2003 + /// * `GetFinalPathNameByHandleW`: Windows XP, Windows Server 2003 + pub mod kernel32 { + use libc::types::os::arch::extra::{DWORD, LPCWSTR, BOOLEAN, HANDLE}; + use libc::consts::os::extra::ERROR_CALL_NOT_IMPLEMENTED; + + extern "system" { + fn SetLastError(dwErrCode: DWORD); + } + + compat_fn!(kernel32::CreateSymbolicLinkW(_lpSymlinkFileName: LPCWSTR, + _lpTargetFileName: LPCWSTR, + _dwFlags: DWORD) -> BOOLEAN { + unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); } + 0 + }) + + compat_fn!(kernel32::GetFinalPathNameByHandleW(_hFile: HANDLE, + _lpszFilePath: LPCWSTR, + _cchFilePath: DWORD, + _dwFlags: DWORD) -> DWORD { + unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); } + 0 + }) + } +} diff --git a/src/libnative/io/file_win32.rs b/src/libnative/io/file_win32.rs index ea105b267c1..1c69392165d 100644 --- a/src/libnative/io/file_win32.rs +++ b/src/libnative/io/file_win32.rs @@ -408,7 +408,7 @@ pub fn chown(_p: &CString, _uid: int, _gid: int) -> IoResult<()> { pub fn readlink(p: &CString) -> IoResult<Path> { // FIXME: I have a feeling that this reads intermediate symlinks as well. - use std::os::win32::compat::kernel32::GetFinalPathNameByHandleW; + use io::c::compat::kernel32::GetFinalPathNameByHandleW; let handle = unsafe { as_utf16_p(p.as_str().unwrap(), |p| { libc::CreateFileW(p, @@ -441,7 +441,7 @@ pub fn readlink(p: &CString) -> IoResult<Path> { } pub fn symlink(src: &CString, dst: &CString) -> IoResult<()> { - use std::os::win32::compat::kernel32::CreateSymbolicLinkW; + use io::c::compat::kernel32::CreateSymbolicLinkW; super::mkerr_winbool(as_utf16_p(src.as_str().unwrap(), |src| { as_utf16_p(dst.as_str().unwrap(), |dst| { unsafe { CreateSymbolicLinkW(dst, src, 0) } diff --git a/src/libnative/lib.rs b/src/libnative/lib.rs index 4c0c4dcc18e..6309e4df40e 100644 --- a/src/libnative/lib.rs +++ b/src/libnative/lib.rs @@ -50,6 +50,7 @@ html_root_url = "http://static.rust-lang.org/doc/master")] #![deny(unused_result, unused_must_use)] #![allow(non_camel_case_types)] +#![feature(macro_rules)] // NB this crate explicitly does *not* allow glob imports, please seriously // consider whether they're needed before adding that feature here (the |
