From 703ced337bc8303bccc57a098c9e49603381b651 Mon Sep 17 00:00:00 2001 From: TheBrokenRail Date: Sun, 25 Sep 2022 19:35:51 -0400 Subject: [PATCH] Use File Locking --- launcher/src/bootstrap.c | 20 +++- launcher/src/client/cache.cpp | 160 ++++++++++++++++------------- libreborn/include/libreborn/util.h | 4 + libreborn/src/util/util.c | 21 ++++ 4 files changed, 133 insertions(+), 72 deletions(-) diff --git a/launcher/src/bootstrap.c b/launcher/src/bootstrap.c index fdf2a501e..889b99f16 100644 --- a/launcher/src/bootstrap.c +++ b/launcher/src/bootstrap.c @@ -193,10 +193,24 @@ void run_simple_command(const char *const command[], const char *error) { ERR("%s", error); } } +#define HOME_SUBDIRECTORY_FOR_SDK HOME_SUBDIRECTORY_FOR_GAME_DATA "/sdk" static void copy_sdk(char *binary_directory) { + // Ensure SDK Directory + { + char *sdk_path = NULL; + safe_asprintf(&sdk_path, "%s" HOME_SUBDIRECTORY_FOR_SDK, getenv("HOME")); + const char *const command[] = {"mkdir", "-p", sdk_path, NULL}; + run_simple_command(command, "Unable To Create SDK Directory"); + } + + // Lock File + char *lock_file_path = NULL; + safe_asprintf(&lock_file_path, "%s" HOME_SUBDIRECTORY_FOR_SDK "/.lock", getenv("HOME")); + int lock_file_fd = lock_file(lock_file_path); + // Output Directory char *output = NULL; - safe_asprintf(&output, "%s" HOME_SUBDIRECTORY_FOR_GAME_DATA "/sdk/" MCPI_SDK_DIR, getenv("HOME")); + safe_asprintf(&output, "%s" HOME_SUBDIRECTORY_FOR_SDK "/" MCPI_SDK_DIR, getenv("HOME")); // Source Directory char *source = NULL; safe_asprintf(&source, "%s/sdk/.", binary_directory); @@ -222,6 +236,10 @@ static void copy_sdk(char *binary_directory) { // Free free(output); free(source); + + // Unlock File + unlock_file(lock_file_path, lock_file_fd); + free(lock_file_path); } // Bootstrap diff --git a/launcher/src/client/cache.cpp b/launcher/src/client/cache.cpp index a340d00fa..70e6369c6 100644 --- a/launcher/src/client/cache.cpp +++ b/launcher/src/client/cache.cpp @@ -30,55 +30,67 @@ launcher_cache load_cache() { // Log DEBUG("Loading Launcher Cache..."); + // Lock File + int lock_fd = lock_file(get_cache_path().c_str()); + + // Return Value + launcher_cache ret = empty_cache; + // Open File std::ifstream stream(get_cache_path(), std::ios::in | std::ios::binary); if (!stream) { - // No Warning If File Doesn't Exist + // Fail struct stat s; + // No Warning If File Doesn't Exist if (stat(get_cache_path().c_str(), &s) == 0) { WARN("Unable To Open Launcher Cache For Loading"); } - return empty_cache; - } - - // Check Version - unsigned char cache_version; - stream.read((char *) &cache_version, 1); - if (stream.eof() || cache_version != (unsigned char) CACHE_VERSION) { - if (!stream.eof()) { - WARN("Invalid Launcher Cache Version (Expected: %i, Actual: %i)", (int) CACHE_VERSION, (int) cache_version); + } else { + // Check Version + unsigned char cache_version; + stream.read((char *) &cache_version, 1); + if (stream.eof() || cache_version != (unsigned char) CACHE_VERSION) { + // Fail + if (!stream.eof()) { + WARN("Invalid Launcher Cache Version (Expected: %i, Actual: %i)", (int) CACHE_VERSION, (int) cache_version); + } else { + WARN("Unable To Read Launcher Cache Version"); + } + stream.close(); } else { - WARN("Unable To Read Launcher Cache Version"); + // Load Username And Render Distance + launcher_cache cache; + std::getline(stream, cache.username, '\0'); + std::getline(stream, cache.render_distance, '\0'); + + // Load Feature Flags + std::string flag; + while (!stream.eof() && std::getline(stream, flag, '\0')) { + if (flag.length() > 0) { + unsigned char is_enabled = 0; + stream.read((char *) &is_enabled, 1); + cache.feature_flags[flag] = is_enabled != (unsigned char) 0; + } + stream.peek(); + } + + // Finish + stream.close(); + if (!stream) { + // Fail + WARN("Failure While Loading Launcher Cache"); + } else { + // Success + ret = cache; + } } - stream.close(); - return empty_cache; } - // Load Username And Render Distance - launcher_cache cache; - std::getline(stream, cache.username, '\0'); - std::getline(stream, cache.render_distance, '\0'); - - // Load Feature Flags - std::string flag; - while (!stream.eof() && std::getline(stream, flag, '\0')) { - if (flag.length() > 0) { - unsigned char is_enabled = 0; - stream.read((char *) &is_enabled, 1); - cache.feature_flags[flag] = is_enabled != (unsigned char) 0; - } - stream.peek(); - } - - // Finish - stream.close(); - if (!stream) { - WARN("Failure While Loading Launcher Cache"); - return empty_cache; - } + // Unlock File + unlock_file(get_cache_path().c_str(), lock_fd); // Return - return cache; + return ret; } // Save @@ -94,51 +106,57 @@ void save_cache() { // Log DEBUG("Saving Launcher Cache..."); + // Lock File + int lock_fd = lock_file(get_cache_path().c_str()); + // Open File std::ofstream stream(get_cache_path(), std::ios::out | std::ios::binary); if (!stream) { + // Fail WARN("Unable To Open Launcher Cache For Saving"); - return; - } + } else { + // Save Cache Version + unsigned char cache_version = (unsigned char) CACHE_VERSION; + stream.write((const char *) &cache_version, 1); - // Save Cache Version - unsigned char cache_version = (unsigned char) CACHE_VERSION; - stream.write((const char *) &cache_version, 1); + // Save Username And Render Distance + write_env_to_stream(stream, "MCPI_USERNAME"); + write_env_to_stream(stream, "MCPI_RENDER_DISTANCE"); - // Save Username And Render Distance - write_env_to_stream(stream, "MCPI_USERNAME"); - write_env_to_stream(stream, "MCPI_RENDER_DISTANCE"); - - // Save Feature Flags - std::unordered_map flags; - load_available_feature_flags([&flags](std::string flag) { - std::string stripped_flag = strip_feature_flag_default(flag, NULL); - flags[stripped_flag] = false; - }); - { - const char *enabled_flags = getenv("MCPI_FEATURE_FLAGS"); - if (enabled_flags == NULL) { - IMPOSSIBLE(); - } - std::istringstream enabled_flags_stream(enabled_flags); - std::string flag; - while (std::getline(enabled_flags_stream, flag, '|')) { - if (flag.length() > 0) { - flags[flag] = true; + // Save Feature Flags + std::unordered_map flags; + load_available_feature_flags([&flags](std::string flag) { + std::string stripped_flag = strip_feature_flag_default(flag, NULL); + flags[stripped_flag] = false; + }); + { + const char *enabled_flags = getenv("MCPI_FEATURE_FLAGS"); + if (enabled_flags == NULL) { + IMPOSSIBLE(); + } + std::istringstream enabled_flags_stream(enabled_flags); + std::string flag; + while (std::getline(enabled_flags_stream, flag, '|')) { + if (flag.length() > 0) { + flags[flag] = true; + } } } - } - for (auto &it : flags) { - stream.write(it.first.c_str(), it.first.size() + 1); - unsigned char val = it.second ? (unsigned char) 1 : (unsigned char) 0; - stream.write((const char *) &val, 1); + for (auto &it : flags) { + stream.write(it.first.c_str(), it.first.size() + 1); + unsigned char val = it.second ? (unsigned char) 1 : (unsigned char) 0; + stream.write((const char *) &val, 1); + } + + // Finish + stream.close(); + if (!stream.good()) { + WARN("Failure While Saving Launcher Cache"); + } } - // Finish - stream.close(); - if (!stream.good()) { - WARN("Failure While Saving Launcher Cache"); - } + // Unlock File + unlock_file(get_cache_path().c_str(), lock_fd); } // Wipe Cache diff --git a/libreborn/include/libreborn/util.h b/libreborn/include/libreborn/util.h index 061b0f5e3..13da7306d 100644 --- a/libreborn/include/libreborn/util.h +++ b/libreborn/include/libreborn/util.h @@ -41,6 +41,10 @@ void safe_pipe2(int pipefd[2], int flags); // Check If Two Percentages Are Different Enough To Be Logged int is_progress_difference_significant(int32_t new_val, int32_t old_val); +// Lock File +int lock_file(const char *file); +void unlock_file(const char *file, int fd); + #ifdef __cplusplus } #endif diff --git a/libreborn/src/util/util.c b/libreborn/src/util/util.c index 98d9dcfbc..0aa32ad2c 100644 --- a/libreborn/src/util/util.c +++ b/libreborn/src/util/util.c @@ -1,3 +1,6 @@ +#include +#include + #include // Safe Version Of pipe() @@ -22,3 +25,21 @@ int is_progress_difference_significant(int32_t new_val, int32_t old_val) { return 0; } } + +// Lock File +int lock_file(const char *file) { + int fd = open(file, O_WRONLY | O_CREAT, S_IWUSR); + if (fd == -1) { + ERR("Unable To Open Lock File: %s: %s", file, strerror(errno)); + } + if (flock(fd, LOCK_EX) == -1) { + ERR("Unable To Lock File: %s: %s", file, strerror(errno)); + } + return fd; +} +void unlock_file(const char *file, int fd) { + if (flock(fd, LOCK_UN) == -1) { + ERR("Unable To Unlock File: %s: %s", file, strerror(errno)); + } + close(fd); +}