Skip to content

Commit 49ea513

Browse files
committed
Use winapi instead of PowerShell to discover browser version
1 parent 50c6c13 commit 49ea513

File tree

6 files changed

+117
-30
lines changed

6 files changed

+117
-30
lines changed

rust/Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ apple-flat-package = "0.20.0"
3838
which = "7.0.2"
3939
fs2 = "0.4.3"
4040
fs_extra = "1.3.0"
41+
winapi = { version = "0.3.9", features = ["winver", "winnt", "sysinfoapi"] }
4142

4243
[dev-dependencies]
4344
assert_cmd = "2.0.16"

rust/src/config.rs

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@
1616
// under the License.
1717

1818
use crate::config::OS::{LINUX, MACOS, WINDOWS};
19-
use crate::shell::{run_powershell_command, run_shell_command_by_os};
19+
use crate::shell::run_shell_command_by_os;
2020
use crate::{
2121
default_cache_folder, format_one_arg, path_to_string, Command, ENV_PROCESSOR_ARCHITECTURE,
2222
REQUEST_TIMEOUT_SEC, UNAME_COMMAND,
2323
};
24-
use crate::{ARCH_AMD64, ARCH_ARM64, ARCH_X86, PS_GET_OS_COMMAND, TTL_SEC};
24+
use crate::{ARCH_AMD64, ARCH_ARM64, ARCH_X86, TTL_SEC};
2525
use anyhow::anyhow;
2626
use anyhow::Error;
2727
use std::cell::RefCell;
@@ -30,6 +30,11 @@ use std::env::consts::OS;
3030
use std::fs::read_to_string;
3131
use std::path::Path;
3232
use toml::Table;
33+
use winapi::um::sysinfoapi::{GetNativeSystemInfo, SYSTEM_INFO};
34+
use winapi::um::winnt::{
35+
PROCESSOR_ARCHITECTURE_AMD64, PROCESSOR_ARCHITECTURE_ARM, PROCESSOR_ARCHITECTURE_ARM64,
36+
PROCESSOR_ARCHITECTURE_IA64, PROCESSOR_ARCHITECTURE_INTEL,
37+
};
3338

3439
thread_local!(static CACHE_PATH: RefCell<String> = RefCell::new(path_to_string(&default_cache_folder())));
3540

@@ -71,8 +76,7 @@ impl ManagerConfig {
7176
let self_arch = if WINDOWS.is(self_os) {
7277
let mut architecture = env::var(ENV_PROCESSOR_ARCHITECTURE).unwrap_or_default();
7378
if architecture.is_empty() {
74-
let get_os_command = Command::new_single(PS_GET_OS_COMMAND.to_string());
75-
architecture = run_powershell_command(get_os_command).unwrap_or_default();
79+
architecture = get_win_os_architecture();
7680
}
7781
if architecture.contains("32") {
7882
ARCH_X86.to_string()
@@ -297,3 +301,20 @@ fn read_cache_path() -> String {
297301
});
298302
cache_path
299303
}
304+
305+
fn get_win_os_architecture() -> String {
306+
unsafe {
307+
let mut system_info: SYSTEM_INFO = std::mem::zeroed();
308+
GetNativeSystemInfo(&mut system_info);
309+
310+
match system_info.u.s() {
311+
si if si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64 => "64-bit",
312+
si if si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL => "32-bit",
313+
si if si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_ARM => "ARM",
314+
si if si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_ARM64 => "ARM64",
315+
si if si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_IA64 => "Itanium-based",
316+
_ => "Unknown",
317+
}
318+
.to_string()
319+
}
320+
}

rust/src/files.rs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,18 @@ use directories::BaseDirs;
2929
use flate2::read::GzDecoder;
3030
use fs_extra::dir::{move_dir, CopyOptions};
3131
use regex::Regex;
32+
use std::ffi::OsStr;
3233
use std::fs;
3334
use std::fs::File;
3435
use std::io;
3536
use std::io::{BufReader, Cursor, Read};
37+
use std::os::windows::ffi::OsStrExt;
3638
use std::path::{Path, PathBuf};
39+
use std::ptr;
3740
use tar::Archive;
3841
use walkdir::{DirEntry, WalkDir};
42+
use winapi::shared::minwindef::LPVOID;
43+
use winapi::um::winver::{GetFileVersionInfoSizeW, GetFileVersionInfoW, VerQueryValueW};
3944
use xz2::read::XzDecoder;
4045
use zip::ZipArchive;
4146

@@ -594,3 +599,80 @@ pub fn capitalize(s: &str) -> String {
594599
Some(first) => first.to_uppercase().collect::<String>() + chars.as_str(),
595600
}
596601
}
602+
603+
pub fn get_win_file_version(file_path: &str) -> Option<String> {
604+
unsafe {
605+
let wide_path: Vec<u16> = OsStr::new(file_path).encode_wide().chain(Some(0)).collect();
606+
607+
let mut dummy = 0;
608+
let size = GetFileVersionInfoSizeW(wide_path.as_ptr(), &mut dummy);
609+
if size == 0 {
610+
return None;
611+
}
612+
613+
let mut buffer: Vec<u8> = Vec::with_capacity(size as usize);
614+
if GetFileVersionInfoW(wide_path.as_ptr(), 0, size, buffer.as_mut_ptr() as LPVOID) == 0 {
615+
return None;
616+
}
617+
buffer.set_len(size as usize);
618+
619+
let mut lang_and_codepage_ptr: LPVOID = ptr::null_mut();
620+
let mut lang_and_codepage_len: u32 = 0;
621+
622+
if VerQueryValueW(
623+
buffer.as_ptr() as LPVOID,
624+
OsStr::new("\\VarFileInfo\\Translation")
625+
.encode_wide()
626+
.chain(Some(0))
627+
.collect::<Vec<u16>>()
628+
.as_ptr(),
629+
&mut lang_and_codepage_ptr,
630+
&mut lang_and_codepage_len,
631+
) == 0
632+
{
633+
return None;
634+
}
635+
636+
if lang_and_codepage_len == 0 {
637+
return None;
638+
}
639+
640+
let lang_and_codepage_slice = std::slice::from_raw_parts(
641+
lang_and_codepage_ptr as *const u16,
642+
lang_and_codepage_len as usize / 2,
643+
);
644+
let lang = lang_and_codepage_slice[0];
645+
let codepage = lang_and_codepage_slice[1];
646+
647+
let query = format!(
648+
"\\StringFileInfo\\{:04x}{:04x}\\ProductVersion",
649+
lang, codepage
650+
);
651+
let query_wide: Vec<u16> = OsStr::new(&query).encode_wide().chain(Some(0)).collect();
652+
653+
let mut product_version_ptr: LPVOID = ptr::null_mut();
654+
let mut product_version_len: u32 = 0;
655+
656+
if VerQueryValueW(
657+
buffer.as_ptr() as LPVOID,
658+
query_wide.as_ptr(),
659+
&mut product_version_ptr,
660+
&mut product_version_len,
661+
) == 0
662+
{
663+
return None;
664+
}
665+
666+
if product_version_ptr.is_null() {
667+
return None;
668+
}
669+
670+
let product_version_slice = std::slice::from_raw_parts(
671+
product_version_ptr as *const u16,
672+
product_version_len as usize,
673+
);
674+
let product_version = String::from_utf16_lossy(product_version_slice);
675+
676+
Some(product_version.trim_end_matches('\0').to_string())
677+
}
678+
}

rust/src/lib.rs

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use crate::config::OS::{MACOS, WINDOWS};
2020
use crate::config::{str_to_os, ManagerConfig};
2121
use crate::downloads::download_to_tmp_folder;
2222
use crate::edge::{EdgeManager, EDGEDRIVER_NAME, EDGE_NAMES, WEBVIEW2_NAME};
23+
use crate::files::get_win_file_version;
2324
use crate::files::{
2425
capitalize, collect_files_from_cache, create_path_if_not_exists, default_cache_folder,
2526
find_latest_from_cache, get_binary_extension, path_to_string,
@@ -37,8 +38,7 @@ use crate::metadata::{
3738
use crate::safari::{SafariManager, SAFARIDRIVER_NAME, SAFARI_NAME};
3839
use crate::safaritp::{SafariTPManager, SAFARITP_NAMES};
3940
use crate::shell::{
40-
run_powershell_command_with_log, run_shell_command, run_shell_command_by_os,
41-
run_shell_command_with_log, Command,
41+
run_shell_command, run_shell_command_by_os, run_shell_command_with_log, Command,
4242
};
4343
use crate::stats::{send_stats_to_plausible, Props};
4444
use anyhow::anyhow;
@@ -76,8 +76,6 @@ pub const DEV: &str = "dev";
7676
pub const CANARY: &str = "canary";
7777
pub const NIGHTLY: &str = "nightly";
7878
pub const ESR: &str = "esr";
79-
pub const PS_GET_VERSION_COMMAND: &str = r#"(Get-Item "{}").VersionInfo.ProductVersion"#;
80-
pub const PS_GET_OS_COMMAND: &str = "(Get-WmiObject Win32_OperatingSystem).OSArchitecture";
8179
pub const REG_VERSION_ARG: &str = "version";
8280
pub const REG_CURRENT_VERSION_ARG: &str = "CurrentVersion";
8381
pub const REG_PV_ARG: &str = "pv";
@@ -448,12 +446,11 @@ pub trait SeleniumManager {
448446
));
449447
let mut browser_version: Option<String> = None;
450448
for driver_version_command in commands.into_iter() {
451-
let command_result = if driver_version_command.display().starts_with("(Get-") {
452-
run_powershell_command_with_log(self.get_logger(), driver_version_command)
453-
} else {
454-
run_shell_command_with_log(self.get_logger(), self.get_os(), driver_version_command)
455-
};
456-
let output = match command_result {
449+
let output = match run_shell_command_with_log(
450+
self.get_logger(),
451+
self.get_os(),
452+
driver_version_command,
453+
) {
457454
Ok(out) => out,
458455
Err(_) => continue,
459456
};
@@ -1161,11 +1158,7 @@ pub trait SeleniumManager {
11611158
let mut commands = Vec::new();
11621159
if WINDOWS.is(self.get_os()) {
11631160
if !escaped_browser_path.is_empty() {
1164-
let get_version_command = Command::new_single(format_one_arg(
1165-
PS_GET_VERSION_COMMAND,
1166-
&escaped_browser_path,
1167-
));
1168-
commands.push(get_version_command);
1161+
return Ok(get_win_file_version(&escaped_browser_path));
11691162
}
11701163
if !self.is_browser_version_unstable() {
11711164
let reg_command =

rust/src/shell.rs

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -64,13 +64,6 @@ impl Command {
6464
}
6565
}
6666

67-
pub fn run_powershell_command_with_log(log: &Logger, command: Command) -> Result<String, Error> {
68-
log.debug(format!("Running ps command: {}", command.display()));
69-
let output = run_powershell_command(command)?;
70-
log.debug(format!("Output: {:?}", output));
71-
Ok(output)
72-
}
73-
7467
pub fn run_shell_command_with_log(
7568
log: &Logger,
7669
os: &str,
@@ -82,10 +75,6 @@ pub fn run_shell_command_with_log(
8275
Ok(output)
8376
}
8477

85-
pub fn run_powershell_command(command: Command) -> Result<String, Error> {
86-
run_shell_command("powershell", "-c", command)
87-
}
88-
8978
pub fn run_shell_command_by_os(os: &str, command: Command) -> Result<String, Error> {
9079
let (shell, flag) = if WINDOWS.is(os) {
9180
("cmd", "/c")

0 commit comments

Comments
 (0)