Skip to content

Commit 073d7ff

Browse files
committed
Implement fallbacks for functions unavailable in older versions of Windows
1 parent 1f25c8b commit 073d7ff

File tree

3 files changed

+89
-16
lines changed

3 files changed

+89
-16
lines changed

src/liblibc/lib.rs

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,6 @@ pub use funcs::bsd43::{shutdown};
250250
#[cfg(windows)] pub use funcs::extra::kernel32::{FlushFileBuffers, SetEndOfFile, CreateFileW};
251251
#[cfg(windows)] pub use funcs::extra::kernel32::{CreateDirectoryW, FindFirstFileW};
252252
#[cfg(windows)] pub use funcs::extra::kernel32::{FindNextFileW, FindClose, DeleteFileW};
253-
#[cfg(windows)] pub use funcs::extra::kernel32::{GetFinalPathNameByHandleW, CreateSymbolicLinkW};
254253
#[cfg(windows)] pub use funcs::extra::kernel32::{CreateHardLinkW, CreateEventW};
255254
#[cfg(windows)] pub use funcs::extra::kernel32::{FlushFileBuffers, CreateNamedPipeW};
256255
#[cfg(windows)] pub use funcs::extra::kernel32::{SetNamedPipeHandleState, WaitNamedPipeW};
@@ -1733,6 +1732,7 @@ pub mod consts {
17331732
pub static ERROR_INVALID_HANDLE : c_int = 6;
17341733
pub static ERROR_BROKEN_PIPE: c_int = 109;
17351734
pub static ERROR_DISK_FULL : c_int = 112;
1735+
pub static ERROR_CALL_NOT_IMPLEMENTED : c_int = 120;
17361736
pub static ERROR_INSUFFICIENT_BUFFER : c_int = 122;
17371737
pub static ERROR_INVALID_NAME : c_int = 123;
17381738
pub static ERROR_ALREADY_EXISTS : c_int = 183;
@@ -4185,9 +4185,9 @@ pub mod funcs {
41854185
LPSTARTUPINFO,
41864186
LPPROCESS_INFORMATION,
41874187
LPMEMORY_BASIC_INFORMATION,
4188-
LPSYSTEM_INFO, BOOLEAN,
4189-
HANDLE, LPHANDLE, LARGE_INTEGER,
4190-
PLARGE_INTEGER, LPFILETIME};
4188+
LPSYSTEM_INFO, HANDLE, LPHANDLE,
4189+
LARGE_INTEGER, PLARGE_INTEGER,
4190+
LPFILETIME};
41914191

41924192
extern "system" {
41934193
pub fn GetEnvironmentVariableW(n: LPCWSTR,
@@ -4297,9 +4297,6 @@ pub mod funcs {
42974297
pub fn MoveFileExW(lpExistingFileName: LPCWSTR,
42984298
lpNewFileName: LPCWSTR,
42994299
dwFlags: DWORD) -> BOOL;
4300-
pub fn CreateSymbolicLinkW(lpSymlinkFileName: LPCWSTR,
4301-
lpTargetFileName: LPCWSTR,
4302-
dwFlags: DWORD) -> BOOLEAN;
43034300
pub fn CreateHardLinkW(lpSymlinkFileName: LPCWSTR,
43044301
lpTargetFileName: LPCWSTR,
43054302
lpSecurityAttributes: LPSECURITY_ATTRIBUTES)
@@ -4312,10 +4309,6 @@ pub mod funcs {
43124309
dwCreationDisposition: DWORD,
43134310
dwFlagsAndAttributes: DWORD,
43144311
hTemplateFile: HANDLE) -> HANDLE;
4315-
pub fn GetFinalPathNameByHandleW(hFile: HANDLE,
4316-
lpszFilePath: LPCWSTR,
4317-
cchFilePath: DWORD,
4318-
dwFlags: DWORD) -> DWORD;
43194312
pub fn ReadFile(hFile: HANDLE,
43204313
lpBuffer: LPVOID,
43214314
nNumberOfBytesToRead: DWORD,

src/libnative/io/file_win32.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,7 @@ pub fn chown(_p: &CString, _uid: int, _gid: int) -> IoResult<()> {
408408

409409
pub fn readlink(p: &CString) -> IoResult<Path> {
410410
// FIXME: I have a feeling that this reads intermediate symlinks as well.
411+
use std::os::win32::compat::kernel32::GetFinalPathNameByHandleW;
411412
let handle = unsafe {
412413
as_utf16_p(p.as_str().unwrap(), |p| {
413414
libc::CreateFileW(p,
@@ -425,10 +426,10 @@ pub fn readlink(p: &CString) -> IoResult<Path> {
425426
// Specify (sz - 1) because the documentation states that it's the size
426427
// without the null pointer
427428
let ret = fill_utf16_buf_and_decode(|buf, sz| unsafe {
428-
libc::GetFinalPathNameByHandleW(handle,
429-
buf as *u16,
430-
sz - 1,
431-
libc::VOLUME_NAME_DOS)
429+
GetFinalPathNameByHandleW(handle,
430+
buf as *u16,
431+
sz - 1,
432+
libc::VOLUME_NAME_DOS)
432433
});
433434
let ret = match ret {
434435
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> {
440441
}
441442

442443
pub fn symlink(src: &CString, dst: &CString) -> IoResult<()> {
444+
use std::os::win32::compat::kernel32::CreateSymbolicLinkW;
443445
super::mkerr_winbool(as_utf16_p(src.as_str().unwrap(), |src| {
444446
as_utf16_p(dst.as_str().unwrap(), |dst| {
445-
unsafe { libc::CreateSymbolicLinkW(dst, src, 0) }
447+
unsafe { CreateSymbolicLinkW(dst, src, 0) }
446448
}) as libc::BOOL
447449
}))
448450
}

src/libstd/os.rs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,84 @@ pub mod win32 {
145145
t.push(0u16);
146146
f(t.as_ptr())
147147
}
148+
149+
pub mod compat {
150+
use kinds::Copy;
151+
use option::Option;
152+
use c_str::ToCStr;
153+
use intrinsics::{atomic_store_relaxed, transmute};
154+
use libc::types::os::arch::extra::{LPCWSTR, HMODULE, LPCSTR, LPVOID};
155+
use os::win32::as_utf16_p;
156+
157+
#[link_name="kernel32"]
158+
extern "system" {
159+
fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE;
160+
fn GetProcAddress(hModule: HMODULE, lpProcName: LPCSTR) -> LPVOID;
161+
}
162+
163+
unsafe fn store_func<T: Copy>(ptr: *mut T, module: &str, symbol: &str, fallback: T) {
164+
as_utf16_p(module, |module| {
165+
symbol.with_c_str(|symbol| {
166+
let handle = GetModuleHandleW(module);
167+
let func: Option<T> = transmute(GetProcAddress(handle, symbol));
168+
atomic_store_relaxed(ptr, func.unwrap_or(fallback))
169+
})
170+
})
171+
}
172+
173+
macro_rules! compat_fn(
174+
($module:ident::$symbol:ident($($argname:ident: $argtype:ty),*)
175+
-> $rettype:ty $fallback:block) => (
176+
#[inline(always)]
177+
pub unsafe fn $symbol($($argname: $argtype),*) -> $rettype {
178+
static mut ptr: extern "system" fn($($argname: $argtype),*) -> $rettype = thunk;
179+
180+
extern "system" fn thunk($($argname: $argtype),*) -> $rettype {
181+
unsafe {
182+
::os::win32::compat::store_func(&mut ptr,
183+
stringify!($module),
184+
stringify!($symbol),
185+
fallback);
186+
::intrinsics::atomic_load_relaxed(&ptr)($($argname),*)
187+
}
188+
}
189+
190+
extern "system" fn fallback($($argname: $argtype),*) -> $rettype $fallback
191+
192+
::intrinsics::atomic_load_relaxed(&ptr)($($argname),*)
193+
}
194+
);
195+
196+
($module:ident::$symbol:ident($($argname:ident: $argtype:ty),*) $fallback:block) => (
197+
compat_fn!($module::$symbol($($argname: $argtype),*) -> () $fallback)
198+
)
199+
)
200+
201+
pub mod kernel32 {
202+
use libc::types::os::arch::extra::{DWORD, LPCWSTR, BOOLEAN, HANDLE};
203+
use libc::consts::os::extra::ERROR_CALL_NOT_IMPLEMENTED;
204+
205+
#[link_name="kernel32"]
206+
extern "system" {
207+
fn SetLastError(dwErrCode: DWORD);
208+
}
209+
210+
compat_fn!(kernel32::CreateSymbolicLinkW(_lpSymlinkFileName: LPCWSTR,
211+
_lpTargetFileName: LPCWSTR,
212+
_dwFlags: DWORD) -> BOOLEAN {
213+
unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); }
214+
0
215+
})
216+
217+
compat_fn!(kernel32::GetFinalPathNameByHandleW(_hFile: HANDLE,
218+
_lpszFilePath: LPCWSTR,
219+
_cchFilePath: DWORD,
220+
_dwFlags: DWORD) -> DWORD {
221+
unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); }
222+
0
223+
})
224+
}
225+
}
148226
}
149227

150228
/*

0 commit comments

Comments
 (0)