From 722927caa75b9c5b9c1638f94fef961c7deb6572 Mon Sep 17 00:00:00 2001 From: icex2 Date: Wed, 8 Mar 2023 17:47:06 +0100 Subject: [PATCH] iidxhook-util: Add option to configure path for storing settings Additional flexibility to cover use-cases like storing this data on a separate partition which keeps the game data folder clean and read-only. --- src/main/iidxhook-util/settings.c | 104 ++++++++++++++++++++++++------ src/main/iidxhook-util/settings.h | 15 ++++- 2 files changed, 96 insertions(+), 23 deletions(-) diff --git a/src/main/iidxhook-util/settings.c b/src/main/iidxhook-util/settings.c index 40933b1..761b3f8 100644 --- a/src/main/iidxhook-util/settings.c +++ b/src/main/iidxhook-util/settings.c @@ -13,6 +13,7 @@ #include "util/defs.h" #include "util/fs.h" #include "util/log.h" +#include "util/mem.h" #include "util/str.h" /* ------------------------------------------------------------------------- */ @@ -32,6 +33,24 @@ static const struct hook_symbol settings_hook_syms[] = { }; static bool settings_folders_checked; +static char settings_path[MAX_PATH] = ".\\"; + +/* ------------------------------------------------------------------------- */ + +static void settings_build_new_path(const char* orig_path, char* new_path, size_t new_path_len) +{ + size_t settings_path_len; + + settings_path_len = strlen(settings_path); + + log_assert(settings_path_len + strlen(orig_path) < new_path_len); + + strcpy(new_path, settings_path); + strcat(new_path, orig_path); + + /* Remove : of drive letter. Multiple \ are fine and handled by windows */ + new_path[settings_path_len + 1] = '\\'; +} /* ------------------------------------------------------------------------- */ @@ -44,8 +63,8 @@ BOOL WINAPI my_CreateDirectoryA( lpPathName[1] == ':') { char new_path[MAX_PATH]; - strcpy(new_path, lpPathName); - new_path[1] = '\\'; + settings_build_new_path(lpPathName, new_path, sizeof(new_path)); + log_misc("(CreateDir) Remapped settings path %s", new_path); return real_CreateDirectoryA(new_path, lpSecurityAttributes); @@ -61,43 +80,88 @@ void settings_hook_init(void) hook_table_apply( NULL, "kernel32.dll", settings_hook_syms, lengthof(settings_hook_syms)); - log_info("Inserted settings hooks"); + log_info("Inserted settings hooks, settings path: %s", settings_path); +} + +void settings_hook_set_path(const char* path) +{ + size_t len; + + len = strlen(path); + + log_assert(path > 0); + log_assert(len < MAX_PATH); + + strcpy(settings_path, path); + + /* Ensure trailing \\ to allow simple concatinations in hooks */ + if (settings_path[len - 1] != '\\') { + log_assert(len + 1 < MAX_PATH); + + settings_path[len] = '\\'; + settings_path[len + 1] = '\0'; + } + + log_info("Settings path: %s", settings_path); } HRESULT settings_hook_dispatch_irp(struct irp *irp) { if (irp->op == IRP_OP_OPEN && - (irp->open_filename[0] == L'd' || irp->open_filename[0] == L'e' || - irp->open_filename[0] == L'f') && - irp->open_filename[1] == L':') { - char *log_str; + (irp->open_filename[0] == L'd' || irp->open_filename[0] == L'e' || + irp->open_filename[0] == L'f') && + irp->open_filename[1] == L':') { + HRESULT result; + char new_path[MAX_PATH]; + const wchar_t *old_filename_wstr; + wchar_t *filename_wstr; + char *filename_cstr; - ((wchar_t *) irp->open_filename)[1] = L'\\'; + log_assert(wstr_narrow(irp->open_filename, &filename_cstr)); - wstr_narrow(irp->open_filename, &log_str); - log_misc("Remapped settings path %s", log_str); - free(log_str); + settings_build_new_path(filename_cstr, new_path, sizeof(new_path)); - /* Create local settings folders if not available */ + free(filename_cstr); + + log_misc("Remapped settings path to %s", new_path); + + filename_wstr = str_widen(new_path); + + /* Temporarily swap open_filename */ + old_filename_wstr = irp->open_filename; + irp->open_filename = filename_wstr; + + /* Create settings folders if not available */ if (!settings_folders_checked) { settings_folders_checked = true; for (char c = 'd'; c <= 'f'; c++) { - char str[3]; + char new_path_folder[MAX_PATH]; + size_t settings_path_len = strlen(settings_path); - str[0] = c; - str[1] = '\\'; - str[2] = '\0'; + log_assert(settings_path_len + 3 < MAX_PATH); - if (!path_exists(str)) { - log_misc("Creating local settings folder %s\\", str); - CreateDirectoryA(str, NULL); + strcpy(new_path_folder, settings_path); + + new_path_folder[settings_path_len] = c; + new_path_folder[settings_path_len + 1] = '\\'; + new_path_folder[settings_path_len + 2] = '\0'; + + if (!path_exists(new_path_folder)) { + log_misc("Creating local settings folder %s", new_path_folder); + CreateDirectoryA(new_path_folder, NULL); } } } - return iohook_invoke_next(irp); + result = iohook_invoke_next(irp); + + /* Revert to original irp */ + irp->open_filename = old_filename_wstr; + free(filename_wstr); + + return result; } return iohook_invoke_next(irp); diff --git a/src/main/iidxhook-util/settings.h b/src/main/iidxhook-util/settings.h index 17dce31..5632f8d 100644 --- a/src/main/iidxhook-util/settings.h +++ b/src/main/iidxhook-util/settings.h @@ -4,12 +4,21 @@ #include "hook/iohook.h" /** - * Remaps the paths for the settings drives d:\, e:\ and f:\ - * to local folders e\ and f\. - * Needed on IIDX 9th to Sirius. + * Remaps the paths for storing "settings data" that are usually stored on the + * drives d:\, e:\ and f:\ by the game. This defaults to the local folders + * d\, e\ and f\. + * + * Required hook for 9th to Lincle. */ void settings_hook_init(void); +/** + * Change the path where settings file are stored. + * + * @param path Destination path for storage, relative or absolute. + */ +void settings_hook_set_path(const char* path); + /** * iohook dispatch function */