forked from Rust-related/RustPython
partially fix sys.getwindowsversion() (#5595)
This commit is contained in:
@@ -81,7 +81,7 @@ if sys.platform.startswith("win"):
|
|||||||
0x00000100 | 0x00000001 | 0x00000020 | 0x00002000 | 0x00000010 | 0x00008000 | 0x00020000
|
0x00000100 | 0x00000001 | 0x00000020 | 0x00002000 | 0x00000010 | 0x00008000 | 0x00020000
|
||||||
|
|
||||||
# We really can't test if the results are correct, so it just checks for meaningful value
|
# We really can't test if the results are correct, so it just checks for meaningful value
|
||||||
assert winver.major > 0
|
assert winver.major > 6
|
||||||
assert winver.minor >= 0
|
assert winver.minor >= 0
|
||||||
assert winver.build > 0
|
assert winver.build > 0
|
||||||
assert winver.platform == 2
|
assert winver.platform == 2
|
||||||
@@ -91,8 +91,8 @@ if sys.platform.startswith("win"):
|
|||||||
|
|
||||||
# XXX if platform_version is implemented correctly, this'll break on compatiblity mode or a build without manifest
|
# XXX if platform_version is implemented correctly, this'll break on compatiblity mode or a build without manifest
|
||||||
# these fields can mismatch in CPython
|
# these fields can mismatch in CPython
|
||||||
# assert winver.major == winver.platform_version[0]
|
assert winver.major == winver.platform_version[0]
|
||||||
# assert winver.minor == winver.platform_version[1]
|
assert winver.minor == winver.platform_version[1]
|
||||||
# assert winver.build == winver.platform_version[2]
|
# assert winver.build == winver.platform_version[2]
|
||||||
|
|
||||||
# test int_max_str_digits getter and setter
|
# test int_max_str_digits getter and setter
|
||||||
|
|||||||
@@ -22,12 +22,23 @@ mod sys {
|
|||||||
vm::{Settings, VirtualMachine},
|
vm::{Settings, VirtualMachine},
|
||||||
};
|
};
|
||||||
use num_traits::ToPrimitive;
|
use num_traits::ToPrimitive;
|
||||||
|
#[cfg(windows)]
|
||||||
|
use std::os::windows::ffi::OsStrExt;
|
||||||
use std::{
|
use std::{
|
||||||
env::{self, VarError},
|
env::{self, VarError},
|
||||||
path,
|
path,
|
||||||
sync::atomic::Ordering,
|
sync::atomic::Ordering,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
use windows_sys::Win32::{
|
||||||
|
Foundation::MAX_PATH,
|
||||||
|
Storage::FileSystem::{
|
||||||
|
GetFileVersionInfoSizeW, GetFileVersionInfoW, VS_FIXEDFILEINFO, VerQueryValueW,
|
||||||
|
},
|
||||||
|
System::LibraryLoader::{GetModuleFileNameW, GetModuleHandleW},
|
||||||
|
};
|
||||||
|
|
||||||
// not the same as CPython (e.g. rust's x86_x64-unknown-linux-gnu is just x86_64-linux-gnu)
|
// not the same as CPython (e.g. rust's x86_x64-unknown-linux-gnu is just x86_64-linux-gnu)
|
||||||
// but hopefully that's just an implementation detail? TODO: copy CPython's multiarch exactly,
|
// but hopefully that's just an implementation detail? TODO: copy CPython's multiarch exactly,
|
||||||
// https://github.com/python/cpython/blob/3.8/configure.ac#L725
|
// https://github.com/python/cpython/blob/3.8/configure.ac#L725
|
||||||
@@ -485,6 +496,78 @@ mod sys {
|
|||||||
vm.trace_func.borrow().clone()
|
vm.trace_func.borrow().clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
fn get_kernel32_version() -> std::io::Result<(u32, u32, u32)> {
|
||||||
|
unsafe {
|
||||||
|
// Create a wide string for "kernel32.dll"
|
||||||
|
let module_name: Vec<u16> = std::ffi::OsStr::new("kernel32.dll")
|
||||||
|
.encode_wide()
|
||||||
|
.chain(Some(0))
|
||||||
|
.collect();
|
||||||
|
let h_kernel32 = GetModuleHandleW(module_name.as_ptr());
|
||||||
|
if h_kernel32.is_null() {
|
||||||
|
return Err(std::io::Error::last_os_error());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare a buffer for the module file path
|
||||||
|
let mut kernel32_path = [0u16; MAX_PATH as usize];
|
||||||
|
let len = GetModuleFileNameW(
|
||||||
|
h_kernel32,
|
||||||
|
kernel32_path.as_mut_ptr(),
|
||||||
|
kernel32_path.len() as u32,
|
||||||
|
);
|
||||||
|
if len == 0 {
|
||||||
|
return Err(std::io::Error::last_os_error());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the size of the version information block
|
||||||
|
let verblock_size =
|
||||||
|
GetFileVersionInfoSizeW(kernel32_path.as_ptr(), std::ptr::null_mut());
|
||||||
|
if verblock_size == 0 {
|
||||||
|
return Err(std::io::Error::last_os_error());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate a buffer to hold the version information
|
||||||
|
let mut verblock = vec![0u8; verblock_size as usize];
|
||||||
|
if GetFileVersionInfoW(
|
||||||
|
kernel32_path.as_ptr(),
|
||||||
|
0,
|
||||||
|
verblock_size,
|
||||||
|
verblock.as_mut_ptr() as *mut _,
|
||||||
|
) == 0
|
||||||
|
{
|
||||||
|
return Err(std::io::Error::last_os_error());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare an empty sub-block string (L"") as required by VerQueryValueW
|
||||||
|
let sub_block: Vec<u16> = std::ffi::OsStr::new("")
|
||||||
|
.encode_wide()
|
||||||
|
.chain(Some(0))
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let mut ffi_ptr: *mut VS_FIXEDFILEINFO = std::ptr::null_mut();
|
||||||
|
let mut ffi_len: u32 = 0;
|
||||||
|
if VerQueryValueW(
|
||||||
|
verblock.as_ptr() as *const _,
|
||||||
|
sub_block.as_ptr(),
|
||||||
|
&mut ffi_ptr as *mut *mut VS_FIXEDFILEINFO as *mut *mut _,
|
||||||
|
&mut ffi_len as *mut u32,
|
||||||
|
) == 0
|
||||||
|
|| ffi_ptr.is_null()
|
||||||
|
{
|
||||||
|
return Err(std::io::Error::last_os_error());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract the version numbers from the VS_FIXEDFILEINFO structure.
|
||||||
|
let ffi = *ffi_ptr;
|
||||||
|
let real_major = (ffi.dwProductVersionMS >> 16) & 0xFFFF;
|
||||||
|
let real_minor = ffi.dwProductVersionMS & 0xFFFF;
|
||||||
|
let real_build = (ffi.dwProductVersionLS >> 16) & 0xFFFF;
|
||||||
|
|
||||||
|
Ok((real_major, real_minor, real_build))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
#[pyfunction]
|
#[pyfunction]
|
||||||
fn getwindowsversion(vm: &VirtualMachine) -> PyResult<crate::builtins::tuple::PyTupleRef> {
|
fn getwindowsversion(vm: &VirtualMachine) -> PyResult<crate::builtins::tuple::PyTupleRef> {
|
||||||
@@ -519,21 +602,18 @@ mod sys {
|
|||||||
sp.into_string()
|
sp.into_string()
|
||||||
.map_err(|_| vm.new_os_error("service pack is not ASCII".to_owned()))?
|
.map_err(|_| vm.new_os_error("service pack is not ASCII".to_owned()))?
|
||||||
};
|
};
|
||||||
|
let real_version = get_kernel32_version().map_err(|e| vm.new_os_error(e.to_string()))?;
|
||||||
Ok(WindowsVersion {
|
Ok(WindowsVersion {
|
||||||
major: version.dwMajorVersion,
|
major: real_version.0,
|
||||||
minor: version.dwMinorVersion,
|
minor: real_version.1,
|
||||||
build: version.dwBuildNumber,
|
build: real_version.2,
|
||||||
platform: version.dwPlatformId,
|
platform: version.dwPlatformId,
|
||||||
service_pack,
|
service_pack,
|
||||||
service_pack_major: version.wServicePackMajor,
|
service_pack_major: version.wServicePackMajor,
|
||||||
service_pack_minor: version.wServicePackMinor,
|
service_pack_minor: version.wServicePackMinor,
|
||||||
suite_mask: version.wSuiteMask,
|
suite_mask: version.wSuiteMask,
|
||||||
product_type: version.wProductType,
|
product_type: version.wProductType,
|
||||||
platform_version: (
|
platform_version: (real_version.0, real_version.1, real_version.2), // TODO Provide accurate version, like CPython impl
|
||||||
version.dwMajorVersion,
|
|
||||||
version.dwMinorVersion,
|
|
||||||
version.dwBuildNumber,
|
|
||||||
), // TODO Provide accurate version, like CPython impl
|
|
||||||
}
|
}
|
||||||
.into_struct_sequence(vm))
|
.into_struct_sequence(vm))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user