diff --git a/src-tauri/src/utils/bitness.rs b/src-tauri/src/utils/bitness.rs index 0ab1bfd..5882a23 100644 --- a/src-tauri/src/utils/bitness.rs +++ b/src-tauri/src/utils/bitness.rs @@ -13,14 +13,19 @@ pub enum Bitness { /// 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 { - // 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, - }; + use std::io::Read; + + // Only read first 5 bytes + let mut file = fs::File::open(file_path).ok()?; + let mut bytes = [0u8; 5]; + + // Read exactly 5 bytes or fail + if file.read_exact(&mut bytes).is_err() { + return None; + } // Check for ELF magic number (0x7F 'E' 'L' 'F') - if bytes.len() < 5 || &bytes[0..4] != b"\x7FELF" { + if &bytes[0..4] != b"\x7FELF" { return None; } @@ -60,14 +65,32 @@ pub fn detect_game_bitness(game_path: &str) -> Result { "logs", "assets", "_CommonRedist", + "data", + "Data", + "Docs", + "docs", + "screenshots", + "Screenshots", + "saves", + "Saves", + "mods", + "Mods", + "maps", + "Maps", ]; // Limit scan depth to avoid deep recursion - const MAX_DEPTH: usize = 5; + const MAX_DEPTH: usize = 3; + + // Stop after finding reasonable confidence (10 binaries) + const CONFIDENCE_THRESHOLD: usize = 10; let mut bit64_binaries = Vec::new(); let mut bit32_binaries = Vec::new(); + #[cfg(unix)] + use std::os::unix::fs::PermissionsExt; + // Scan for Linux binaries for entry in WalkDir::new(game_path_obj) .max_depth(MAX_DEPTH) @@ -83,6 +106,12 @@ pub fn detect_game_bitness(game_path: &str) -> Result { }) .filter_map(Result::ok) { + // Early termination when we have high confidence + if bit64_binaries.len() >= CONFIDENCE_THRESHOLD || bit32_binaries.len() >= CONFIDENCE_THRESHOLD { + debug!("Reached confidence threshold, stopping scan early"); + break; + } + let path = entry.path(); // Only check files @@ -102,20 +131,24 @@ pub fn detect_game_bitness(game_path: &str) -> Result { || filename.starts_with("lib"); // Check if file is executable - #[cfg(unix)] - { - use std::os::unix::fs::PermissionsExt; - if let Ok(metadata) = fs::metadata(path) { - let permissions = metadata.permissions(); - let is_executable = permissions.mode() & 0o111 != 0; - - // Skip files that are neither executable nor have binary extensions - if !is_executable && !has_binary_extension { - continue; + let is_executable = { + { + // Get metadata once and check both extension and permissions + if let Ok(metadata) = fs::metadata(path) { + let permissions = metadata.permissions(); + let executable = permissions.mode() & 0o111 != 0; + + // Skip files that are neither executable nor have binary extensions + executable || has_binary_extension + } else { + // If we can't read metadata, only proceed if it has binary extension + has_binary_extension } - } else { - continue; } + }; + + if !is_executable { + continue; } // Detect bitness @@ -123,8 +156,24 @@ pub fn detect_game_bitness(game_path: &str) -> Result { 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()), + Bitness::Bit64 => { + bit64_binaries.push(path.to_path_buf()); + + // If we find libsteam_api.so and it's 64-bit, we can be very confident + if filename == "libsteam_api.so" { + info!("Found 64-bit libsteam_api.so"); + return Ok(Bitness::Bit64); + } + }, + Bitness::Bit32 => { + bit32_binaries.push(path.to_path_buf()); + + // If we find libsteam_api.so and it's 32-bit, we can be very confident + if filename == "libsteam_api.so" { + info!("Found 32-bit libsteam_api.so"); + return Ok(Bitness::Bit32); + } + }, } } }