diff --git a/include/aurora/aurora.h b/include/aurora/aurora.h index 041dfe8..bb0e8b8 100644 --- a/include/aurora/aurora.h +++ b/include/aurora/aurora.h @@ -76,7 +76,8 @@ typedef void (*AuroraImGuiInitCallback)(const AuroraWindowSize* size); typedef struct { const char* appName; - const char* configPath; + const char* userPath; + const char* cachePath; AuroraBackend desiredBackend; uint32_t msaa; uint16_t maxTextureAnisotropy; @@ -113,7 +114,8 @@ typedef struct { typedef struct { AuroraBackend backend; - const char* configPath; + const char* userPath; + const char* cachePath; SDL_Window* window; AuroraWindowSize windowSize; } AuroraInfo; diff --git a/lib/aurora.cpp b/lib/aurora.cpp index 62b8043..2492aed 100644 --- a/lib/aurora.cpp +++ b/lib/aurora.cpp @@ -79,10 +79,15 @@ AuroraInfo initialize(int argc, char* argv[], const AuroraConfig& config) noexce } else { g_config.appName = strdup(g_config.appName); } - if (g_config.configPath == nullptr) { - g_config.configPath = SDL_GetPrefPath(nullptr, g_config.appName); + if (g_config.userPath == nullptr) { + g_config.userPath = SDL_GetPrefPath(nullptr, g_config.appName); } else { - g_config.configPath = strdup(g_config.configPath); + g_config.userPath = strdup(g_config.userPath); + } + if (g_config.cachePath == nullptr) { + g_config.cachePath = SDL_GetPrefPath(nullptr, g_config.appName); + } else { + g_config.cachePath = strdup(g_config.cachePath); } if (g_config.msaa == 0) { g_config.msaa = 1; @@ -159,7 +164,8 @@ AuroraInfo initialize(int argc, char* argv[], const AuroraConfig& config) noexce g_config.desiredBackend = selectedBackend; return { .backend = selectedBackend, - .configPath = g_config.configPath, + .userPath = g_config.userPath, + .cachePath = g_config.cachePath, .window = window::get_sdl_window(), .windowSize = size, }; diff --git a/lib/card/CardGciFolder.cpp b/lib/card/CardGciFolder.cpp index e52bafa..2b06e2e 100644 --- a/lib/card/CardGciFolder.cpp +++ b/lib/card/CardGciFolder.cpp @@ -103,14 +103,16 @@ ECardResult CardGciFolder::createFile(const char* filename, size_t size, FileHan gciFileHeader->m_blockCount = neededBlocks; gciFileHeader->m_firstBlock = m_bat.allocateBlocks(neededBlocks, maxBlocks); - m_files.push_back({*gciFileHeader, fileSize, reinterpret_cast(gciFilename.c_str()), false}); // push non-endian swapped header first - - handleOut = FileHandle(m_files.size() - 1, 0); - // write big endian header for dolphin compat gciFileHeader->swapEndian(); FileIO file(m_folderPath / gciFilename, true); - file.fileWrite(fileBuf.data(), fileBuf.size(), 0); + if (!file || !file.fileWrite(fileBuf.data(), fileBuf.size(), 0)) { + return ECardResult::IOERROR; + } + + gciFileHeader->swapEndian(); + m_files.push_back({*gciFileHeader, fileSize, reinterpret_cast(gciFilename.c_str()), false}); // push non-endian swapped header first + handleOut = FileHandle(m_files.size() - 1, 0); return ECardResult::READY; } @@ -340,25 +342,67 @@ void CardGciFolder::commit() { bool CardGciFolder::open(const std::filesystem::path& filepath) { m_folderPath = filepath; - if (!std::filesystem::exists(filepath) || !std::filesystem::is_directory(filepath)) + std::error_code ec; + if (!std::filesystem::exists(filepath, ec) || !std::filesystem::is_directory(filepath, ec)) { + if (ec) { + Log.warn("Failed to inspect GCI folder '{}': {}", fs_path_to_string(filepath), ec.message()); + } return false; + } - for (const auto& dir : std::filesystem::directory_iterator(filepath)) { - if (!dir.is_regular_file()) { + std::filesystem::directory_iterator it( + filepath, std::filesystem::directory_options::skip_permission_denied, ec); + if (ec) { + Log.warn("Failed to enumerate GCI folder '{}': {}", fs_path_to_string(filepath), ec.message()); + return false; + } + + const std::filesystem::directory_iterator end; + while (it != end) { + const auto path = it->path(); + const auto status = it->status(ec); + if (ec) { + Log.warn("Failed to inspect GCI folder entry '{}': {}", fs_path_to_string(path), ec.message()); + return false; + } + if (!std::filesystem::is_regular_file(status)) { + it.increment(ec); + if (ec) { + Log.warn("Failed to continue enumerating GCI folder '{}': {}", fs_path_to_string(filepath), ec.message()); + return false; + } continue; } - auto path = dir.path(); - if (path.extension() != ".gci") + if (path.extension() != ".gci") { + it.increment(ec); + if (ec) { + Log.warn("Failed to continue enumerating GCI folder '{}': {}", fs_path_to_string(filepath), ec.message()); + return false; + } continue; + } FileIO file(path); + if (!file) { + Log.warn("Failed to open GCI file '{}'", fs_path_to_string(path)); + return false; + } File fileData; - file.fileRead((void*)&fileData, sizeof(File), 0); + if (!file.fileRead(&fileData, sizeof(File), 0)) { + Log.warn("Failed to read GCI file '{}'", fs_path_to_string(path)); + return false; + } fileData.swapEndian(); m_files.push_back({fileData, file.fileSize(), path.filename().u8string(), false}); + + it.increment(ec); + if (ec) { + Log.warn("Failed to continue enumerating GCI folder '{}': {}", fs_path_to_string(filepath), ec.message()); + return false; + } } return true; diff --git a/lib/dolphin/card.cpp b/lib/dolphin/card.cpp index 3784e32..626ce4f 100644 --- a/lib/dolphin/card.cpp +++ b/lib/dolphin/card.cpp @@ -174,8 +174,8 @@ void CARDInit(const char* game, const char* maker) { } std::filesystem::path cardWorkingDir; - if (aurora::g_config.configPath != nullptr) - cardWorkingDir = reinterpret_cast(aurora::g_config.configPath); + if (aurora::g_config.userPath != nullptr) + cardWorkingDir = reinterpret_cast(aurora::g_config.userPath); else cardWorkingDir = std::filesystem::current_path(); @@ -189,10 +189,14 @@ void CARDInit(const char* game, const char* maker) { const auto& curPath = cardPaths[i]; - if (std::filesystem::exists(curPath)) { - CardChannels[i]->open(curPath); + std::error_code ec; + if (std::filesystem::exists(curPath, ec) && CardChannels[i]->open(curPath)) { loadedCard = true; Log.info("Loaded GC Card Image: {}", fs_path_to_string(curPath)); + } else if (ec) { + Log.warn("Failed to inspect GC Card path '{}': {}", fs_path_to_string(curPath), ec.message()); + } else if (std::filesystem::exists(curPath, ec)) { + Log.warn("Failed to load GC Card Image: {}", fs_path_to_string(curPath)); } } @@ -735,4 +739,4 @@ s32 CARDWriteAsync(const CARDFileInfo* fileInfo, const void* addr, const s32 len callback(fileInfo->chan, res); return res; } -} \ No newline at end of file +} diff --git a/lib/dolphin/pad/pad.cpp b/lib/dolphin/pad/pad.cpp index bcecdd7..7dc995d 100644 --- a/lib/dolphin/pad/pad.cpp +++ b/lib/dolphin/pad/pad.cpp @@ -447,7 +447,7 @@ void __PADLoadMapping(aurora::input::GameController* controller) /* NOLINT(*-re return; } - std::string basePath{aurora::g_config.configPath}; + std::string basePath{aurora::g_config.userPath}; if (!controller->m_mappingLoaded) { __PADSetDefaultMapping(controller); controller->m_axisMapping = g_defaultAxes; @@ -1150,7 +1150,7 @@ constexpr uint32_t k_keyboardMagic = SBIG('KBND'); constexpr int32_t k_keyboardVersion = 3; static void load_keyboard_bindings() { - const auto filePath = std::filesystem::path{aurora::g_config.configPath} / "keyboard_bindings.dat"; + const auto filePath = std::filesystem::path{aurora::g_config.userPath} / "keyboard_bindings.dat"; SDL_IOStream* file = SDL_IOFromFile(filePath.string().c_str(), "rb"); if (file == nullptr) { return; @@ -1220,7 +1220,7 @@ static void load_keyboard_bindings() { } static void save_keyboard_bindings() { - const auto filePath = std::filesystem::path{aurora::g_config.configPath} / "keyboard_bindings.dat"; + const auto filePath = std::filesystem::path{aurora::g_config.userPath} / "keyboard_bindings.dat"; SDL_IOStream* file = SDL_IOFromFile(filePath.string().c_str(), "wb"); if (file == nullptr) { aurora::input::Log.warn("save_keyboard_bindings: failed to open {} for writing", filePath.string()); @@ -1247,7 +1247,7 @@ void __PADWriteDeadZones(SDL_IOStream* file, // NOLINT(*-reserved-identifier) } void PADSerializeMappings() { - const std::filesystem::path basePath{aurora::g_config.configPath}; + const std::filesystem::path basePath{aurora::g_config.userPath}; for (auto& controller : aurora::input::g_GameControllers | std::views::values) { EnsureMappingLoaded(&controller); @@ -1629,4 +1629,4 @@ PADControllerType PADGetControllerTypeForIndex(const u32 index) { return PAD_TYPE_NSO_GAMECUBE; } return static_cast(type); -} \ No newline at end of file +} diff --git a/lib/gfx/pipeline_cache.cpp b/lib/gfx/pipeline_cache.cpp index f5cdc86..633cc64 100644 --- a/lib/gfx/pipeline_cache.cpp +++ b/lib/gfx/pipeline_cache.cpp @@ -227,7 +227,7 @@ static bool prepare_pipeline_cache_db() { return true; } - const auto path = (std::filesystem::path{g_config.configPath} / "pipeline_cache.db").string(); + const auto path = (std::filesystem::path{g_config.cachePath} / "pipeline_cache.db").string(); auto ret = sqlite3_open(path.c_str(), &g_pipelineCacheDb); if (ret != SQLITE_OK) { Log.error("Failed to open pipeline cache database: {}", sqlite3_errmsg(g_pipelineCacheDb)); diff --git a/lib/gfx/texture_replacement.cpp b/lib/gfx/texture_replacement.cpp index edafb91..bd5c91b 100644 --- a/lib/gfx/texture_replacement.cpp +++ b/lib/gfx/texture_replacement.cpp @@ -493,10 +493,11 @@ void build_index() noexcept { return; } - auto configPath = std::filesystem::path{reinterpret_cast(g_config.configPath)}; + auto userPath = std::filesystem::path{reinterpret_cast(g_config.userPath)}; + auto cachePath = std::filesystem::path{reinterpret_cast(g_config.cachePath)}; - s_replacementRoot = configPath / "texture_replacements"; - s_dumpRoot = configPath / "texture_dumps"; + s_replacementRoot = userPath / "texture_replacements"; + s_dumpRoot = cachePath / "texture_dumps"; if (!ensure_directory(s_replacementRoot)) { return; diff --git a/lib/imgui.cpp b/lib/imgui.cpp index 2d40cc4..0c31342 100644 --- a/lib/imgui.cpp +++ b/lib/imgui.cpp @@ -32,8 +32,8 @@ void create_context() noexcept { IMGUI_CHECKVERSION(); ImGui::CreateContext(); ImGuiIO& io = ImGui::GetIO(); - g_imguiSettings = std::string{g_config.configPath} + "/imgui.ini"; - g_imguiLog = std::string{g_config.configPath} + "/imgui.log"; + g_imguiSettings = std::string{g_config.userPath} + "/imgui.ini"; + g_imguiLog = std::string{g_config.cachePath} + "/imgui.log"; io.IniFilename = g_imguiSettings.c_str(); io.LogFilename = g_imguiLog.c_str(); } diff --git a/lib/input.cpp b/lib/input.cpp index b1931c5..b060b17 100644 --- a/lib/input.cpp +++ b/lib/input.cpp @@ -45,11 +45,11 @@ std::array g_portPreferences; bool g_portPreferencesLoaded = false; std::string port_preferences_path() { - if (g_config.configPath == nullptr) { + if (g_config.userPath == nullptr) { return {}; } - std::string path{g_config.configPath}; + std::string path{g_config.userPath}; if (!path.empty() && path.back() != '/' && path.back() != '\\') { path += '/'; } @@ -196,8 +196,8 @@ void save_port_preferences() { return; } - if (!SDL_CreateDirectory(g_config.configPath)) { - Log.warn("Failed to create controller port preference directory '{}': {}", g_config.configPath, SDL_GetError()); + if (!SDL_CreateDirectory(g_config.userPath)) { + Log.warn("Failed to create controller port preference directory '{}': {}", g_config.userPath, SDL_GetError()); return; } diff --git a/lib/webgpu/gpu_cache.cpp b/lib/webgpu/gpu_cache.cpp index 6f34ffb..e0395cb 100644 --- a/lib/webgpu/gpu_cache.cpp +++ b/lib/webgpu/gpu_cache.cpp @@ -92,7 +92,7 @@ INSERT INTO aurora_schema VALUES ({});)", static bool cache_init_core() { Log.debug("SQLite version {}", sqlite3_libversion()); - std::string file = fs_path_to_string(std::filesystem::path{reinterpret_cast(g_config.configPath)} / "dawn_cache.db"); + std::string file = fs_path_to_string(std::filesystem::path{reinterpret_cast(g_config.cachePath)} / "dawn_cache.db"); Log.debug("Using dawn cache at {}", file); auto ret = sqlite3_open(file.c_str(), &db); if (ret != SQLITE_OK) {