From 026297334f28500c8cbf6a5f48f395196700d6d7 Mon Sep 17 00:00:00 2001 From: Antonino Di Guardo <64427768+digant73@users.noreply.github.com> Date: Thu, 7 May 2026 05:38:57 +0200 Subject: [PATCH] Some fixes (#18686) ### FIXES + MINOR IMPROVEMENTS: - Fixed issue18685: Not a real issue. PR18648 added some logging that made evident a missing check on the validity of the paths in `games.yml` before trying to manage the path as a possible ISO file. That missing check was already present but simply invisible due to missing log - Fixed `bytes_to_hex()` function used to store file hash hex string: In some cases the integrity check wrongly reported the check as failed - Optimized `fs::get_optical_raw_device()` function: Moved under `_WIN32` block a check valid only on `Windows` and simplified the logic to detect a CDROM / BD as raw device - Used `iso_file` objects instead of `fs:file` in `ISO.cpp`: It allows to use proper `bool()` operator on some checks --- Utilities/File.cpp | 42 +++++++----------------- rpcs3/Crypto/utils.cpp | 8 +++++ rpcs3/Loader/ISO.cpp | 29 ++++++++-------- rpcs3/Loader/ISO.h | 5 +-- rpcs3/rpcs3qt/game_list_context_menu.cpp | 3 +- 5 files changed, 39 insertions(+), 48 deletions(-) diff --git a/Utilities/File.cpp b/Utilities/File.cpp index da29fba7bd..20e25794d2 100644 --- a/Utilities/File.cpp +++ b/Utilities/File.cpp @@ -1125,13 +1125,6 @@ bool fs::is_optical_raw_device([[maybe_unused]] const std::string& path) bool fs::get_optical_raw_device(const std::string& path, std::string* raw_device) { - // Skip a useless check to detect an optical raw device if navigating on subfolders (e.g. C:/subfolder_1/subfolder_2/), it means we are on a hdd/ssd. - // A path for an optical drive should include only the drive letter (e.g. E:/) - if (path.find_first_of(":") != path.find_last_not_of(delim)) - { - return false; - } - if (fs::is_optical_raw_device(path)) { if (raw_device) @@ -1143,38 +1136,27 @@ bool fs::get_optical_raw_device(const std::string& path, std::string* raw_device } #ifdef _WIN32 - constexpr u32 BUF_SIZE = 1000; - WCHAR drive_list[BUF_SIZE] = {0}; + // Skip a useless check to detect an optical raw device if navigating on subfolders (e.g. C:\subfolder_1\subfolder_2\), + // it means we are on a HDD/SSD. A path for an optical drive should include only the drive letter (e.g. E:\) + const size_t drive_delim_pos = path.find_first_of(":"); - // GetLogicalDriveStrings() returns a double-null terminated list of null-terminated strings. - // E.g. A:\B:\C:\ - const DWORD copied = GetLogicalDriveStrings(BUF_SIZE, drive_list); - - if (copied == 0 || copied > BUF_SIZE) + if (drive_delim_pos != 1 || drive_delim_pos != path.find_last_not_of(delim)) { return false; } - for (const WCHAR* drive = drive_list; drive && *drive; drive += wcslen(drive) + 1) + const std::string drive_letter = path.substr(0, drive_delim_pos + 1); // e.g. "E:" + const std::string drive_path = drive_letter + "\\"; // e.g. "E:\" + + if (GetDriveTypeA(drive_path.c_str()) == DRIVE_CDROM) { - if (GetDriveType(drive) == DRIVE_CDROM) + if (raw_device) { - const std::wstring ws(drive); - const std::string s = std::string(ws.begin(), ws.end() - 1); - - if (path.starts_with(s)) - { - if (raw_device) - { - *raw_device = "\\\\.\\" + s; - } - - return true; - } + *raw_device = "\\\\.\\" + drive_letter; } - } - return false; + return true; + } #endif return false; } diff --git a/rpcs3/Crypto/utils.cpp b/rpcs3/Crypto/utils.cpp index 51ad284c62..7c1d1df309 100644 --- a/rpcs3/Crypto/utils.cpp +++ b/rpcs3/Crypto/utils.cpp @@ -37,6 +37,14 @@ void bytes_to_hex(std::string& hex_str, const unsigned char* data, unsigned int { fmt::throw_exception("Failed to read bytes: %s", std::make_error_code(err).message()); } + + // Padding handling for values ​​< 0x10 (e.g. 0x05 becomes "5" instead of "05") + // If to_chars only writes 1 character, we move to the right and put '0' + if (ptr == &hex_str[i] + 1) + { + hex_str[i + 1] = hex_str[i]; + hex_str[i] = '0'; + } } } diff --git a/rpcs3/Loader/ISO.cpp b/rpcs3/Loader/ISO.cpp index 175e2fde1d..cfd83863ef 100644 --- a/rpcs3/Loader/ISO.cpp +++ b/rpcs3/Loader/ISO.cpp @@ -54,7 +54,7 @@ static void* get_aligned_buf() return s_aligned_buf.buf; } -static bool is_iso_file(const fs::file& file, u64* size = nullptr) +static bool is_iso_file(iso_file& file, u64* size = nullptr) { if (!file || file.size() < 32768ULL + 6) { @@ -87,7 +87,7 @@ bool is_iso_file(const std::string& path, u64* size, bool* is_raw_device) // "new_path" is updated with the raw device path in case "path" points to a BD drive const bool raw_device = fs::get_optical_raw_device(path, &new_path); - if (!raw_device && fs::is_dir(path)) + if (!raw_device && !fs::is_file(path)) { return false; } @@ -97,7 +97,7 @@ bool is_iso_file(const std::string& path, u64* size, bool* is_raw_device) *is_raw_device = raw_device; } - fs::file file(std::make_unique(new_path, fs::read)); + iso_file file(new_path); return is_iso_file(file, size); } @@ -337,7 +337,7 @@ iso_type_status iso_file_decryption::retrieve_key(iso_archive& archive, std::str return iso_type_status::ERROR_OPENING_KEY; } -iso_type_status iso_file_decryption::check_type(const std::string& path, std::string& key_path, aes_context* aes_ctx) +iso_type_status iso_file_decryption::check_type(const std::string& path, std::string* key_path, aes_context* aes_ctx) { if (!is_iso_file(path)) { @@ -363,8 +363,12 @@ iso_type_status iso_file_decryption::check_type(const std::string& path, std::st { if (fs::is_file(path)) { - key_path = path; - return get_key(key_path, aes_ctx); + if (key_path) + { + *key_path = path; + } + + return get_key(path, aes_ctx); } } @@ -381,7 +385,7 @@ bool iso_file_decryption::init(const std::string& path, iso_archive* archive) // Store the ISO region information (needed by both the "Redump" type (only on "decrypt()" method) and "3k3y" type) // - fs::file iso_file(std::make_unique(path, fs::read)); + iso_file iso_file(path); if (!is_iso_file(iso_file)) { @@ -390,7 +394,7 @@ bool iso_file_decryption::init(const std::string& path, iso_archive* archive) } // Reset the file position after it was changed by is_iso_file() - iso_file.seek(0); + iso_file.seek(0, fs::seek_set); std::array sec0_sec1; @@ -447,7 +451,7 @@ bool iso_file_decryption::init(const std::string& path, iso_archive* archive) else { // Try to detect the Redump type. If so, the decryption context is set into "m_aes_dec" - status = check_type(path, key_path, &m_aes_dec); + status = check_type(path, &key_path, &m_aes_dec); } switch (status) @@ -968,17 +972,14 @@ iso_archive::iso_archive(const std::string& path) // "m_path" is updated with the raw device path in case "path" points to a BD drive fs::get_optical_raw_device(path, &m_path); - fs::file iso_file(std::make_unique(m_path, fs::read)); - - if (!iso_file || !is_iso_file(iso_file)) + if (!is_iso_file(m_path)) { // Not ISO... TODO: throw something? iso_log.error("iso_archive: Failed to recognize ISO file: '%s'", path); return; } - // Reset the file position after it was changed by is_iso_file() - iso_file.seek(0); + fs::file iso_file(std::make_unique(m_path)); u8 descriptor_type = -2; bool use_ucs2_decoding = false; diff --git a/rpcs3/Loader/ISO.h b/rpcs3/Loader/ISO.h index 7287146a2f..0caf53f6a9 100644 --- a/rpcs3/Loader/ISO.h +++ b/rpcs3/Loader/ISO.h @@ -71,7 +71,7 @@ private: static iso_type_status retrieve_key(iso_archive& archive, std::string& key_path, aes_context& aes_ctx); public: - static iso_type_status check_type(const std::string& path, std::string& key_path, aes_context* aes_ctx = nullptr); + static iso_type_status check_type(const std::string& path, std::string* key_path = nullptr, aes_context* aes_ctx = nullptr); iso_encryption_type get_enc_type() const { return m_enc_type; } @@ -116,7 +116,7 @@ protected: u64 file_offset(u64 pos) const; public: - iso_file(const std::string& path, bs_t mode); + iso_file(const std::string& path, bs_t mode = fs::read); iso_file(const std::string& path, bs_t mode, const iso_fs_node& node); explicit operator bool() const { return m_file.operator bool(); } @@ -173,6 +173,7 @@ public: const std::string& path() const { return m_path; } const iso_fs_node& root() const { return m_root; } + iso_fs_node* retrieve(const std::string& path); bool exists(const std::string& path); bool is_file(const std::string& path); diff --git a/rpcs3/rpcs3qt/game_list_context_menu.cpp b/rpcs3/rpcs3qt/game_list_context_menu.cpp index eb56a76ab1..402286e2f1 100644 --- a/rpcs3/rpcs3qt/game_list_context_menu.cpp +++ b/rpcs3/rpcs3qt/game_list_context_menu.cpp @@ -605,8 +605,7 @@ void game_list_context_menu::show_single_selection_context_menu(const game_info& // Check integrity if (QString::fromStdString(current_game.category) == cat::cat_disc_game) { - std::string key_path; - const iso_type_status iso_type = iso_file_decryption::check_type(current_game.path, key_path); + const iso_type_status iso_type = iso_file_decryption::check_type(current_game.path); // If it's an ISO file (e.g. even a decrypted ISO), always provide the entry on the context menu but disable // it if the ISO does not support integrity check (e.g. non Redump ISO) or no integrity DB is found.