mirror of
https://github.com/Novattz/creamlinux-installer.git
synced 2026-01-24 12:22:49 -05:00
bitness detection
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
)]
|
||||
|
||||
mod cache;
|
||||
mod utils;
|
||||
mod dlc_manager;
|
||||
mod installer;
|
||||
mod searcher;
|
||||
|
||||
158
src-tauri/src/utils/bitness.rs
Normal file
158
src-tauri/src/utils/bitness.rs
Normal file
@@ -0,0 +1,158 @@
|
||||
use log::{debug, info, warn};
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
use walkdir::WalkDir;
|
||||
|
||||
/// Represents the bitness of a binary
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Bitness {
|
||||
Bit32,
|
||||
Bit64,
|
||||
}
|
||||
|
||||
/// Detect the bitness of a Linux Binary by reading ELF header
|
||||
/// ELF format: https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
|
||||
fn detect_binary_bitness(file_path: &Path) -> Option<Bitness> {
|
||||
// Read first 5 bytes of the file to check ELF header
|
||||
let bytes = match fs::read(file_path) {
|
||||
Ok(b) if b.len() >= 5 => b,
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
// Check for ELF magic number (0x7F 'E' 'L' 'F')
|
||||
if bytes.len() < 5 || &bytes[0..4] != b"\x7ELF" {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Byte 4 (EI_CLASS) indicates 32-bit or 64-bit
|
||||
// 1 = ELFCLASS32 (32-bit)
|
||||
// 2 = ELFCLASS64 (64-bit)
|
||||
match bytes[4] {
|
||||
1 => Some(Bitness::Bit32),
|
||||
2 => Some(Bitness::Bit64),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Scan game directory for Linux binaries and determine bitness
|
||||
/// Returns the detected bitness, prioritizing the main game executable
|
||||
pub fn detect_game_bitness(game_path: &str) -> Result<Bitness, String> {
|
||||
info!("Detecting bitness for game at: {}", game_path);
|
||||
|
||||
let game_path_obj = Path::new(game_path);
|
||||
if !game_path_obj.exists() {
|
||||
return Err("Game path does not exist".to_string());
|
||||
}
|
||||
|
||||
// Directories to skip for performance
|
||||
let skip_dirs = [
|
||||
"videos",
|
||||
"video",
|
||||
"movies",
|
||||
"movie",
|
||||
"sound",
|
||||
"sounds",
|
||||
"audio",
|
||||
"textures",
|
||||
"music",
|
||||
"localization",
|
||||
"shaders",
|
||||
"logs",
|
||||
"assets",
|
||||
"_CommonRedist",
|
||||
];
|
||||
|
||||
// Limit scan depth to avoid deep recursion
|
||||
const MAX_DEPTH: usize = 5;
|
||||
|
||||
let mut bit64_binaries = Vec::new();
|
||||
let mut bit32_binaries = Vec::new();
|
||||
|
||||
// Scan for Linux binaries
|
||||
for entry in WalkDir::new(game_path_obj)
|
||||
.max_depth(MAX_DEPTH)
|
||||
.follow_links(false)
|
||||
.into_iter()
|
||||
.filter_entry(|e| {
|
||||
if e.file_type().is_dir() {
|
||||
let dir_name = e.file_name().to_string_lossy().to_lowercase();
|
||||
!skip_dirs.iter().any(|&skip| dir_name.contains(skip))
|
||||
} else {
|
||||
true
|
||||
}
|
||||
})
|
||||
.filter_map(Result::ok)
|
||||
{
|
||||
let path = entry.path();
|
||||
|
||||
// Only check files
|
||||
if !path.is_file() {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check if file is executable
|
||||
#[cfg(unix)]
|
||||
{
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
if let Ok(metadata) = fs::metadata(path) {
|
||||
let permissions = metadata.permissions();
|
||||
// Check if executable bit is set
|
||||
if permissions.mode() & 0o111 == 0 {
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Check for common Linux executable extensions or no extension
|
||||
let filename = path.file_name().unwrap_or_default().to_string_lossy();
|
||||
let has_exe_extension = filename.ends_with(".x86")
|
||||
|| filename.ends_with(".x86_64")
|
||||
|| filename.ends_with(".bin")
|
||||
|| filename.contains('.');
|
||||
|
||||
// Also check for .so files (shared libraries) as they indicate bitness
|
||||
let is_shared_lib = filename.ends_with(".so")
|
||||
|| filename.contains(".so")
|
||||
|| filename.starts_with("lib");
|
||||
|
||||
if !has_exe_extension && !is_shared_lib {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Detect bitness
|
||||
if let Some(bitness) = detect_binary_bitness(path) {
|
||||
debug!("Found {:?} binary: {}", bitness, path.display());
|
||||
|
||||
match bitness {
|
||||
Bitness::Bit64 => bit64_binaries.push(path.to_path_buf()),
|
||||
Bitness::Bit32 => bit32_binaries.push(path.to_path_buf()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Decision logic: prioritize finding the main game executable
|
||||
// 1. If we found any 64-bit binaries and no 32-bit, it's 64-bit
|
||||
// 2. If we found any 32-bit binaries and no 64-bit, it's 32-bit
|
||||
// 3. If we found both, prefer 64-bit (modern games are usually 64-bit)
|
||||
// 4. If we found neither, return an error
|
||||
|
||||
if !bit64_binaries.is_empty() && bit32_binaries.is_empty() {
|
||||
info!("Detected 64-bit game (Only 64-bit binaries found");
|
||||
Ok(Bitness::Bit64)
|
||||
} else if !bit32_binaries.is_empty() && bit64_binaries.is_empty() {
|
||||
info!("Detected 32-bit game (Only 32-bit binaries found");
|
||||
Ok(Bitness::Bit32)
|
||||
} else if !bit64_binaries.is_empty() && !bit32_binaries.is_empty() {
|
||||
warn!(
|
||||
"Found both 32-bit and 64-bit binaries, defaulting to 64-bit. 32-bit: {}, 64-bit: {}",
|
||||
bit32_binaries.len(),
|
||||
bit64_binaries.len()
|
||||
);
|
||||
info!("Detected 64-bit game (mixed binaries, defaulting to 64-bit)");
|
||||
Ok(Bitness::Bit64)
|
||||
} else {
|
||||
Err("Could not detect game bitness: no Linux binaries found".to_string())
|
||||
}
|
||||
}
|
||||
1
src-tauri/src/utils/mod.rs
Normal file
1
src-tauri/src/utils/mod.rs
Normal file
@@ -0,0 +1 @@
|
||||
pub mod bitness;
|
||||
Reference in New Issue
Block a user