mirror of
https://github.com/velopack/velopack.git
synced 2025-10-25 15:19:22 +00:00
Use IsWow64Process2 to determine windows process architecture
This commit is contained in:
12
src/Rust/Cargo.lock
generated
12
src/Rust/Cargo.lock
generated
@@ -994,6 +994,17 @@ dependencies = [
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "os_info"
|
||||
version = "3.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ae99c7fa6dd38c7cafe1ec085e804f8f555a2f8659b0dbe03f1f9963a9b51092"
|
||||
dependencies = [
|
||||
"log",
|
||||
"serde",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "percent-encoding"
|
||||
version = "2.3.1"
|
||||
@@ -1586,6 +1597,7 @@ dependencies = [
|
||||
"native-tls",
|
||||
"normpath",
|
||||
"ntest",
|
||||
"os_info",
|
||||
"pretty-bytes-rust",
|
||||
"pretty_assertions",
|
||||
"rand",
|
||||
|
||||
@@ -78,6 +78,7 @@ url = "2.5"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
time = "0.3"
|
||||
os_info = "3.8"
|
||||
|
||||
[target.'cfg(unix)'.dependencies]
|
||||
native-dialog = "0.7"
|
||||
@@ -101,6 +102,7 @@ windows = { version = "0.52", default-features = false, features = [
|
||||
"Win32_UI",
|
||||
"Win32_UI_Shell",
|
||||
"Win32_System_Threading",
|
||||
"Win32_System_SystemInformation",
|
||||
"Win32_System_Variant",
|
||||
"Win32_Storage_EnhancedStorage",
|
||||
"Win32_Storage_FileSystem",
|
||||
@@ -123,13 +125,6 @@ windows-sys = { version = "0.52", default-features = false, features = [
|
||||
"Wdk",
|
||||
"Wdk_System",
|
||||
"Wdk_System_Threading",
|
||||
# below are just for os_info
|
||||
"Win32_UI_WindowsAndMessaging",
|
||||
"Win32_System_Diagnostics_Debug",
|
||||
"Win32_System_LibraryLoader",
|
||||
"Win32_System_SystemInformation",
|
||||
"Win32_System_Registry",
|
||||
"Win32_System_SystemServices",
|
||||
] }
|
||||
normpath = "1.0.1"
|
||||
webview2-com = "0.28.0"
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
use crate::{dialogs, shared, shared::bundle, windows};
|
||||
use crate::{
|
||||
dialogs,
|
||||
shared::{self, bundle, runtime_arch::RuntimeArch},
|
||||
windows,
|
||||
};
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use memmap2::Mmap;
|
||||
use pretty_bytes_rust::pretty_bytes;
|
||||
@@ -11,8 +15,9 @@ use std::{
|
||||
use winsafe::{self as w, co};
|
||||
|
||||
pub fn install(debug_pkg: Option<&PathBuf>, install_to: Option<&PathBuf>) -> Result<()> {
|
||||
let osinfo = windows::os_info::get();
|
||||
info!("OS: {}, Arch={}", osinfo, osinfo.architecture().unwrap_or("unknown"));
|
||||
let osinfo = os_info::get();
|
||||
let osarch = RuntimeArch::from_current_system();
|
||||
info!("OS: {osinfo}, Arch={osarch:#?}");
|
||||
|
||||
if !w::IsWindows7OrGreater()? {
|
||||
bail!("This installer requires Windows 7 or later and cannot run.");
|
||||
@@ -121,7 +126,7 @@ pub fn install(debug_pkg: Option<&PathBuf>, install_to: Option<&PathBuf>) -> Res
|
||||
let splash_bytes = pkg.get_splash_bytes();
|
||||
windows::splash::show_splash_dialog(app.title.to_owned(), splash_bytes)
|
||||
};
|
||||
|
||||
|
||||
let install_result = install_impl(&pkg, &root_path, &tx);
|
||||
let _ = tx.send(windows::splash::MSG_CLOSE);
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
pub mod bundle;
|
||||
pub mod download;
|
||||
pub mod macho;
|
||||
pub mod runtime_arch;
|
||||
|
||||
mod dialogs_const;
|
||||
mod dialogs_common;
|
||||
|
||||
102
src/Rust/src/shared/runtime_arch.rs
Normal file
102
src/Rust/src/shared/runtime_arch.rs
Normal file
@@ -0,0 +1,102 @@
|
||||
#[derive(PartialEq, Debug, Clone, strum::IntoStaticStr)]
|
||||
pub enum RuntimeArch {
|
||||
X86,
|
||||
X64,
|
||||
Arm64,
|
||||
}
|
||||
|
||||
impl RuntimeArch {
|
||||
#[cfg(target_os = "windows")]
|
||||
fn from_u32(value: u32) -> Option<Self> {
|
||||
match value {
|
||||
0x014c => Some(RuntimeArch::X86),
|
||||
0x8664 => Some(RuntimeArch::X64),
|
||||
0xAA64 => Some(RuntimeArch::Arm64),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_str(arch_str: &str) -> Option<Self> {
|
||||
match arch_str.to_lowercase().as_str() {
|
||||
"x86" => Some(RuntimeArch::X86),
|
||||
"i386" => Some(RuntimeArch::X86),
|
||||
"x64" => Some(RuntimeArch::X64),
|
||||
"x86_64" => Some(RuntimeArch::X64),
|
||||
"arm64" => Some(RuntimeArch::Arm64),
|
||||
"aarch64" => Some(RuntimeArch::Arm64),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn from_current_system() -> Option<Self> {
|
||||
return check_arch_windows();
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
pub fn from_current_system() -> Option<Self> {
|
||||
use os_info;
|
||||
let info = os_info::get();
|
||||
let machine = info.architecture();
|
||||
if machine.is_none() {
|
||||
return None;
|
||||
}
|
||||
let machine = machine.unwrap();
|
||||
if machine.is_empty() {
|
||||
return None;
|
||||
}
|
||||
Self::from_str(machine)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn check_arch_windows() -> Option<RuntimeArch> {
|
||||
use windows::Win32::Foundation::{FALSE, TRUE};
|
||||
use windows::Win32::System::SystemInformation::IMAGE_FILE_MACHINE;
|
||||
use windows::Win32::System::Threading::{GetCurrentProcess, IsWow64Process, IsWow64Process2};
|
||||
|
||||
unsafe {
|
||||
let handle = GetCurrentProcess();
|
||||
|
||||
let mut process_machine: IMAGE_FILE_MACHINE = Default::default();
|
||||
let mut native_machine: IMAGE_FILE_MACHINE = Default::default();
|
||||
if let Ok(()) = IsWow64Process2(handle, &mut process_machine, Some(&mut native_machine)) {
|
||||
return RuntimeArch::from_u32(native_machine.0.into());
|
||||
}
|
||||
|
||||
let mut iswow64 = FALSE;
|
||||
if let Ok(()) = IsWow64Process(handle, &mut iswow64) {
|
||||
if iswow64 == TRUE {
|
||||
return Some(RuntimeArch::X64);
|
||||
} else {
|
||||
return Some(RuntimeArch::X86);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
return Some(RuntimeArch::X64);
|
||||
|
||||
#[cfg(not(target_arch = "x86_64"))]
|
||||
return Some(RuntimeArch::X86);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_os = "windows")]
|
||||
fn test_current_architecture() {
|
||||
let arch = check_arch_windows();
|
||||
assert!(arch.is_some());
|
||||
let arch = arch.unwrap();
|
||||
assert!(arch == RuntimeArch::X64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cpu_arch_from_str() {
|
||||
assert_eq!(RuntimeArch::from_str("x86"), Some(RuntimeArch::X86));
|
||||
assert_eq!(RuntimeArch::from_str("x64"), Some(RuntimeArch::X64));
|
||||
assert_eq!(RuntimeArch::from_str("arm64"), Some(RuntimeArch::Arm64));
|
||||
assert_eq!(RuntimeArch::from_str("foo"), None);
|
||||
assert_eq!(RuntimeArch::from_str("X86"), Some(RuntimeArch::X86));
|
||||
assert_eq!(RuntimeArch::from_str("X64"), Some(RuntimeArch::X64));
|
||||
assert_eq!(RuntimeArch::from_str("ARM64"), Some(RuntimeArch::Arm64));
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
pub mod locksmith;
|
||||
pub mod mitigate;
|
||||
pub mod os_info;
|
||||
pub mod prerequisite;
|
||||
pub mod runtimes;
|
||||
pub mod splash;
|
||||
|
||||
@@ -1,820 +0,0 @@
|
||||
// spell-checker:ignore dword, minwindef, ntdef, ntdll, ntstatus, osversioninfoex, osversioninfoexa
|
||||
// spell-checker:ignore osversioninfoexw, serverr, sysinfoapi, winnt, winuser, pbool, libloaderapi
|
||||
// spell-checker:ignore lpcstr, processthreadsapi, farproc, lstatus, wchar, lpbyte, hkey, winerror
|
||||
// spell-checker:ignore osstr, winreg
|
||||
|
||||
#![allow(unsafe_code)]
|
||||
|
||||
use std::fmt::{self, Display, Formatter};
|
||||
use std::{
|
||||
ffi::{OsStr, OsString},
|
||||
mem::{self, MaybeUninit},
|
||||
os::windows::ffi::{OsStrExt, OsStringExt},
|
||||
ptr,
|
||||
};
|
||||
|
||||
use windows_sys::Win32::{
|
||||
Foundation::{ERROR_SUCCESS, FARPROC, NTSTATUS, STATUS_SUCCESS},
|
||||
System::{
|
||||
SystemInformation::{
|
||||
PROCESSOR_ARCHITECTURE_AMD64, PROCESSOR_ARCHITECTURE_ARM, PROCESSOR_ARCHITECTURE_IA64,
|
||||
PROCESSOR_ARCHITECTURE_INTEL,
|
||||
},
|
||||
LibraryLoader::{GetModuleHandleA, GetProcAddress},
|
||||
Registry::{RegOpenKeyExW, RegQueryValueExW, HKEY_LOCAL_MACHINE, KEY_READ, REG_SZ},
|
||||
SystemInformation::{GetNativeSystemInfo, GetSystemInfo, SYSTEM_INFO},
|
||||
SystemServices::{VER_NT_WORKSTATION, VER_SUITE_WH_SERVER},
|
||||
},
|
||||
UI::WindowsAndMessaging::{GetSystemMetrics, SM_SERVERR2},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct Info {
|
||||
/// Operating system type. See `Type` for details.
|
||||
pub(crate) os_type: Type,
|
||||
/// Operating system version. See `Version` for details.
|
||||
pub(crate) version: Version,
|
||||
/// Operating system edition.
|
||||
pub(crate) edition: Option<String>,
|
||||
/// Operating system codename.
|
||||
pub(crate) codename: Option<String>,
|
||||
/// Operating system architecture in terms of how many bits compose the basic values it can deal
|
||||
/// with. See `Bitness` for details.
|
||||
pub(crate) bitness: Bitness,
|
||||
/// Processor architecture.
|
||||
pub(crate) architecture: Option<String>,
|
||||
}
|
||||
|
||||
impl Info {
|
||||
/// Constructs a new `Info` instance with unknown type, version and bitness.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use os_info::{Info, Type, Version, Bitness};
|
||||
///
|
||||
/// let info = Info::unknown();
|
||||
/// assert_eq!(Type::Unknown, info.os_type());
|
||||
/// assert_eq!(&Version::Unknown, info.version());
|
||||
/// assert_eq!(None, info.edition());
|
||||
/// assert_eq!(None, info.codename());
|
||||
/// assert_eq!(Bitness::Unknown, info.bitness());
|
||||
/// assert_eq!(None, info.architecture());
|
||||
/// ```
|
||||
pub fn unknown() -> Self {
|
||||
Self {
|
||||
os_type: Type::Unknown,
|
||||
version: Version::Unknown,
|
||||
edition: None,
|
||||
codename: None,
|
||||
bitness: Bitness::Unknown,
|
||||
architecture: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Constructs a new `Info` instance with the specified operating system type.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use os_info::{Info, Type, Version, Bitness};
|
||||
///
|
||||
/// let os_type = Type::Linux;
|
||||
/// let info = Info::with_type(os_type);
|
||||
/// assert_eq!(os_type, info.os_type());
|
||||
/// assert_eq!(&Version::Unknown, info.version());
|
||||
/// assert_eq!(None, info.edition());
|
||||
/// assert_eq!(None, info.codename());
|
||||
/// assert_eq!(Bitness::Unknown, info.bitness());
|
||||
/// assert_eq!(None, info.architecture());
|
||||
/// ```
|
||||
pub fn with_type(os_type: Type) -> Self {
|
||||
Self {
|
||||
os_type,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns operating system type. See `Type` for details.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use os_info::{Info, Type};
|
||||
///
|
||||
/// let info = Info::unknown();
|
||||
/// assert_eq!(Type::Unknown, info.os_type());
|
||||
/// ```
|
||||
pub fn os_type(&self) -> Type {
|
||||
self.os_type
|
||||
}
|
||||
|
||||
/// Returns operating system version. See `Version` for details.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use os_info::{Info, Version};
|
||||
///
|
||||
/// let info = Info::unknown();
|
||||
/// assert_eq!(&Version::Unknown, info.version());
|
||||
/// ```
|
||||
pub fn version(&self) -> &Version {
|
||||
&self.version
|
||||
}
|
||||
|
||||
/// Returns optional operation system edition.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use os_info::Info;
|
||||
///
|
||||
/// let info = Info::unknown();
|
||||
/// assert_eq!(None, info.edition());
|
||||
pub fn edition(&self) -> Option<&str> {
|
||||
self.edition.as_ref().map(String::as_ref)
|
||||
}
|
||||
|
||||
/// Returns optional operation system 'codename'.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use os_info::Info;
|
||||
///
|
||||
/// let info = Info::unknown();
|
||||
/// assert_eq!(None, info.codename());
|
||||
pub fn codename(&self) -> Option<&str> {
|
||||
self.codename.as_ref().map(String::as_ref)
|
||||
}
|
||||
|
||||
/// Returns operating system bitness. See `Bitness` for details.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use os_info::{Info, Bitness};
|
||||
///
|
||||
/// let info = Info::unknown();
|
||||
/// assert_eq!(Bitness::Unknown, info.bitness());
|
||||
/// ```
|
||||
pub fn bitness(&self) -> Bitness {
|
||||
self.bitness
|
||||
}
|
||||
|
||||
/// Returns operating system architecture.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use os_info::Info;
|
||||
///
|
||||
/// let info = Info::unknown();
|
||||
/// assert_eq!(None, info.architecture());
|
||||
pub fn architecture(&self) -> Option<&str> {
|
||||
self.architecture.as_ref().map(String::as_ref)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Info {
|
||||
fn default() -> Self {
|
||||
Self::unknown()
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Info {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "{}", self.os_type)?;
|
||||
if self.version != Version::Unknown {
|
||||
write!(f, " {}", self.version)?;
|
||||
}
|
||||
if let Some(ref edition) = self.edition {
|
||||
write!(f, " ({edition})")?;
|
||||
}
|
||||
if let Some(ref codename) = self.codename {
|
||||
write!(f, " ({codename})")?;
|
||||
}
|
||||
write!(f, " [{}]", self.bitness)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[allow(non_camel_case_types, clippy::upper_case_acronyms)]
|
||||
#[non_exhaustive]
|
||||
pub enum Type {
|
||||
/// IBM AIX (<https://en.wikipedia.org/wiki/IBM_AIX>).
|
||||
AIX,
|
||||
/// Alpaquita Linux (<https://bell-sw.com/alpaquita-linux/>).
|
||||
Alpaquita,
|
||||
/// Alpine Linux (<https://en.wikipedia.org/wiki/Alpine_Linux>).
|
||||
Alpine,
|
||||
/// Amazon Linux AMI (<https://en.wikipedia.org/wiki/Amazon_Machine_Image#Amazon_Linux_AMI>).
|
||||
Amazon,
|
||||
/// Android (<https://en.wikipedia.org/wiki/Android_(operating_system)>).
|
||||
Android,
|
||||
/// Arch Linux (<https://en.wikipedia.org/wiki/Arch_Linux>).
|
||||
Arch,
|
||||
/// Artix Linux (<https://en.wikipedia.org/wiki/Artix_Linux>).
|
||||
Artix,
|
||||
/// CentOS (<https://en.wikipedia.org/wiki/CentOS>).
|
||||
CentOS,
|
||||
/// Debian (<https://en.wikipedia.org/wiki/Debian>).
|
||||
Debian,
|
||||
/// DragonFly BSD (<https://en.wikipedia.org/wiki/DragonFly_BSD>).
|
||||
DragonFly,
|
||||
/// Emscripten (<https://en.wikipedia.org/wiki/Emscripten>).
|
||||
Emscripten,
|
||||
/// EndeavourOS (<https://en.wikipedia.org/wiki/EndeavourOS>).
|
||||
EndeavourOS,
|
||||
/// Fedora (<https://en.wikipedia.org/wiki/Fedora_(operating_system)>).
|
||||
Fedora,
|
||||
/// FreeBSD (<https://en.wikipedia.org/wiki/FreeBSD>).
|
||||
FreeBSD,
|
||||
/// Garuda Linux (<https://en.wikipedia.org/wiki/Garuda_Linux>)
|
||||
Garuda,
|
||||
/// Gentoo Linux (<https://en.wikipedia.org/wiki/Gentoo_Linux>).
|
||||
Gentoo,
|
||||
/// HardenedBSD (https://hardenedbsd.org/).
|
||||
HardenedBSD,
|
||||
/// Illumos (https://en.wikipedia.org/wiki/Illumos).
|
||||
Illumos,
|
||||
/// Kali Linux (https://en.wikipedia.org/wiki/Kali_Linux).
|
||||
Kali,
|
||||
/// Linux based operating system (<https://en.wikipedia.org/wiki/Linux>).
|
||||
Linux,
|
||||
/// Mabox (<https://maboxlinux.org/>).
|
||||
Mabox,
|
||||
/// Mac OS X/OS X/macOS (<https://en.wikipedia.org/wiki/MacOS>).
|
||||
Macos,
|
||||
/// Manjaro (<https://en.wikipedia.org/wiki/Manjaro>).
|
||||
Manjaro,
|
||||
/// Mariner (<https://en.wikipedia.org/wiki/CBL-Mariner>).
|
||||
Mariner,
|
||||
/// MidnightBSD (<https://en.wikipedia.org/wiki/MidnightBSD>).
|
||||
MidnightBSD,
|
||||
/// Mint (<https://en.wikipedia.org/wiki/Linux_Mint>).
|
||||
Mint,
|
||||
/// NetBSD (<https://en.wikipedia.org/wiki/NetBSD>).
|
||||
NetBSD,
|
||||
/// NixOS (<https://en.wikipedia.org/wiki/NixOS>).
|
||||
NixOS,
|
||||
/// OpenBSD (<https://en.wikipedia.org/wiki/OpenBSD>).
|
||||
OpenBSD,
|
||||
/// OpenCloudOS (<https://www.opencloudos.org>).
|
||||
OpenCloudOS,
|
||||
/// openEuler (<https://en.wikipedia.org/wiki/EulerOS>).
|
||||
openEuler,
|
||||
/// openSUSE (<https://en.wikipedia.org/wiki/OpenSUSE>).
|
||||
openSUSE,
|
||||
/// Oracle Linux (<https://en.wikipedia.org/wiki/Oracle_Linux>).
|
||||
OracleLinux,
|
||||
/// Pop!_OS (<https://en.wikipedia.org/wiki/Pop!_OS>)
|
||||
Pop,
|
||||
/// Raspberry Pi OS (<https://en.wikipedia.org/wiki/Raspberry_Pi_OS>).
|
||||
Raspbian,
|
||||
/// Red Hat Linux (<https://en.wikipedia.org/wiki/Red_Hat_Linux>).
|
||||
Redhat,
|
||||
/// Red Hat Enterprise Linux (<https://en.wikipedia.org/wiki/Red_Hat_Enterprise_Linux>).
|
||||
RedHatEnterprise,
|
||||
/// Redox (<https://en.wikipedia.org/wiki/Redox_(operating_system)>).
|
||||
Redox,
|
||||
/// Solus (<https://en.wikipedia.org/wiki/Solus_(operating_system)>).
|
||||
Solus,
|
||||
/// SUSE Linux Enterprise Server (<https://en.wikipedia.org/wiki/SUSE_Linux_Enterprise>).
|
||||
SUSE,
|
||||
/// Ubuntu (<https://en.wikipedia.org/wiki/Ubuntu_(operating_system)>).
|
||||
Ubuntu,
|
||||
/// Unknown operating system.
|
||||
Unknown,
|
||||
/// Windows (<https://en.wikipedia.org/wiki/Microsoft_Windows>).
|
||||
Windows,
|
||||
}
|
||||
|
||||
impl Default for Type {
|
||||
fn default() -> Self {
|
||||
Type::Unknown
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Type {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Type::Alpaquita => write!(f, "Alpaquita Linux"),
|
||||
Type::Alpine => write!(f, "Alpine Linux"),
|
||||
Type::Amazon => write!(f, "Amazon Linux AMI"),
|
||||
Type::Arch => write!(f, "Arch Linux"),
|
||||
Type::Artix => write!(f, "Artix Linux"),
|
||||
Type::DragonFly => write!(f, "DragonFly BSD"),
|
||||
Type::Garuda => write!(f, "Garuda Linux"),
|
||||
Type::Gentoo => write!(f, "Gentoo Linux"),
|
||||
Type::Illumos => write!(f, "illumos"),
|
||||
Type::Kali => write!(f, "Kali Linux"),
|
||||
Type::Macos => write!(f, "Mac OS"),
|
||||
Type::MidnightBSD => write!(f, "Midnight BSD"),
|
||||
Type::Mint => write!(f, "Linux Mint"),
|
||||
Type::Pop => write!(f, "Pop!_OS"),
|
||||
Type::Raspbian => write!(f, "Raspberry Pi OS"),
|
||||
Type::Redhat => write!(f, "Red Hat Linux"),
|
||||
Type::RedHatEnterprise => write!(f, "Red Hat Enterprise Linux"),
|
||||
Type::SUSE => write!(f, "SUSE Linux Enterprise Server"),
|
||||
_ => write!(f, "{self:?}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub enum Bitness {
|
||||
/// Unknown bitness (unable to determine).
|
||||
Unknown,
|
||||
/// 32-bit.
|
||||
X32,
|
||||
/// 64-bit.
|
||||
X64,
|
||||
}
|
||||
|
||||
impl Display for Bitness {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Bitness::Unknown => write!(f, "unknown bitness"),
|
||||
Bitness::X32 => write!(f, "32-bit"),
|
||||
Bitness::X64 => write!(f, "64-bit"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Operating system version.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub enum Version {
|
||||
/// Unknown version.
|
||||
Unknown,
|
||||
/// Semantic version (major.minor.patch).
|
||||
Semantic(u64, u64, u64),
|
||||
/// Rolling version. Optionally contains the release date in the string format.
|
||||
Rolling(Option<String>),
|
||||
/// Custom version format.
|
||||
Custom(String),
|
||||
}
|
||||
|
||||
impl Version {
|
||||
/// Constructs `VersionType` from the given string.
|
||||
///
|
||||
/// Returns `VersionType::Unknown` if the string is empty. If it can be parsed as a semantic
|
||||
/// version, then `VersionType::Semantic`, otherwise `VersionType::Custom`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use os_info::Version;
|
||||
///
|
||||
/// let v = Version::from_string("custom");
|
||||
/// assert_eq!(Version::Custom("custom".to_owned()), v);
|
||||
///
|
||||
/// let v = Version::from_string("1.2.3");
|
||||
/// assert_eq!(Version::Semantic(1, 2, 3), v);
|
||||
/// ```
|
||||
pub fn from_string<S: Into<String> + AsRef<str>>(s: S) -> Self {
|
||||
if s.as_ref().is_empty() {
|
||||
Self::Unknown
|
||||
} else if let Some((major, minor, patch)) = parse_version(s.as_ref()) {
|
||||
Self::Semantic(major, minor, patch)
|
||||
} else {
|
||||
Self::Custom(s.into())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Version {
|
||||
fn default() -> Self {
|
||||
Version::Unknown
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Version {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Self::Unknown => f.write_str("Unknown"),
|
||||
Self::Semantic(major, minor, patch) => write!(f, "{major}.{minor}.{patch}"),
|
||||
Self::Rolling(ref date) => {
|
||||
let date = match date {
|
||||
Some(date) => format!(" ({date})"),
|
||||
None => "".to_owned(),
|
||||
};
|
||||
write!(f, "Rolling Release{date}")
|
||||
}
|
||||
Self::Custom(ref version) => write!(f, "{version}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_version(s: &str) -> Option<(u64, u64, u64)> {
|
||||
let mut iter = s.trim().split_terminator('.').fuse();
|
||||
|
||||
let major = iter.next().and_then(|s| s.parse().ok())?;
|
||||
let minor = iter.next().unwrap_or("0").parse().ok()?;
|
||||
let patch = iter.next().unwrap_or("0").parse().ok()?;
|
||||
|
||||
if iter.next().is_some() {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some((major, minor, patch))
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86")]
|
||||
type OSVERSIONINFOEX = windows_sys::Win32::System::SystemInformation::OSVERSIONINFOEXA;
|
||||
|
||||
#[cfg(not(target_arch = "x86"))]
|
||||
type OSVERSIONINFOEX = windows_sys::Win32::System::SystemInformation::OSVERSIONINFOEXW;
|
||||
|
||||
pub fn get() -> Info {
|
||||
let (version, edition) = version();
|
||||
let native_system_info = native_system_info();
|
||||
|
||||
Info {
|
||||
os_type: Type::Windows,
|
||||
version,
|
||||
edition,
|
||||
bitness: bitness(),
|
||||
architecture: architecture(native_system_info),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
fn version() -> (Version, Option<String>) {
|
||||
match version_info() {
|
||||
None => (Version::Unknown, None),
|
||||
Some(v) => (
|
||||
Version::Semantic(
|
||||
v.dwMajorVersion as u64,
|
||||
v.dwMinorVersion as u64,
|
||||
v.dwBuildNumber as u64,
|
||||
),
|
||||
product_name(&v).or_else(|| edition(&v)),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
// According to https://learn.microsoft.com/windows/win32/api/sysinfoapi/ns-sysinfoapi-system_info
|
||||
// there is a variant for AMD64 CPUs, but it's not defined in generated bindings.
|
||||
const PROCESSOR_ARCHITECTURE_ARM64: u16 = 12;
|
||||
|
||||
fn native_system_info() -> SYSTEM_INFO {
|
||||
let mut system_info: MaybeUninit<SYSTEM_INFO> = MaybeUninit::zeroed();
|
||||
unsafe {
|
||||
GetNativeSystemInfo(system_info.as_mut_ptr());
|
||||
};
|
||||
|
||||
unsafe { system_info.assume_init() }
|
||||
}
|
||||
|
||||
fn architecture(system_info: SYSTEM_INFO) -> Option<String> {
|
||||
let cpu_architecture = unsafe { system_info.Anonymous.Anonymous.wProcessorArchitecture };
|
||||
|
||||
match cpu_architecture {
|
||||
PROCESSOR_ARCHITECTURE_AMD64 => Some("x86_64"),
|
||||
PROCESSOR_ARCHITECTURE_IA64 => Some("ia64"),
|
||||
PROCESSOR_ARCHITECTURE_ARM => Some("arm"),
|
||||
PROCESSOR_ARCHITECTURE_ARM64 => Some("aarch64"),
|
||||
PROCESSOR_ARCHITECTURE_INTEL => Some("i386"),
|
||||
_ => None,
|
||||
}
|
||||
.map(str::to_string)
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
fn bitness() -> Bitness {
|
||||
// x64 program can only run on x64 Windows.
|
||||
Bitness::X64
|
||||
}
|
||||
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
fn bitness() -> Bitness {
|
||||
use windows_sys::Win32::Foundation::{BOOL, FALSE, HANDLE};
|
||||
use windows_sys::Win32::System::Threading::GetCurrentProcess;
|
||||
|
||||
// IsWow64Process is not available on all supported versions of Windows. Use GetModuleHandle to
|
||||
// get a handle to the DLL that contains the function and GetProcAddress to get a pointer to the
|
||||
// function if available.
|
||||
let is_wow_64 = match get_proc_address(b"kernel32\0", b"IsWow64Process\0") {
|
||||
None => return Bitness::Unknown,
|
||||
Some(val) => val,
|
||||
};
|
||||
|
||||
type IsWow64 = unsafe extern "system" fn(HANDLE, *mut BOOL) -> BOOL;
|
||||
let is_wow_64: IsWow64 = unsafe { mem::transmute(is_wow_64) };
|
||||
|
||||
let mut result = FALSE;
|
||||
if unsafe { is_wow_64(GetCurrentProcess(), &mut result) } == 0 {
|
||||
log::error!("IsWow64Process failed");
|
||||
return Bitness::Unknown;
|
||||
}
|
||||
|
||||
if result == FALSE {
|
||||
Bitness::X32
|
||||
} else {
|
||||
Bitness::X64
|
||||
}
|
||||
}
|
||||
|
||||
// Calls the Win32 API function RtlGetVersion to get the OS version information:
|
||||
// https://msdn.microsoft.com/library/mt723418(v=vs.85).aspx
|
||||
fn version_info() -> Option<OSVERSIONINFOEX> {
|
||||
let rtl_get_version = match get_proc_address(b"ntdll\0", b"RtlGetVersion\0") {
|
||||
None => return None,
|
||||
Some(val) => val,
|
||||
};
|
||||
|
||||
type RtlGetVersion = unsafe extern "system" fn(&mut OSVERSIONINFOEX) -> NTSTATUS;
|
||||
let rtl_get_version: RtlGetVersion = unsafe { mem::transmute(rtl_get_version) };
|
||||
|
||||
let mut info: OSVERSIONINFOEX = unsafe { mem::zeroed() };
|
||||
info.dwOSVersionInfoSize = mem::size_of::<OSVERSIONINFOEX>() as u32;
|
||||
|
||||
if unsafe { rtl_get_version(&mut info) } == STATUS_SUCCESS {
|
||||
Some(info)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
fn product_name(info: &OSVERSIONINFOEX) -> Option<String> {
|
||||
let sub_key = to_wide("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion");
|
||||
let mut key = Default::default();
|
||||
if unsafe { RegOpenKeyExW(HKEY_LOCAL_MACHINE, sub_key.as_ptr(), 0, KEY_READ, &mut key) }
|
||||
!= ERROR_SUCCESS
|
||||
|| key == 0
|
||||
{
|
||||
log::error!("RegOpenKeyExW(HKEY_LOCAL_MACHINE, ...) failed");
|
||||
return None;
|
||||
}
|
||||
|
||||
let is_win_11 = info.dwMajorVersion == 10 && info.dwBuildNumber >= 22000;
|
||||
|
||||
// Get size of the data.
|
||||
let name = to_wide(if is_win_11 {
|
||||
"EditionID"
|
||||
} else {
|
||||
"ProductName"
|
||||
});
|
||||
let mut data_type = 0;
|
||||
let mut data_size = 0;
|
||||
if unsafe {
|
||||
RegQueryValueExW(
|
||||
key,
|
||||
name.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
&mut data_type,
|
||||
ptr::null_mut(),
|
||||
&mut data_size,
|
||||
)
|
||||
} != ERROR_SUCCESS
|
||||
|| data_type != REG_SZ
|
||||
|| data_size == 0
|
||||
|| data_size % 2 != 0
|
||||
{
|
||||
log::error!("RegQueryValueExW failed");
|
||||
return None;
|
||||
}
|
||||
|
||||
// Get the data.
|
||||
let mut data = vec![0u16; data_size as usize / 2];
|
||||
if unsafe {
|
||||
RegQueryValueExW(
|
||||
key,
|
||||
name.as_ptr(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
data.as_mut_ptr().cast(),
|
||||
&mut data_size,
|
||||
)
|
||||
} != ERROR_SUCCESS
|
||||
|| data_size as usize != data.len() * 2
|
||||
{
|
||||
return None;
|
||||
}
|
||||
|
||||
// If the data has the REG_SZ, REG_MULTI_SZ or REG_EXPAND_SZ type, the string may not have been
|
||||
// stored with the proper terminating null characters.
|
||||
match data.last() {
|
||||
Some(0) => {
|
||||
data.pop();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
let value = OsString::from_wide(data.as_slice())
|
||||
.to_string_lossy()
|
||||
.into_owned();
|
||||
|
||||
if is_win_11 {
|
||||
Some(format!("Windows 11 {}", value))
|
||||
} else {
|
||||
Some(value)
|
||||
}
|
||||
}
|
||||
|
||||
fn to_wide(value: &str) -> Vec<u16> {
|
||||
OsStr::new(value).encode_wide().chain(Some(0)).collect()
|
||||
}
|
||||
|
||||
// Examines data in the OSVERSIONINFOEX structure to determine the Windows edition:
|
||||
// https://msdn.microsoft.com/library/windows/desktop/ms724833(v=vs.85).aspx
|
||||
fn edition(version_info: &OSVERSIONINFOEX) -> Option<String> {
|
||||
match (
|
||||
version_info.dwMajorVersion,
|
||||
version_info.dwMinorVersion,
|
||||
version_info.wProductType as u32,
|
||||
) {
|
||||
// Windows 10.
|
||||
(10, 0, VER_NT_WORKSTATION) => {
|
||||
if version_info.dwBuildNumber >= 22000 {
|
||||
Some("Windows 11")
|
||||
} else {
|
||||
Some("Windows 10")
|
||||
}
|
||||
}
|
||||
(10, 0, _) => Some("Windows Server 2016"),
|
||||
// Windows Vista, 7, 8 and 8.1.
|
||||
(6, 3, VER_NT_WORKSTATION) => Some("Windows 8.1"),
|
||||
(6, 3, _) => Some("Windows Server 2012 R2"),
|
||||
(6, 2, VER_NT_WORKSTATION) => Some("Windows 8"),
|
||||
(6, 2, _) => Some("Windows Server 2012"),
|
||||
(6, 1, VER_NT_WORKSTATION) => Some("Windows 7"),
|
||||
(6, 1, _) => Some("Windows Server 2008 R2"),
|
||||
(6, 0, VER_NT_WORKSTATION) => Some("Windows Vista"),
|
||||
(6, 0, _) => Some("Windows Server 2008"),
|
||||
// Windows 2000, Home Server, 2003 Server, 2003 R2 Server, XP and XP Professional x64.
|
||||
(5, 1, _) => Some("Windows XP"),
|
||||
(5, 0, _) => Some("Windows 2000"),
|
||||
(5, 2, _) if unsafe { GetSystemMetrics(SM_SERVERR2) } == 0 => {
|
||||
let mut info: SYSTEM_INFO = unsafe { mem::zeroed() };
|
||||
unsafe { GetSystemInfo(&mut info) };
|
||||
|
||||
if Into::<u32>::into(version_info.wSuiteMask) & VER_SUITE_WH_SERVER
|
||||
== VER_SUITE_WH_SERVER
|
||||
{
|
||||
Some("Windows Home Server")
|
||||
} else if version_info.wProductType == VER_NT_WORKSTATION as u8
|
||||
&& unsafe { info.Anonymous.Anonymous.wProcessorArchitecture }
|
||||
== PROCESSOR_ARCHITECTURE_AMD64
|
||||
{
|
||||
Some("Windows XP Professional x64 Edition")
|
||||
} else {
|
||||
Some("Windows Server 2003")
|
||||
}
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
.map(str::to_string)
|
||||
}
|
||||
|
||||
fn get_proc_address(module: &[u8], proc: &[u8]) -> Option<FARPROC> {
|
||||
assert!(
|
||||
*module.last().expect("Empty module name") == 0,
|
||||
"Module name should be zero-terminated"
|
||||
);
|
||||
assert!(
|
||||
*proc.last().expect("Empty procedure name") == 0,
|
||||
"Procedure name should be zero-terminated"
|
||||
);
|
||||
|
||||
let handle = unsafe { GetModuleHandleA(module.as_ptr()) };
|
||||
if handle == 0 {
|
||||
log::error!(
|
||||
"GetModuleHandleA({}) failed",
|
||||
String::from_utf8_lossy(module)
|
||||
);
|
||||
return None;
|
||||
}
|
||||
|
||||
unsafe { Some(GetProcAddress(handle, proc.as_ptr())) }
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use pretty_assertions::{assert_eq, assert_ne};
|
||||
|
||||
#[test]
|
||||
fn version() {
|
||||
let info = get();
|
||||
assert_eq!(Type::Windows, info.os_type());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_version_info() {
|
||||
let version = version_info();
|
||||
assert!(version.is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_edition() {
|
||||
let test_data = [
|
||||
(10, 0, 0, "Windows Server 2016"),
|
||||
(6, 3, VER_NT_WORKSTATION, "Windows 8.1"),
|
||||
(6, 3, 0, "Windows Server 2012 R2"),
|
||||
(6, 2, VER_NT_WORKSTATION, "Windows 8"),
|
||||
(6, 2, 0, "Windows Server 2012"),
|
||||
(6, 1, VER_NT_WORKSTATION, "Windows 7"),
|
||||
(6, 1, 0, "Windows Server 2008 R2"),
|
||||
(6, 0, VER_NT_WORKSTATION, "Windows Vista"),
|
||||
(6, 0, 0, "Windows Server 2008"),
|
||||
(5, 1, 0, "Windows XP"),
|
||||
(5, 1, 1, "Windows XP"),
|
||||
(5, 1, 100, "Windows XP"),
|
||||
(5, 0, 0, "Windows 2000"),
|
||||
(5, 0, 1, "Windows 2000"),
|
||||
(5, 0, 100, "Windows 2000"),
|
||||
];
|
||||
|
||||
let mut info = version_info().unwrap();
|
||||
|
||||
for &(major, minor, product_type, expected_edition) in &test_data {
|
||||
info.dwMajorVersion = major;
|
||||
info.dwMinorVersion = minor;
|
||||
info.wProductType = product_type as u8;
|
||||
|
||||
let edition = edition(&info).unwrap();
|
||||
assert_eq!(edition, expected_edition);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_bitness() {
|
||||
let b = bitness();
|
||||
assert_ne!(b, Bitness::Unknown);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "Empty module name")]
|
||||
fn empty_module_name() {
|
||||
get_proc_address(b"", b"RtlGetVersion\0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "Module name should be zero-terminated")]
|
||||
fn non_zero_terminated_module_name() {
|
||||
get_proc_address(b"ntdll", b"RtlGetVersion\0");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "Empty procedure name")]
|
||||
fn empty_proc_name() {
|
||||
get_proc_address(b"ntdll\0", b"");
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "Procedure name should be zero-terminated")]
|
||||
fn non_zero_terminated_proc_name() {
|
||||
get_proc_address(b"ntdll\0", b"RtlGetVersion");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn proc_address() {
|
||||
let address = get_proc_address(b"ntdll\0", b"RtlGetVersion\0");
|
||||
assert!(address.is_some());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_architecture() {
|
||||
let cpu_types: [(u16, Option<String>); 6] = [
|
||||
(PROCESSOR_ARCHITECTURE_AMD64, Some("x86_64".to_owned())),
|
||||
(PROCESSOR_ARCHITECTURE_ARM, Some("arm".to_owned())),
|
||||
(PROCESSOR_ARCHITECTURE_ARM64, Some("aarch64".to_owned())),
|
||||
(PROCESSOR_ARCHITECTURE_IA64, Some("ia64".to_owned())),
|
||||
(PROCESSOR_ARCHITECTURE_INTEL, Some("i386".to_owned())),
|
||||
(0xffff, None),
|
||||
];
|
||||
|
||||
let mut native_info = native_system_info();
|
||||
|
||||
for cpu_type in cpu_types {
|
||||
native_info.Anonymous.Anonymous.wProcessorArchitecture = cpu_type.0;
|
||||
assert_eq!(architecture(native_info), cpu_type.1);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_product_name() {
|
||||
let version = version_info().expect("version_info() failed");
|
||||
let edition = product_name(&version).expect("edition() failed");
|
||||
assert!(!edition.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn to_wide_str() {
|
||||
let data = [
|
||||
("", [0x0000].as_ref()),
|
||||
("U", &[0x0055, 0x0000]),
|
||||
("你好", &[0x4F60, 0x597D, 0x0000]),
|
||||
];
|
||||
|
||||
for (s, expected) in &data {
|
||||
let wide = to_wide(s);
|
||||
assert_eq!(&wide, expected);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::shared as util;
|
||||
use crate::shared::download;
|
||||
use crate::shared::runtime_arch::RuntimeArch;
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use regex::Regex;
|
||||
use std::process::Command as Process;
|
||||
@@ -56,54 +57,6 @@ lazy_static! {
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Clone, strum::IntoStaticStr)]
|
||||
pub enum RuntimeArch {
|
||||
X86,
|
||||
X64,
|
||||
Arm64,
|
||||
}
|
||||
|
||||
impl RuntimeArch {
|
||||
pub fn from_str(arch_str: &str) -> Option<Self> {
|
||||
match arch_str.to_lowercase().as_str() {
|
||||
"x86" => Some(RuntimeArch::X86),
|
||||
"x64" => Some(RuntimeArch::X64),
|
||||
"arm64" => Some(RuntimeArch::Arm64),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
pub fn from_current_system() -> Option<Self> {
|
||||
let info = super::os_info::get();
|
||||
let machine = info.architecture();
|
||||
if machine.is_none() {
|
||||
return None;
|
||||
}
|
||||
let mut machine = machine.unwrap();
|
||||
if machine.is_empty() {
|
||||
return None;
|
||||
}
|
||||
if machine == "x86_64" {
|
||||
machine = "x64";
|
||||
} else if machine == "i386" {
|
||||
machine = "x86";
|
||||
} else if machine == "aarch64" {
|
||||
machine = "arm64";
|
||||
}
|
||||
Self::from_str(machine)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cpu_arch_from_str() {
|
||||
assert_eq!(RuntimeArch::from_str("x86"), Some(RuntimeArch::X86));
|
||||
assert_eq!(RuntimeArch::from_str("x64"), Some(RuntimeArch::X64));
|
||||
assert_eq!(RuntimeArch::from_str("arm64"), Some(RuntimeArch::Arm64));
|
||||
assert_eq!(RuntimeArch::from_str("foo"), None);
|
||||
assert_eq!(RuntimeArch::from_str("X86"), Some(RuntimeArch::X86));
|
||||
assert_eq!(RuntimeArch::from_str("X64"), Some(RuntimeArch::X64));
|
||||
assert_eq!(RuntimeArch::from_str("ARM64"), Some(RuntimeArch::Arm64));
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, strum::IntoStaticStr)]
|
||||
pub enum RuntimeInstallResult {
|
||||
InstallSuccess,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::shared;
|
||||
use crate::shared::{self, runtime_arch::RuntimeArch};
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use normpath::PathExt;
|
||||
use std::{
|
||||
@@ -301,37 +301,31 @@ where
|
||||
}
|
||||
|
||||
pub fn is_cpu_architecture_supported(architecture: &str) -> Result<bool> {
|
||||
let info = super::os_info::get();
|
||||
let machine = info.architecture();
|
||||
let machine = RuntimeArch::from_current_system();
|
||||
if machine.is_none() {
|
||||
return Ok(true); // we can't detect current arch so try installing anyway.
|
||||
}
|
||||
|
||||
let mut machine = machine.unwrap();
|
||||
let is_win_11 = is_os_version_or_greater("11")?;
|
||||
|
||||
if machine.is_empty() || architecture.is_empty() {
|
||||
// we can't detect current os arch so try installing anyway
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
// https://github.com/stanislav-tkach/os_info/blob/master/os_info/src/windows/winapi.rs#L82
|
||||
if machine == "x86_64" {
|
||||
machine = "x64";
|
||||
} else if machine == "i386" {
|
||||
machine = "x86";
|
||||
} else if machine == "aarch64" {
|
||||
machine = "arm64";
|
||||
let architecture = RuntimeArch::from_str(architecture);
|
||||
if architecture.is_none() {
|
||||
// no arch specified in this package, so install on any arch
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
if machine == "x86" {
|
||||
let machine = machine.unwrap();
|
||||
let architecture = architecture.unwrap();
|
||||
let is_win_11 = is_os_version_or_greater("11")?;
|
||||
|
||||
if machine == RuntimeArch::X86 {
|
||||
// windows x86 only supports x86
|
||||
Ok(architecture == "x86")
|
||||
} else if machine == "x64" {
|
||||
Ok(architecture == RuntimeArch::X86)
|
||||
} else if machine == RuntimeArch::X64 {
|
||||
// windows x64 only supports x86 and x64
|
||||
Ok(architecture == "x86" || architecture == "x64")
|
||||
} else if machine == "arm64" {
|
||||
Ok(architecture == RuntimeArch::X86 || architecture == RuntimeArch::X64)
|
||||
} else if machine == RuntimeArch::Arm64 {
|
||||
// windows arm64 supports x86, and arm64, and only on windows 11 does it support x64
|
||||
Ok(architecture == "x86" || (architecture == "x64" && is_win_11) || architecture == "arm64")
|
||||
Ok(architecture == RuntimeArch::X86 || (architecture == RuntimeArch::X64 && is_win_11) || architecture == RuntimeArch::Arm64)
|
||||
} else {
|
||||
// we don't know what this is, so try installing anyway
|
||||
Ok(true)
|
||||
@@ -341,7 +335,7 @@ pub fn is_cpu_architecture_supported(architecture: &str) -> Result<bool> {
|
||||
#[test]
|
||||
pub fn test_x64_and_x86_is_supported_but_not_arm64_or_invalid() {
|
||||
assert!(!is_cpu_architecture_supported("arm64").unwrap());
|
||||
assert!(!is_cpu_architecture_supported("invalid").unwrap());
|
||||
assert!(is_cpu_architecture_supported("invalid").unwrap());
|
||||
assert!(is_cpu_architecture_supported("x64").unwrap());
|
||||
assert!(is_cpu_architecture_supported("x86").unwrap());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user