Use File Locking

This commit is contained in:
TheBrokenRail 2022-09-25 19:35:51 -04:00
parent bedd5ea53a
commit 703ced337b
4 changed files with 133 additions and 72 deletions

View File

@ -193,10 +193,24 @@ void run_simple_command(const char *const command[], const char *error) {
ERR("%s", error); ERR("%s", error);
} }
} }
#define HOME_SUBDIRECTORY_FOR_SDK HOME_SUBDIRECTORY_FOR_GAME_DATA "/sdk"
static void copy_sdk(char *binary_directory) { 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 // Output Directory
char *output = NULL; 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 // Source Directory
char *source = NULL; char *source = NULL;
safe_asprintf(&source, "%s/sdk/.", binary_directory); safe_asprintf(&source, "%s/sdk/.", binary_directory);
@ -222,6 +236,10 @@ static void copy_sdk(char *binary_directory) {
// Free // Free
free(output); free(output);
free(source); free(source);
// Unlock File
unlock_file(lock_file_path, lock_file_fd);
free(lock_file_path);
} }
// Bootstrap // Bootstrap

View File

@ -30,55 +30,67 @@ launcher_cache load_cache() {
// Log // Log
DEBUG("Loading Launcher Cache..."); 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 // Open File
std::ifstream stream(get_cache_path(), std::ios::in | std::ios::binary); std::ifstream stream(get_cache_path(), std::ios::in | std::ios::binary);
if (!stream) { if (!stream) {
// No Warning If File Doesn't Exist // Fail
struct stat s; struct stat s;
// No Warning If File Doesn't Exist
if (stat(get_cache_path().c_str(), &s) == 0) { if (stat(get_cache_path().c_str(), &s) == 0) {
WARN("Unable To Open Launcher Cache For Loading"); WARN("Unable To Open Launcher Cache For Loading");
} }
return empty_cache; } else {
} // Check Version
unsigned char cache_version;
// Check Version stream.read((char *) &cache_version, 1);
unsigned char cache_version; if (stream.eof() || cache_version != (unsigned char) CACHE_VERSION) {
stream.read((char *) &cache_version, 1); // Fail
if (stream.eof() || cache_version != (unsigned char) CACHE_VERSION) { if (!stream.eof()) {
if (!stream.eof()) { WARN("Invalid Launcher Cache Version (Expected: %i, Actual: %i)", (int) CACHE_VERSION, (int) cache_version);
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 { } 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 // Unlock File
launcher_cache cache; unlock_file(get_cache_path().c_str(), lock_fd);
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;
}
// Return // Return
return cache; return ret;
} }
// Save // Save
@ -94,51 +106,57 @@ void save_cache() {
// Log // Log
DEBUG("Saving Launcher Cache..."); DEBUG("Saving Launcher Cache...");
// Lock File
int lock_fd = lock_file(get_cache_path().c_str());
// Open File // Open File
std::ofstream stream(get_cache_path(), std::ios::out | std::ios::binary); std::ofstream stream(get_cache_path(), std::ios::out | std::ios::binary);
if (!stream) { if (!stream) {
// Fail
WARN("Unable To Open Launcher Cache For Saving"); 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 // Save Username And Render Distance
unsigned char cache_version = (unsigned char) CACHE_VERSION; write_env_to_stream(stream, "MCPI_USERNAME");
stream.write((const char *) &cache_version, 1); write_env_to_stream(stream, "MCPI_RENDER_DISTANCE");
// Save Username And Render Distance // Save Feature Flags
write_env_to_stream(stream, "MCPI_USERNAME"); std::unordered_map<std::string, bool> flags;
write_env_to_stream(stream, "MCPI_RENDER_DISTANCE"); load_available_feature_flags([&flags](std::string flag) {
std::string stripped_flag = strip_feature_flag_default(flag, NULL);
// Save Feature Flags flags[stripped_flag] = false;
std::unordered_map<std::string, bool> flags; });
load_available_feature_flags([&flags](std::string flag) { {
std::string stripped_flag = strip_feature_flag_default(flag, NULL); const char *enabled_flags = getenv("MCPI_FEATURE_FLAGS");
flags[stripped_flag] = false; if (enabled_flags == NULL) {
}); IMPOSSIBLE();
{ }
const char *enabled_flags = getenv("MCPI_FEATURE_FLAGS"); std::istringstream enabled_flags_stream(enabled_flags);
if (enabled_flags == NULL) { std::string flag;
IMPOSSIBLE(); while (std::getline(enabled_flags_stream, flag, '|')) {
} if (flag.length() > 0) {
std::istringstream enabled_flags_stream(enabled_flags); flags[flag] = true;
std::string flag; }
while (std::getline(enabled_flags_stream, flag, '|')) {
if (flag.length() > 0) {
flags[flag] = true;
} }
} }
} for (auto &it : flags) {
for (auto &it : flags) { stream.write(it.first.c_str(), it.first.size() + 1);
stream.write(it.first.c_str(), it.first.size() + 1); unsigned char val = it.second ? (unsigned char) 1 : (unsigned char) 0;
unsigned char val = it.second ? (unsigned char) 1 : (unsigned char) 0; stream.write((const char *) &val, 1);
stream.write((const char *) &val, 1); }
// Finish
stream.close();
if (!stream.good()) {
WARN("Failure While Saving Launcher Cache");
}
} }
// Finish // Unlock File
stream.close(); unlock_file(get_cache_path().c_str(), lock_fd);
if (!stream.good()) {
WARN("Failure While Saving Launcher Cache");
}
} }
// Wipe Cache // Wipe Cache

View File

@ -41,6 +41,10 @@ void safe_pipe2(int pipefd[2], int flags);
// Check If Two Percentages Are Different Enough To Be Logged // Check If Two Percentages Are Different Enough To Be Logged
int is_progress_difference_significant(int32_t new_val, int32_t old_val); 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 #ifdef __cplusplus
} }
#endif #endif

View File

@ -1,3 +1,6 @@
#include <fcntl.h>
#include <sys/file.h>
#include <libreborn/util.h> #include <libreborn/util.h>
// Safe Version Of pipe() // Safe Version Of pipe()
@ -22,3 +25,21 @@ int is_progress_difference_significant(int32_t new_val, int32_t old_val) {
return 0; 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);
}