mirror of
https://github.com/velopack/velopack.git
synced 2025-10-25 15:19:22 +00:00
Add x86 support
This commit is contained in:
@@ -1,8 +1,10 @@
|
|||||||
[alias]
|
[alias]
|
||||||
bx = "build"
|
bx = "build"
|
||||||
bw = "build --features windows"
|
|
||||||
tx = "test"
|
tx = "test"
|
||||||
|
|
||||||
tw = "test --features windows"
|
tw = "test --features windows"
|
||||||
|
bw = "build --features windows"
|
||||||
|
bw86 = "build --target i686-pc-windows-msvc --features windows"
|
||||||
|
|
||||||
[build]
|
[build]
|
||||||
rustflags = ["-C", "target-feature=+crt-static"]
|
rustflags = ["-C", "target-feature=+crt-static"]
|
||||||
104
src/Rust/Cargo.lock
generated
104
src/Rust/Cargo.lock
generated
@@ -405,6 +405,12 @@ dependencies = [
|
|||||||
"rpassword",
|
"rpassword",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "diff"
|
||||||
|
version = "0.1.13"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "digest"
|
name = "digest"
|
||||||
version = "0.9.0"
|
version = "0.9.0"
|
||||||
@@ -1064,15 +1070,6 @@ dependencies = [
|
|||||||
"vcpkg",
|
"vcpkg",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "os_info"
|
|
||||||
version = "3.7.0"
|
|
||||||
source = "git+https://github.com/stanislav-tkach/os_info.git?branch=master#13df8d7858bf79e4f98b66bd33efac751240486f"
|
|
||||||
dependencies = [
|
|
||||||
"log",
|
|
||||||
"windows-sys 0.45.0",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "percent-encoding"
|
name = "percent-encoding"
|
||||||
version = "2.3.1"
|
version = "2.3.1"
|
||||||
@@ -1119,6 +1116,16 @@ dependencies = [
|
|||||||
"clap",
|
"clap",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "pretty_assertions"
|
||||||
|
version = "1.4.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66"
|
||||||
|
dependencies = [
|
||||||
|
"diff",
|
||||||
|
"yansi",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-crate"
|
name = "proc-macro-crate"
|
||||||
version = "1.3.1"
|
version = "1.3.1"
|
||||||
@@ -1671,8 +1678,8 @@ dependencies = [
|
|||||||
"native-tls",
|
"native-tls",
|
||||||
"normpath",
|
"normpath",
|
||||||
"ntest",
|
"ntest",
|
||||||
"os_info",
|
|
||||||
"pretty-bytes-rust",
|
"pretty-bytes-rust",
|
||||||
|
"pretty_assertions",
|
||||||
"rand",
|
"rand",
|
||||||
"regex",
|
"regex",
|
||||||
"remove_dir_all",
|
"remove_dir_all",
|
||||||
@@ -1885,15 +1892,6 @@ dependencies = [
|
|||||||
"windows-targets 0.52.0",
|
"windows-targets 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-sys"
|
|
||||||
version = "0.45.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
|
|
||||||
dependencies = [
|
|
||||||
"windows-targets 0.42.2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-sys"
|
name = "windows-sys"
|
||||||
version = "0.48.0"
|
version = "0.48.0"
|
||||||
@@ -1912,21 +1910,6 @@ dependencies = [
|
|||||||
"windows-targets 0.52.0",
|
"windows-targets 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows-targets"
|
|
||||||
version = "0.42.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
|
|
||||||
dependencies = [
|
|
||||||
"windows_aarch64_gnullvm 0.42.2",
|
|
||||||
"windows_aarch64_msvc 0.42.2",
|
|
||||||
"windows_i686_gnu 0.42.2",
|
|
||||||
"windows_i686_msvc 0.42.2",
|
|
||||||
"windows_x86_64_gnu 0.42.2",
|
|
||||||
"windows_x86_64_gnullvm 0.42.2",
|
|
||||||
"windows_x86_64_msvc 0.42.2",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows-targets"
|
name = "windows-targets"
|
||||||
version = "0.48.5"
|
version = "0.48.5"
|
||||||
@@ -1957,12 +1940,6 @@ dependencies = [
|
|||||||
"windows_x86_64_msvc 0.52.0",
|
"windows_x86_64_msvc 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_aarch64_gnullvm"
|
|
||||||
version = "0.42.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_gnullvm"
|
name = "windows_aarch64_gnullvm"
|
||||||
version = "0.48.5"
|
version = "0.48.5"
|
||||||
@@ -1975,12 +1952,6 @@ version = "0.52.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
|
checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_aarch64_msvc"
|
|
||||||
version = "0.42.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_aarch64_msvc"
|
name = "windows_aarch64_msvc"
|
||||||
version = "0.48.5"
|
version = "0.48.5"
|
||||||
@@ -1993,12 +1964,6 @@ version = "0.52.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
|
checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_gnu"
|
|
||||||
version = "0.42.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_gnu"
|
name = "windows_i686_gnu"
|
||||||
version = "0.48.5"
|
version = "0.48.5"
|
||||||
@@ -2011,12 +1976,6 @@ version = "0.52.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
|
checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_i686_msvc"
|
|
||||||
version = "0.42.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_i686_msvc"
|
name = "windows_i686_msvc"
|
||||||
version = "0.48.5"
|
version = "0.48.5"
|
||||||
@@ -2029,12 +1988,6 @@ version = "0.52.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
|
checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_gnu"
|
|
||||||
version = "0.42.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnu"
|
name = "windows_x86_64_gnu"
|
||||||
version = "0.48.5"
|
version = "0.48.5"
|
||||||
@@ -2047,12 +2000,6 @@ version = "0.52.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
|
checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_gnullvm"
|
|
||||||
version = "0.42.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_gnullvm"
|
name = "windows_x86_64_gnullvm"
|
||||||
version = "0.48.5"
|
version = "0.48.5"
|
||||||
@@ -2065,12 +2012,6 @@ version = "0.52.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
|
checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "windows_x86_64_msvc"
|
|
||||||
version = "0.42.2"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "windows_x86_64_msvc"
|
name = "windows_x86_64_msvc"
|
||||||
version = "0.48.5"
|
version = "0.48.5"
|
||||||
@@ -2103,8 +2044,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winsafe"
|
name = "winsafe"
|
||||||
version = "0.0.18"
|
version = "0.0.19"
|
||||||
source = "git+https://github.com/caesay/winsafe.git?branch=cs/only-ipersistfile#e9aadd0b7d8337364865039bf098e73be40d11a1"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "xml"
|
name = "xml"
|
||||||
@@ -2121,6 +2063,12 @@ version = "0.8.19"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a"
|
checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "yansi"
|
||||||
|
version = "0.5.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "zip"
|
name = "zip"
|
||||||
version = "0.6.6"
|
version = "0.6.6"
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ rpath = false # disable rpath
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0"
|
anyhow = "1.0"
|
||||||
pretty-bytes-rust = "0.3"
|
pretty-bytes-rust = "0.3"
|
||||||
os_info = { git = "https://github.com/stanislav-tkach/os_info.git", branch = "master", default-features = false } # public releases don't yet have processor arch info
|
|
||||||
zip = { version = "0.6", default-features = false, features = ["deflate"] }
|
zip = { version = "0.6", default-features = false, features = ["deflate"] }
|
||||||
regex = "1.10"
|
regex = "1.10"
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
@@ -85,14 +84,10 @@ libc = "0.2"
|
|||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
fs_extra = "1.2"
|
fs_extra = "1.2"
|
||||||
memmap2 = "0.9"
|
memmap2 = "0.9"
|
||||||
winsafe = { git = "https://github.com/caesay/winsafe.git", branch = "cs/only-ipersistfile", features = [
|
winsafe = { version = "0.0.19", features = [
|
||||||
"kernel",
|
|
||||||
"version",
|
"version",
|
||||||
"user",
|
"user",
|
||||||
"shell",
|
|
||||||
"comctl",
|
|
||||||
"gui",
|
"gui",
|
||||||
"ole",
|
|
||||||
] }
|
] }
|
||||||
image = { version = "0.24", default-features = false, features = [
|
image = { version = "0.24", default-features = false, features = [
|
||||||
"gif",
|
"gif",
|
||||||
@@ -127,6 +122,13 @@ windows-sys = { version = "0.52", default-features = false, features = [
|
|||||||
"Wdk",
|
"Wdk",
|
||||||
"Wdk_System",
|
"Wdk_System",
|
||||||
"Wdk_System_Threading",
|
"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"
|
normpath = "1.0.1"
|
||||||
codesign-verify = { git = "https://github.com/caesay/codesign-verify-rs.git" }
|
codesign-verify = { git = "https://github.com/caesay/codesign-verify-rs.git" }
|
||||||
@@ -134,6 +136,7 @@ codesign-verify = { git = "https://github.com/caesay/codesign-verify-rs.git" }
|
|||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tempfile = "3.9"
|
tempfile = "3.9"
|
||||||
ntest = "0.9.0"
|
ntest = "0.9.0"
|
||||||
|
pretty_assertions = "1.4"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
semver = "1.0"
|
semver = "1.0"
|
||||||
|
|||||||
@@ -1,6 +1,15 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
|
||||||
|
|
||||||
|
<!-- No UAC needed-->
|
||||||
|
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
|
||||||
|
<security>
|
||||||
|
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||||
|
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
|
||||||
|
</requestedPrivileges>
|
||||||
|
</security>
|
||||||
|
</trustInfo>
|
||||||
|
|
||||||
<!-- Indicate our support for newer versions so windows stops lying to us -->
|
<!-- Indicate our support for newer versions so windows stops lying to us -->
|
||||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||||
<application>
|
<application>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ use std::{
|
|||||||
use winsafe::{self as w, co};
|
use winsafe::{self as w, co};
|
||||||
|
|
||||||
pub fn install(debug_pkg: Option<&PathBuf>, install_to: Option<&PathBuf>) -> Result<()> {
|
pub fn install(debug_pkg: Option<&PathBuf>, install_to: Option<&PathBuf>) -> Result<()> {
|
||||||
let osinfo = os_info::get();
|
let osinfo = windows::os_info::get();
|
||||||
info!("OS: {}, Arch={}", osinfo, osinfo.architecture().unwrap_or("unknown"));
|
info!("OS: {}, Arch={}", osinfo, osinfo.architecture().unwrap_or("unknown"));
|
||||||
|
|
||||||
if !w::IsWindowsVersionOrGreater(6, 1, 1)? {
|
if !w::IsWindowsVersionOrGreater(6, 1, 1)? {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ pub mod download;
|
|||||||
pub mod prerequisite;
|
pub mod prerequisite;
|
||||||
pub mod runtimes;
|
pub mod runtimes;
|
||||||
pub mod splash;
|
pub mod splash;
|
||||||
|
pub mod os_info;
|
||||||
|
|
||||||
mod self_delete;
|
mod self_delete;
|
||||||
mod shortcuts;
|
mod shortcuts;
|
||||||
|
|||||||
820
src/Rust/src/windows/os_info.rs
Normal file
820
src/Rust/src/windows/os_info.rs
Normal file
@@ -0,0 +1,820 @@
|
|||||||
|
// 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/en-us/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/en-us/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/en-us/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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -72,7 +72,7 @@ impl RuntimeArch {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn from_current_system() -> Option<Self> {
|
pub fn from_current_system() -> Option<Self> {
|
||||||
let info = os_info::get();
|
let info = super::os_info::get();
|
||||||
let machine = info.architecture();
|
let machine = info.architecture();
|
||||||
if machine.is_none() {
|
if machine.is_none() {
|
||||||
return None;
|
return None;
|
||||||
|
|||||||
@@ -305,7 +305,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_cpu_architecture_supported(architecture: &str) -> Result<bool> {
|
pub fn is_cpu_architecture_supported(architecture: &str) -> Result<bool> {
|
||||||
let info = os_info::get();
|
let info = super::os_info::get();
|
||||||
let machine = info.architecture();
|
let machine = info.architecture();
|
||||||
if machine.is_none() {
|
if machine.is_none() {
|
||||||
return Ok(true); // we can't detect current arch so try installing anyway.
|
return Ok(true); // we can't detect current arch so try installing anyway.
|
||||||
|
|||||||
Reference in New Issue
Block a user