diff --git a/common/FileSystem.cpp b/common/FileSystem.cpp index 66cc4f57c2..e162a55599 100644 --- a/common/FileSystem.cpp +++ b/common/FileSystem.cpp @@ -994,6 +994,37 @@ std::FILE* FileSystem::OpenCFile(const char* filename, const char* mode, Error* #endif } +std::FILE* FileSystem::OpenCFileTryIgnoreCase(const char* filename, const char* mode, Error* error) +{ +#if defined(_WIN32) || defined(__APPLE__) + return OpenCFile(filename, mode, error); +#else + std::FILE* fp = std::fopen(filename, mode); + const auto cur_errno = errno; + + if (!fp) + { + const auto dir = std::string(Path::GetDirectory(filename)); + FindResultsArray files; + if (FindFiles(dir.c_str(), "*", FILESYSTEM_FIND_FILES | FILESYSTEM_FIND_HIDDEN_FILES, &files)) + { + for (auto& file : files) + { + if (StringUtil::compareNoCase(file.FileName, filename)) + { + fp = std::fopen(file.FileName.c_str(), mode); + break; + } + } + } + } + if (!fp) + Error::SetErrno(error, cur_errno); + return fp; +#endif +} + + int FileSystem::OpenFDFile(const char* filename, int flags, int mode, Error* error) { #ifdef _WIN32 @@ -1015,6 +1046,11 @@ FileSystem::ManagedCFilePtr FileSystem::OpenManagedCFile(const char* filename, c return ManagedCFilePtr(OpenCFile(filename, mode, error)); } +FileSystem::ManagedCFilePtr FileSystem::OpenManagedCFileTryIgnoreCase(const char* filename, const char* mode, Error* error) +{ + return ManagedCFilePtr(OpenCFileTryIgnoreCase(filename, mode, error)); +} + std::FILE* FileSystem::OpenSharedCFile(const char* filename, const char* mode, FileShareMode share_mode, Error* error) { #ifdef _WIN32 diff --git a/common/FileSystem.h b/common/FileSystem.h index e1f73229db..6b7fe1806c 100644 --- a/common/FileSystem.h +++ b/common/FileSystem.h @@ -106,7 +106,16 @@ namespace FileSystem /// open files using ManagedCFilePtr = std::unique_ptr; ManagedCFilePtr OpenManagedCFile(const char* filename, const char* mode, Error* error = nullptr); + // Tries to open a file using the given filename, but if that fails searches + // the directory for a file with a case-insensitive match. + // This is the same as OpenManagedCFile on Windows and MacOS + ManagedCFilePtr OpenManagedCFileTryIgnoreCase(const char* filename, const char* mode, Error* error = nullptr); std::FILE* OpenCFile(const char* filename, const char* mode, Error* error = nullptr); + // Tries to open a file using the given filename, but if that fails searches + // the directory for a file with a case-insensitive match. + // This is the same as OpenCFile on Windows and MacOS + std::FILE* OpenCFileTryIgnoreCase(const char* filename, const char* mode, Error* error = nullptr); + int FSeek64(std::FILE* fp, s64 offset, int whence); s64 FTell64(std::FILE* fp); s64 FSize64(std::FILE* fp); diff --git a/pcsx2/CDVD/CDVD.cpp b/pcsx2/CDVD/CDVD.cpp index 34bea0e58f..9bd3c9b3bf 100644 --- a/pcsx2/CDVD/CDVD.cpp +++ b/pcsx2/CDVD/CDVD.cpp @@ -155,7 +155,7 @@ void cdvdLoadNVRAM() { Error error; const std::string nvmfile = cdvdGetNVRAMPath(); - auto fp = FileSystem::OpenManagedCFile(nvmfile.c_str(), "rb", &error); + auto fp = FileSystem::OpenManagedCFileTryIgnoreCase(nvmfile.c_str(), "rb", &error); if (!fp || std::fread(s_nvram, sizeof(s_nvram), 1, fp.get()) != 1) { ERROR_LOG("Failed to open or read NVRAM at {}: {}", Path::GetFileName(nvmfile), error.GetDescription()); @@ -178,7 +178,7 @@ void cdvdLoadNVRAM() // Also load the mechacon version while we're here. const std::string mecfile = Path::ReplaceExtension(BiosPath, "mec"); - fp = FileSystem::OpenManagedCFile(mecfile.c_str(), "rb", &error); + fp = FileSystem::OpenManagedCFileTryIgnoreCase(mecfile.c_str(), "rb", &error); if (!fp || std::fread(&s_mecha_version, sizeof(s_mecha_version), 1, fp.get()) != 1) { s_mecha_version = DEFAULT_MECHA_VERSION; @@ -186,7 +186,7 @@ void cdvdLoadNVRAM() ERROR_LOG("Failed to open or read MEC file at {}: {}, creating default.", Path::GetFileName(nvmfile), error.GetDescription()); fp.reset(); - fp = FileSystem::OpenManagedCFile(mecfile.c_str(), "wb"); + fp = FileSystem::OpenManagedCFileTryIgnoreCase(mecfile.c_str(), "wb"); if (!fp || std::fwrite(&s_mecha_version, sizeof(s_mecha_version), 1, fp.get()) != 1) Host::ReportErrorAsync("Error", "Failed to write MEC file. Check your BIOS setup/permission settings."); } @@ -197,10 +197,10 @@ void cdvdSaveNVRAM() { Error error; const std::string nvmfile = cdvdGetNVRAMPath(); - auto fp = FileSystem::OpenManagedCFile(nvmfile.c_str(), "r+b", &error); + auto fp = FileSystem::OpenManagedCFileTryIgnoreCase(nvmfile.c_str(), "r+b", &error); if (!fp) { - fp = FileSystem::OpenManagedCFile(nvmfile.c_str(), "w+b", &error); + fp = FileSystem::OpenManagedCFileTryIgnoreCase(nvmfile.c_str(), "w+b", &error); if (!fp) [[unlikely]] { ERROR_LOG("Failed to open NVRAM at {} for updating: {}", Path::GetFileName(nvmfile), error.GetDescription()); diff --git a/pcsx2/ps2/BiosTools.cpp b/pcsx2/ps2/BiosTools.cpp index 3604aef717..0f3f9a33c0 100644 --- a/pcsx2/ps2/BiosTools.cpp +++ b/pcsx2/ps2/BiosTools.cpp @@ -226,7 +226,7 @@ static void LoadExtraRom(const char* ext, u32 offset, u32 size) BiosRom.resize(offset + size); - auto fp = FileSystem::OpenManagedCFile(Bios1.c_str(), "rb"); + auto fp = FileSystem::OpenManagedCFileTryIgnoreCase(Bios1.c_str(), "rb"); if (!fp || std::fread(&BiosRom[offset], static_cast(std::min(size, filesize)), 1, fp.get()) != 1) { Console.Warning("BIOS Warning: %s could not be read (permission denied?)", ext);