From 17e38fd9a17a69dc45296154f75320d3dc8dd172 Mon Sep 17 00:00:00 2001 From: Andrey Nazarov Date: Thu, 5 Sep 2024 18:13:06 +0300 Subject: [PATCH] Lookup some files in homedir only. Some files that are written by engine, like savegames, should never be loaded from base directory. Add FS_DIR_* family of flags to specify whether to lookup file in basedir or homedir only. Also simplify management of FS_PATH_* flags. Add default_lookup_flags() to avoid manipulating searchpath flags in setup_game_paths(). --- inc/shared/files.h | 10 ++++-- src/client/ui/demos.c | 2 +- src/common/files.c | 72 ++++++++++++++++++++++--------------------- src/common/prompt.c | 2 +- src/server/save.c | 15 +++++---- 5 files changed, 56 insertions(+), 45 deletions(-) diff --git a/inc/shared/files.h b/inc/shared/files.h index 276298b1e..9ec210e1b 100644 --- a/inc/shared/files.h +++ b/inc/shared/files.h @@ -39,13 +39,13 @@ typedef struct { #define FS_BUF_NONE 0x0000000c // unbuffered #define FS_BUF_MASK 0x0000000c -// where to open file from +// where to open file from (packfile vs disk) #define FS_TYPE_ANY 0x00000000 // open from anywhere #define FS_TYPE_REAL 0x00000010 // open from disk only #define FS_TYPE_PAK 0x00000020 // open from pack only #define FS_TYPE_MASK 0x00000030 -// where to look for a file +// where to look for a file (baseq2 vs gamedir) #define FS_PATH_ANY 0x00000000 // look in any search paths #define FS_PATH_BASE 0x00000040 // look in base search paths #define FS_PATH_GAME 0x00000080 // look in game search paths @@ -67,3 +67,9 @@ typedef struct { #define FS_FLAG_DEFLATE 0x00000800 // if compressed, read raw deflate data, fail otherwise #define FS_FLAG_LOADFILE 0x00001000 // open non-unique handle, must be closed very quickly #define FS_FLAG_MASK 0x0000ff00 + +// where to look for a file (basedir vs homedir) +#define FS_DIR_ANY 0x00000000 // look anywhere +#define FS_DIR_BASE 0x00010000 // look in basedir +#define FS_DIR_HOME 0x00020000 // look in homedir +#define FS_DIR_MASK 0x00030000 diff --git a/src/client/ui/demos.c b/src/client/ui/demos.c index 47fb1c5cd..0d26d0b7b 100644 --- a/src/client/ui/demos.c +++ b/src/client/ui/demos.c @@ -167,7 +167,7 @@ static char *LoadCache(void **list) if (Q_concat(buffer, sizeof(buffer), m_demos.browse, "/" COM_DEMOCACHE_NAME) >= sizeof(buffer)) { return NULL; } - len = FS_LoadFileEx(buffer, (void **)&cache, FS_TYPE_REAL | FS_PATH_GAME, TAG_FILESYSTEM); + len = FS_LoadFileEx(buffer, (void **)&cache, FS_TYPE_REAL | FS_PATH_GAME | FS_DIR_HOME, TAG_FILESYSTEM); if (!cache) { return NULL; } diff --git a/src/common/files.c b/src/common/files.c index 076169a91..8b6c467cd 100644 --- a/src/common/files.c +++ b/src/common/files.c @@ -1333,10 +1333,9 @@ static int64_t open_file_read(file_t *file, const char *normalized, size_t namel // search through the path, one element at a time for (search = fs_searchpaths; search; search = search->next) { - if (file->mode & FS_PATH_MASK) { - if ((file->mode & search->mode & FS_PATH_MASK) == 0) { - continue; - } + if ((file->mode & search->mode & FS_PATH_MASK) == 0 || + (file->mode & search->mode & FS_DIR_MASK ) == 0) { + continue; } // is the element a pak file? @@ -1637,6 +1636,17 @@ int FS_Write(const void *buf, size_t len, qhandle_t f) return len; } +static unsigned default_lookup_flags(unsigned flags) +{ + if (!(flags & FS_PATH_MASK) || !fs_game->string[0]) + flags |= FS_PATH_MASK; + + if (!(flags & FS_DIR_MASK) || !sys_homedir->string[0]) + flags |= FS_DIR_MASK; + + return flags; +} + /* ============ FS_OpenFile @@ -1663,7 +1673,7 @@ int64_t FS_OpenFile(const char *name, qhandle_t *f, unsigned mode) return Q_ERR(EMFILE); } - file->mode = mode; + file->mode = default_lookup_flags(mode); if ((mode & FS_MODE_MASK) == FS_MODE_READ) { ret = expand_open_file_read(file, name); @@ -1841,13 +1851,17 @@ int FS_LoadFileEx(const char *path, void **buffer, unsigned flags, memtag_t tag) return Q_ERR(EAGAIN); // not yet initialized } + if (flags & FS_MODE_MASK) { + return Q_ERR(EINVAL); + } + // allocate new file handle file = alloc_handle(&f); if (!file) { return Q_ERR(EMFILE); } - file->mode = (flags & ~FS_MODE_MASK) | FS_MODE_READ | FS_FLAG_LOADFILE; + file->mode = default_lookup_flags(flags) | FS_MODE_READ | FS_FLAG_LOADFILE; // look for it in the filesystem or pack files len = expand_open_file_read(file, path); @@ -2756,6 +2770,10 @@ void **FS_ListFiles(const char *path, const char *filter, unsigned flags, int *c *count_p = 0; } + if (!fs_searchpaths) { + return NULL; // not yet initialized + } + if (!path) { path = ""; pathlen = 0; @@ -2774,11 +2792,12 @@ void **FS_ListFiles(const char *path, const char *filter, unsigned flags, int *c return NULL; } + flags = default_lookup_flags(flags); + for (search = fs_searchpaths; search; search = search->next) { - if (flags & FS_PATH_MASK) { - if ((flags & search->mode & FS_PATH_MASK) == 0) { - continue; - } + if ((flags & search->mode & FS_PATH_MASK) == 0 || + (flags & search->mode & FS_DIR_MASK ) == 0) { + continue; } if (search->pack) { if ((flags & FS_TYPE_MASK) == FS_TYPE_REAL) { @@ -3509,7 +3528,7 @@ static void add_game_kpf(const char *dir) return; search = FS_Malloc(sizeof(*search)); - search->mode = FS_PATH_BASE | FS_PATH_GAME; + search->mode = FS_PATH_BASE | FS_DIR_BASE; search->filename[0] = 0; search->pack = pack_get(pack); search->next = fs_searchpaths; @@ -3519,14 +3538,11 @@ static void add_game_kpf(const char *dir) static void setup_base_paths(void) { - // base paths have both BASE and GAME bits set by default - // the GAME bit will be removed once gamedir is set, - // and will be put back once gamedir is reset to basegame add_game_kpf(sys_basedir->string); - add_game_dir(FS_PATH_BASE | FS_PATH_GAME, "%s/"BASEGAME, sys_basedir->string); + add_game_dir(FS_PATH_BASE | FS_DIR_BASE, "%s/"BASEGAME, sys_basedir->string); if (sys_homedir->string[0]) { - add_game_dir(FS_PATH_BASE | FS_PATH_GAME, "%s/"BASEGAME, sys_homedir->string); + add_game_dir(FS_PATH_BASE | FS_DIR_HOME, "%s/"BASEGAME, sys_homedir->string); } fs_base_searchpaths = fs_searchpaths; @@ -3535,33 +3551,19 @@ static void setup_base_paths(void) // Sets the gamedir and path to a different directory. static void setup_game_paths(void) { - searchpath_t *path; - if (fs_game->string[0]) { // add system path first - add_game_dir(FS_PATH_GAME, "%s/%s", sys_basedir->string, fs_game->string); + add_game_dir(FS_PATH_GAME | FS_DIR_BASE, "%s/%s", sys_basedir->string, fs_game->string); // home paths override system paths if (sys_homedir->string[0]) { - add_game_dir(FS_PATH_GAME, "%s/%s", sys_homedir->string, fs_game->string); + add_game_dir(FS_PATH_GAME | FS_DIR_HOME, "%s/%s", sys_homedir->string, fs_game->string); } - - // remove the game bit from base paths - for (path = fs_base_searchpaths; path; path = path->next) { - path->mode &= ~FS_PATH_GAME; - } - - // this var is set for compatibility with server browsers, etc - Cvar_FullSet("gamedir", fs_game->string, CVAR_ROM | CVAR_SERVERINFO, FROM_CODE); - } else { - // add the game bit to base paths - for (path = fs_base_searchpaths; path; path = path->next) { - path->mode |= FS_PATH_GAME; - } - - Cvar_FullSet("gamedir", "", CVAR_ROM, FROM_CODE); } + // this var is set for compatibility with server browsers, etc + Cvar_FullSet("gamedir", fs_game->string, CVAR_ROM | CVAR_SERVERINFO, FROM_CODE); + // this var is used by the game library to find it's home directory Cvar_FullSet("fs_gamedir", fs_gamedir, CVAR_ROM, FROM_CODE); } diff --git a/src/common/prompt.c b/src/common/prompt.c index 73a11fe77..1acd2fdbe 100644 --- a/src/common/prompt.c +++ b/src/common/prompt.c @@ -545,7 +545,7 @@ void Prompt_LoadHistory(commandPrompt_t *prompt, const char *filename) qhandle_t f; unsigned i; - FS_OpenFile(filename, &f, FS_MODE_READ | FS_TYPE_REAL | FS_PATH_BASE); + FS_OpenFile(filename, &f, FS_MODE_READ | FS_TYPE_REAL | FS_PATH_BASE | FS_DIR_HOME); if (!f) { return; } diff --git a/src/server/save.c b/src/server/save.c index d7757d063..a6bac3437 100644 --- a/src/server/save.c +++ b/src/server/save.c @@ -25,6 +25,9 @@ with this program; if not, write to the Free Software Foundation, Inc., #define SAVE_CURRENT ".current" #define SAVE_AUTO "save0" +// only load saves from home dir +#define SAVE_LOOKUP_FLAGS (FS_TYPE_REAL | FS_PATH_GAME | FS_DIR_HOME) + typedef enum { SAVE_MANUAL, // manual save SAVE_LEVEL_START, // autosave at level start @@ -203,7 +206,7 @@ static int remove_file(const char *dir, const char *name) static void **list_save_dir(const char *dir, int *count) { return FS_ListFiles(va("save/%s", dir), ".ssv;.sav;.sv2", - FS_TYPE_REAL | FS_PATH_GAME | FS_SEARCH_RECURSIVE, count); + SAVE_LOOKUP_FLAGS | FS_SEARCH_RECURSIVE, count); } static int wipe_save_dir(const char *dir) @@ -241,7 +244,7 @@ static int read_binary_file(const char *name) qhandle_t f; int64_t len; - len = FS_OpenFile(name, &f, FS_MODE_READ | FS_TYPE_REAL | FS_PATH_GAME); + len = FS_OpenFile(name, &f, SAVE_LOOKUP_FLAGS | FS_MODE_READ); if (!f) return -1; @@ -406,7 +409,7 @@ static int read_level_file(void) if (Q_snprintf(name, MAX_QPATH, "save/" SAVE_CURRENT "/%s.sv2", sv.name) >= MAX_QPATH) return -1; - len = FS_LoadFileEx(name, &data, FS_TYPE_REAL | FS_PATH_GAME, TAG_SERVER); + len = FS_LoadFileEx(name, &data, SAVE_LOOKUP_FLAGS, TAG_SERVER); if (!data) return -1; @@ -592,7 +595,7 @@ void SV_CheckForEnhancedSavegames(void) static void SV_Savegame_c(genctx_t *ctx, int argnum) { if (argnum == 1) { - FS_File_g("save", NULL, FS_SEARCH_DIRSONLY | FS_TYPE_REAL | FS_PATH_GAME, ctx); + FS_File_g("save", NULL, SAVE_LOOKUP_FLAGS | FS_SEARCH_DIRSONLY, ctx); } } @@ -612,8 +615,8 @@ static void SV_Loadgame_f(void) } // make sure the server files exist - if (!FS_FileExistsEx(va("save/%s/server.ssv", dir), FS_TYPE_REAL | FS_PATH_GAME) || - !FS_FileExistsEx(va("save/%s/game.ssv", dir), FS_TYPE_REAL | FS_PATH_GAME)) { + if (!FS_FileExistsEx(va("save/%s/server.ssv", dir), SAVE_LOOKUP_FLAGS) || + !FS_FileExistsEx(va("save/%s/game.ssv", dir), SAVE_LOOKUP_FLAGS)) { Com_Printf("No such savegame: %s\n", dir); return; }