diff --git a/layeredfs/hook.cpp b/layeredfs/hook.cpp index eb3618b..e89358a 100644 --- a/layeredfs/hook.cpp +++ b/layeredfs/hook.cpp @@ -16,6 +16,7 @@ using std::string; #include #include #include +#include #include "3rd_party/MinHook.h" #pragma comment(lib, "minhook.lib") @@ -37,7 +38,7 @@ using std::string; #undef max #undef min -#define VER_STRING "2.0" +#define VER_STRING "2.1" #ifdef _DEBUG #define DBG_VER_STRING "_DEBUG" @@ -75,7 +76,8 @@ typedef struct image { } image_t; // ifs_textures["data/graphics/ver04/logo.ifs/tex/4f754d4f424f092637a49a5527ece9bb"] will be "konami" -std::unordered_map ifs_textures; +static std::unordered_map ifs_textures; +static std::mutex ifs_textures_mtx; typedef std::unordered_set string_set; @@ -234,7 +236,9 @@ bool add_images_to_list(string_set &extra_pngs, rapidxml::xml_node<> *texturelis image_info.height = texture->height; auto md5_path = ifs_path + "/tex/" + image_info.name_md5; + ifs_textures_mtx.lock(); ifs_textures[md5_path] = image_info; + ifs_textures_mtx.unlock(); } } @@ -340,7 +344,9 @@ void parse_texturelist(string const&path, string const&norm_path, optional &mod_path) { + ifs_textures_mtx.lock(); auto tex_search = ifs_textures.find(norm_path); if (tex_search == ifs_textures.end()) { + ifs_textures_mtx.unlock(); return; } //logf("Mapped file %s is found!", norm_path.c_str()); auto tex = tex_search->second; + ifs_textures_mtx.unlock(); // is it safe to unlock this early? Time will tell... // remove the /tex/, it's nicer to navigate auto png_path = find_first_modfile(tex.ifs_mod_path + "/" + tex.name + ".png"); diff --git a/layeredfs/modpath_handler.cpp b/layeredfs/modpath_handler.cpp index 62b60f0..570e87f 100644 --- a/layeredfs/modpath_handler.cpp +++ b/layeredfs/modpath_handler.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include "ramfs_demangler.h" @@ -79,18 +80,26 @@ void cache_mods(void) { // data, data2, data_op2 etc // data is "flat", all others must have their own special subfolders static vector game_folders; +static std::mutex game_folders_mtx; optional normalise_path(string &path) { // one-off init if (game_folders.empty()) { - for (auto folder : folders_in_folder(".")) { - // data is the normal case we transparently handle - if (!strcmp(folder.c_str(), "data")) { - continue; - } + game_folders_mtx.lock(); + + // check again in case init was raced + if (game_folders.empty()) { + for (auto folder : folders_in_folder(".")) { + // data is the normal case we transparently handle + if (!strcmp(folder.c_str(), "data")) { + continue; + } - game_folders.push_back(folder + "/"); + game_folders.push_back(folder + "/"); + } } + game_folders_mtx.unlock(); + // all access past here is read-only, don't use the mutex any more } ramfs_demangler_demangle_if_possible(path); diff --git a/layeredfs/ramfs_demangler.cpp b/layeredfs/ramfs_demangler.cpp index 4a7cb31..7b4dca2 100644 --- a/layeredfs/ramfs_demangler.cpp +++ b/layeredfs/ramfs_demangler.cpp @@ -32,6 +32,7 @@ #include #include +#include #include #include "3rd_party/hat-trie/htrie_map.h" @@ -48,18 +49,22 @@ typedef struct { optional mounted_path; } file_cleanup_info_t; -unordered_map cleanup_map; -unordered_map open_file_map; -unordered_map ram_load_map; +static unordered_map cleanup_map; +static unordered_map open_file_map; +static unordered_map ram_load_map; // using tries for fast prefix matches on our mangled names -tsl::htrie_map ramfs_map; -tsl::htrie_map mangling_map; +static tsl::htrie_map ramfs_map; +static tsl::htrie_map mangling_map; + +static std::mutex mangling_mtx; void ramfs_demangler_on_fs_open(const std::string& norm_path, AVS_FILE open_result) { if (open_result < 0 || !string_ends_with(norm_path.c_str(), ".ifs")) { return; } + const std::lock_guard lock(mangling_mtx); + auto existing_info = cleanup_map.find(norm_path); if (existing_info != cleanup_map.end()) { file_cleanup_info_t cleanup = existing_info->second; @@ -87,6 +92,8 @@ void ramfs_demangler_on_fs_open(const std::string& norm_path, AVS_FILE open_resu } void ramfs_demangler_on_fs_read(AVS_FILE context, void* dest) { + const std::lock_guard lock(mangling_mtx); + auto find = open_file_map.find(context); if (find != open_file_map.end()) { auto path = find->second; @@ -102,6 +109,8 @@ void ramfs_demangler_on_fs_read(AVS_FILE context, void* dest) { } void ramfs_demangler_on_fs_mount(const char* mountpoint, const char* fsroot, const char* fstype, const char* flags) { + const std::lock_guard lock(mangling_mtx); + if (!strcmp(fstype, "ramfs")) { void* buffer; @@ -150,6 +159,8 @@ void ramfs_demangler_on_fs_mount(const char* mountpoint, const char* fsroot, con } void ramfs_demangler_demangle_if_possible(std::string& raw_path) { + const std::lock_guard lock(mangling_mtx); + auto search = mangling_map.longest_prefix(raw_path); if (search != mangling_map.end()) { //logf_verbose("can demangle %s to %s", search.key().c_str(), search->c_str()); diff --git a/layeredfs/utils.cpp b/layeredfs/utils.cpp index 7046af2..e5cf41d 100644 --- a/layeredfs/utils.cpp +++ b/layeredfs/utils.cpp @@ -1,9 +1,12 @@ #include "utils.h" #include "avs.h" +#include + #define SUPPRESS_PRINTF void logf(char* fmt, ...) { + static std::mutex log_mutex; static FILE* logfile = NULL; static bool tried_to_open = false; va_list args; @@ -14,11 +17,17 @@ void logf(char* fmt, ...) { printf("\n"); #endif // don't reopen every time: slow as shit - if (!logfile && !tried_to_open) { - fopen_s(&logfile, "ifs_hook.log", "w"); + if (!tried_to_open) { + const std::lock_guard lock(log_mutex); + + if (!logfile) { + fopen_s(&logfile, "ifs_hook.log", "w"); + } tried_to_open = true; } if (logfile) { + const std::lock_guard lock(log_mutex); + va_start(args, fmt); vfprintf(logfile, fmt, args); va_end(args);