From 53072cb289b4cb02a823ebe5952762f8e50d0faa Mon Sep 17 00:00:00 2001 From: David Chavez Date: Sun, 2 Jun 2024 20:38:40 +0200 Subject: [PATCH] Use file backup system for config files (#29) --- librecomp/CMakeLists.txt | 1 + librecomp/include/librecomp/recomp_files.h | 14 ++++++ librecomp/src/files.cpp | 51 ++++++++++++++++++++++ librecomp/src/pi.cpp | 44 ++++++------------- 4 files changed, 79 insertions(+), 31 deletions(-) create mode 100644 librecomp/include/librecomp/recomp_files.h create mode 100644 librecomp/src/files.cpp diff --git a/librecomp/CMakeLists.txt b/librecomp/CMakeLists.txt index 02d2558..55c1bc8 100644 --- a/librecomp/CMakeLists.txt +++ b/librecomp/CMakeLists.txt @@ -8,6 +8,7 @@ add_library(librecomp STATIC "${CMAKE_CURRENT_SOURCE_DIR}/src/dp.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/eep.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/euc-jp.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/src/files.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/flash.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/math_routines.cpp" "${CMAKE_CURRENT_SOURCE_DIR}/src/overlays.cpp" diff --git a/librecomp/include/librecomp/recomp_files.h b/librecomp/include/librecomp/recomp_files.h new file mode 100644 index 0000000..63e3e9d --- /dev/null +++ b/librecomp/include/librecomp/recomp_files.h @@ -0,0 +1,14 @@ +#ifndef __RECOMP_FILES_H__ +#define __RECOMP_FILES_H__ + +#include +#include + +namespace recomp { + std::ifstream open_input_file_with_backup(const std::filesystem::path& filepath, std::ios_base::openmode mode = std::ios_base::in); + std::ifstream open_input_backup_file(const std::filesystem::path& filepath, std::ios_base::openmode mode = std::ios_base::in); + std::ofstream open_output_file_with_backup(const std::filesystem::path& filepath, std::ios_base::openmode mode = std::ios_base::out); + bool finalize_output_file_with_backup(const std::filesystem::path& filepath); +}; + +#endif diff --git a/librecomp/src/files.cpp b/librecomp/src/files.cpp new file mode 100644 index 0000000..facb160 --- /dev/null +++ b/librecomp/src/files.cpp @@ -0,0 +1,51 @@ +#include "recomp_files.h" + +constexpr std::u8string_view backup_suffix = u8".bak"; +constexpr std::u8string_view temp_suffix = u8".temp"; + +std::ifstream recomp::open_input_backup_file(const std::filesystem::path& filepath, std::ios_base::openmode mode) { + std::filesystem::path backup_path{filepath}; + backup_path += backup_suffix; + return std::ifstream{backup_path, mode}; +} + +std::ifstream recomp::open_input_file_with_backup(const std::filesystem::path& filepath, std::ios_base::openmode mode) { + std::ifstream ret{filepath, mode}; + + // Check if the file failed to open and open the corresponding backup file instead if so. + if (!ret.good()) { + return open_input_backup_file(filepath, mode); + } + + return ret; +} + +std::ofstream recomp::open_output_file_with_backup(const std::filesystem::path& filepath, std::ios_base::openmode mode) { + std::filesystem::path temp_path{filepath}; + temp_path += temp_suffix; + std::ofstream temp_file_out{ temp_path, mode }; + + return temp_file_out; +} + +bool recomp::finalize_output_file_with_backup(const std::filesystem::path& filepath) { + std::filesystem::path backup_path{filepath}; + backup_path += backup_suffix; + + std::filesystem::path temp_path{filepath}; + temp_path += temp_suffix; + + std::error_code ec; + if (std::filesystem::exists(filepath, ec)) { + std::filesystem::copy_file(filepath, backup_path, std::filesystem::copy_options::overwrite_existing, ec); + if (ec) { + return false; + } + } + std::filesystem::copy_file(temp_path, filepath, std::filesystem::copy_options::overwrite_existing, ec); + if (ec) { + return false; + } + std::filesystem::remove(temp_path, ec); + return true; +} diff --git a/librecomp/src/pi.cpp b/librecomp/src/pi.cpp index 715e458..8ee7025 100644 --- a/librecomp/src/pi.cpp +++ b/librecomp/src/pi.cpp @@ -6,6 +6,7 @@ #include #include "recomp.h" #include "recomp_game.h" +#include "recomp_files.h" #include #include @@ -101,37 +102,24 @@ std::filesystem::path get_save_file_path() { return config_path / save_folder / (std::u8string{recomp::current_game_id()} + u8".bin"); } -std::filesystem::path get_save_file_path_temp() { - return config_path / save_folder / (recomp::current_game_id() + u8".bin.temp"); -} - -std::filesystem::path get_save_file_path_backup() { - return config_path / save_folder / (recomp::current_game_id() + u8".bin.bak"); -} - void update_save_file() { + bool saving_failed = false; { - std::ofstream save_file{ get_save_file_path_temp(), std::ios_base::binary }; + std::ofstream save_file = recomp::open_output_file_with_backup(get_save_file_path(), std::ios_base::binary); if (save_file.good()) { std::lock_guard lock{ save_context.save_buffer_mutex }; save_file.write(save_context.save_buffer.data(), save_context.save_buffer.size()); } else { - ultramodern::error_handling::message_box("Failed to write to the save file. Check your file permissions. If you have moved your appdata folder to Dropbox or similar, this can cause issues."); + saving_failed = false; } } - - std::error_code ec; - if (std::filesystem::exists(get_save_file_path(), ec)) { - std::filesystem::copy_file(get_save_file_path(), get_save_file_path_backup(), std::filesystem::copy_options::overwrite_existing, ec); - if (ec) { - printf("[ERROR] Failed to copy save file backup\n"); - } + if (!saving_failed) { + saving_failed = !recomp::finalize_output_file_with_backup(get_save_file_path()); } - std::filesystem::copy_file(get_save_file_path_temp(), get_save_file_path(), std::filesystem::copy_options::overwrite_existing, ec); - if (ec) { - ultramodern::error_handling::message_box("Failed to write to the save file. Check your file permissions. If you have moved your appdata folder to Dropbox or similar, this can cause issues."); + if (saving_failed) { + ultramodern::error_handling::message_box("Failed to write to the save file. Check your file permissions and whether the save folder has been moved to Dropbox or similar, as this can cause issues."); } } @@ -198,24 +186,18 @@ void save_clear(uint32_t start, uint32_t size, char value) { void ultramodern::init_saving(RDRAM_ARG1) { std::filesystem::path save_file_path = get_save_file_path(); - std::filesystem::path save_file_path_backup = get_save_file_path_backup(); // Ensure the save file directory exists. std::filesystem::create_directories(save_file_path.parent_path()); // Read the save file if it exists. - std::ifstream save_file{ save_file_path, std::ios_base::binary }; + std::ifstream save_file = recomp::open_input_file_with_backup(save_file_path, std::ios_base::binary); if (save_file.good()) { save_file.read(save_context.save_buffer.data(), save_context.save_buffer.size()); - } else { - // Reading the save file faield, so try to read the backup save file. - std::ifstream save_file_backup{ save_file_path_backup, std::ios_base::binary }; - if (save_file_backup.good()) { - save_file_backup.read(save_context.save_buffer.data(), save_context.save_buffer.size()); - } else { - // Otherwise clear the save file to all zeroes. - save_context.save_buffer.fill(0); - } + } + else { + // Otherwise clear the save file to all zeroes. + save_context.save_buffer.fill(0); } save_context.saving_thread = std::thread{saving_thread_func, PASS_RDRAM};