about summary refs log tree commit diff
path: root/src
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
parent1f25c8b78d1192aea69ee9779f512eb9ee78e575 (diff)
downloadrust-073d7ffc2745386f42048847ec7209e47cbdab8f.tar.gz
rust-073d7ffc2745386f42048847ec7209e47cbdab8f.zip
Implement fallbacks for functions unavailable in older versions of Windows
Diffstat (limited to 'src')
-rw-r--r--src/liblibc/lib.rs15
-rw-r--r--src/libnative/io/file_win32.rs12
-rw-r--r--src/libstd/os.rs78
3 files changed, 89 insertions, 16 deletions
diff --git a/src/liblibc/lib.rs b/src/liblibc/lib.rs
index a4593c1cb5a..e96ddfbf7bd 100644
--- a/src/liblibc/lib.rs
+++ b/src/liblibc/lib.rs
@@ -250,7 +250,6 @@ pub use funcs::bsd43::{shutdown};
 #[cfg(windows)] pub use funcs::extra::kernel32::{FlushFileBuffers, SetEndOfFile, CreateFileW};
 #[cfg(windows)] pub use funcs::extra::kernel32::{CreateDirectoryW, FindFirstFileW};
 #[cfg(windows)] pub use funcs::extra::kernel32::{FindNextFileW, FindClose, DeleteFileW};
-#[cfg(windows)] pub use funcs::extra::kernel32::{GetFinalPathNameByHandleW, CreateSymbolicLinkW};
 #[cfg(windows)] pub use funcs::extra::kernel32::{CreateHardLinkW, CreateEventW};
 #[cfg(windows)] pub use funcs::extra::kernel32::{FlushFileBuffers, CreateNamedPipeW};
 #[cfg(windows)] pub use funcs::extra::kernel32::{SetNamedPipeHandleState, WaitNamedPipeW};
@@ -1733,6 +1732,7 @@ pub mod consts {
             pub static ERROR_INVALID_HANDLE : c_int = 6;
             pub static ERROR_BROKEN_PIPE: c_int = 109;
             pub static ERROR_DISK_FULL : c_int = 112;
+            pub static ERROR_CALL_NOT_IMPLEMENTED : c_int = 120;
             pub static ERROR_INSUFFICIENT_BUFFER : c_int = 122;
             pub static ERROR_INVALID_NAME : c_int = 123;
             pub static ERROR_ALREADY_EXISTS : c_int = 183;
@@ -4185,9 +4185,9 @@ pub mod funcs {
                                                LPSTARTUPINFO,
                                                LPPROCESS_INFORMATION,
                                                LPMEMORY_BASIC_INFORMATION,
-                                               LPSYSTEM_INFO, BOOLEAN,
-                                               HANDLE, LPHANDLE, LARGE_INTEGER,
-                                               PLARGE_INTEGER, LPFILETIME};
+                                               LPSYSTEM_INFO, HANDLE, LPHANDLE,
+                                               LARGE_INTEGER, PLARGE_INTEGER,
+                                               LPFILETIME};
 
             extern "system" {
                 pub fn GetEnvironmentVariableW(n: LPCWSTR,
@@ -4297,9 +4297,6 @@ pub mod funcs {
                 pub fn MoveFileExW(lpExistingFileName: LPCWSTR,
                                    lpNewFileName: LPCWSTR,
                                    dwFlags: DWORD) -> BOOL;
-                pub fn CreateSymbolicLinkW(lpSymlinkFileName: LPCWSTR,
-                                           lpTargetFileName: LPCWSTR,
-                                           dwFlags: DWORD) -> BOOLEAN;
                 pub fn CreateHardLinkW(lpSymlinkFileName: LPCWSTR,
                                        lpTargetFileName: LPCWSTR,
                                        lpSecurityAttributes: LPSECURITY_ATTRIBUTES)
@@ -4312,10 +4309,6 @@ pub mod funcs {
                                    dwCreationDisposition: DWORD,
                                    dwFlagsAndAttributes: DWORD,
                                    hTemplateFile: HANDLE) -> HANDLE;
-                pub fn GetFinalPathNameByHandleW(hFile: HANDLE,
-                                                 lpszFilePath: LPCWSTR,
-                                                 cchFilePath: DWORD,
-                                                 dwFlags: DWORD) -> DWORD;
                 pub fn ReadFile(hFile: HANDLE,
                                 lpBuffer: LPVOID,
                                 nNumberOfBytesToRead: DWORD,
diff --git a/src/libnative/io/file_win32.rs b/src/libnative/io/file_win32.rs
index 6a6fb31d3e3..ea105b267c1 100644
--- a/src/libnative/io/file_win32.rs
+++ b/src/libnative/io/file_win32.rs
@@ -408,6 +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;
     let handle = unsafe {
         as_utf16_p(p.as_str().unwrap(), |p| {
             libc::CreateFileW(p,
@@ -425,10 +426,10 @@ pub fn readlink(p: &CString) -> IoResult<Path> {
     // Specify (sz - 1) because the documentation states that it's the size
     // without the null pointer
     let ret = fill_utf16_buf_and_decode(|buf, sz| unsafe {
-        libc::GetFinalPathNameByHandleW(handle,
-                                        buf as *u16,
-                                        sz - 1,
-                                        libc::VOLUME_NAME_DOS)
+        GetFinalPathNameByHandleW(handle,
+                                  buf as *u16,
+                                  sz - 1,
+                                  libc::VOLUME_NAME_DOS)
     });
     let ret = match ret {
         Some(ref s) if s.starts_with(r"\\?\") => Ok(Path::new(s.slice_from(4))),
@@ -440,9 +441,10 @@ pub fn readlink(p: &CString) -> IoResult<Path> {
 }
 
 pub fn symlink(src: &CString, dst: &CString) -> IoResult<()> {
+    use std::os::win32::compat::kernel32::CreateSymbolicLinkW;
     super::mkerr_winbool(as_utf16_p(src.as_str().unwrap(), |src| {
         as_utf16_p(dst.as_str().unwrap(), |dst| {
-            unsafe { libc::CreateSymbolicLinkW(dst, src, 0) }
+            unsafe { CreateSymbolicLinkW(dst, src, 0) }
         }) as libc::BOOL
     }))
 }
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
+            })
+        }
+    }
 }
 
 /*