mirror of
				https://github.com/N64Recomp/N64ModernRuntime.git
				synced 2025-10-30 08:02:29 +00:00 
			
		
		
		
	Use file backup system for config files (#29)
This commit is contained in:
		
							parent
							
								
									e0769a223b
								
							
						
					
					
						commit
						53072cb289
					
				
					 4 changed files with 79 additions and 31 deletions
				
			
		|  | @ -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" | ||||
|  |  | |||
							
								
								
									
										14
									
								
								librecomp/include/librecomp/recomp_files.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								librecomp/include/librecomp/recomp_files.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,14 @@ | |||
| #ifndef __RECOMP_FILES_H__ | ||||
| #define __RECOMP_FILES_H__ | ||||
| 
 | ||||
| #include <filesystem> | ||||
| #include <fstream> | ||||
| 
 | ||||
| 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 | ||||
							
								
								
									
										51
									
								
								librecomp/src/files.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								librecomp/src/files.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -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; | ||||
| } | ||||
|  | @ -6,6 +6,7 @@ | |||
| #include <mutex> | ||||
| #include "recomp.h" | ||||
| #include "recomp_game.h" | ||||
| #include "recomp_files.h" | ||||
| #include <ultramodern/ultra64.h> | ||||
| #include <ultramodern/ultramodern.hpp> | ||||
| 
 | ||||
|  | @ -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}; | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 David Chavez
						David Chavez