about summary refs log tree commit diff
path: root/src/libnative
diff options
context:
space:
mode:
authorAlan Williams <mralert@gmail.com>2014-05-07 11:06:15 -0700
committerAlan Williams <mralert@gmail.com>2014-05-07 11:20:28 -0700
commitfacd1270c636beb7c2c8153424ffd6dda4179d59 (patch)
treeb29d80f2b9677297d62fee4cccd2b1274ff4b921 /src/libnative
parent8543e1b6ced6547057a07f43c413193deb3f9cb1 (diff)
downloadrust-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.rs93
-rw-r--r--src/libnative/io/file_win32.rs4
-rw-r--r--src/libnative/lib.rs1
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