about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorAlan Williams <mralert@gmail.com>2014-05-03 14:27:36 -0700
committerAlan Williams <mralert@gmail.com>2014-05-04 02:57:54 -0700
commit073d7ffc2745386f42048847ec7209e47cbdab8f (patch)
tree92fccddce6bc9f670929d825418411439e063f9f /src/libstd
parent1f25c8b78d1192aea69ee9779f512eb9ee78e575 (diff)
downloadrust-073d7ffc2745386f42048847ec7209e47cbdab8f.tar.gz
rust-073d7ffc2745386f42048847ec7209e47cbdab8f.zip
Implement fallbacks for functions unavailable in older versions of Windows
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/os.rs78
1 files changed, 78 insertions, 0 deletions
diff --git a/src/libstd/os.rs b/src/libstd/os.rs
index 071aae974db..5152399bf7e 100644
--- a/src/libstd/os.rs
+++ b/src/libstd/os.rs
@@ -145,6 +145,84 @@ pub mod win32 {
         t.push(0u16);
         f(t.as_ptr())
     }
+
+    pub mod compat {
+        use kinds::Copy;
+        use option::Option;
+        use c_str::ToCStr;
+        use intrinsics::{atomic_store_relaxed, transmute};
+        use libc::types::os::arch::extra::{LPCWSTR, HMODULE, LPCSTR, LPVOID};
+        use os::win32::as_utf16_p;
+
+        #[link_name="kernel32"]
+        extern "system" {
+            fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE;
+            fn GetProcAddress(hModule: HMODULE, lpProcName: LPCSTR) -> LPVOID;
+        }
+
+        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_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 {
+                            ::os::win32::compat::store_func(&mut ptr,
+                                                                 stringify!($module),
+                                                                 stringify!($symbol),
+                                                                 fallback);
+                            ::intrinsics::atomic_load_relaxed(&ptr)($($argname),*)
+                        }
+                    }
+
+                    extern "system" fn fallback($($argname: $argtype),*) -> $rettype $fallback
+
+                    ::intrinsics::atomic_load_relaxed(&ptr)($($argname),*)
+                }
+            );
+
+            ($module:ident::$symbol:ident($($argname:ident: $argtype:ty),*) $fallback:block) => (
+                compat_fn!($module::$symbol($($argname: $argtype),*) -> () $fallback)
+            )
+        )
+
+        pub mod kernel32 {
+            use libc::types::os::arch::extra::{DWORD, LPCWSTR, BOOLEAN, HANDLE};
+            use libc::consts::os::extra::ERROR_CALL_NOT_IMPLEMENTED;
+
+            #[link_name="kernel32"]
+            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
+            })
+        }
+    }
 }
 
 /*