From 5d4f66cffd078f9f560e17a8e077c31e076e73b6 Mon Sep 17 00:00:00 2001 From: Spoike Date: Tue, 27 Oct 2020 02:56:18 +0000 Subject: [PATCH] Add SB_MULTISEARCH flag for search_begin. git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5782 fc73d0e0-1445-4013-8a0c-d673dee63da5 --- engine/common/fs.c | 60 +++++++++++++++++++++++++++++++++++----- engine/common/pr_bgcmd.c | 11 ++++---- engine/server/pr_cmds.c | 8 +++++- 3 files changed, 66 insertions(+), 13 deletions(-) diff --git a/engine/common/fs.c b/engine/common/fs.c index 3c9c98261..ebe3a93ae 100644 --- a/engine/common/fs.c +++ b/engine/common/fs.c @@ -2671,9 +2671,55 @@ void FS_FreeFile(void *file) BZ_Free(file); } +//handle->EnumerateFiles on each a:b:c part of the given matches string. +static qboolean FS_EnumerateFilesEach(searchpathfuncs_t *handle, char *matches, int (QDECL *func)(const char *fname, qofs_t fsize, time_t mtime, void *parm, searchpathfuncs_t *spath), void *parm) +{ + char cleanpath[MAX_QPATH]; + const char *match; + char *sep; + for (; matches; matches = sep) + { + sep = strchr(matches, ':'); + if (sep) + { + *sep = 0; + match = FS_GetCleanPath(matches, true, cleanpath, sizeof(cleanpath)); + *sep++ = ':'; + } + else + match = FS_GetCleanPath(matches, true, cleanpath, sizeof(cleanpath)); -searchpathfuncs_t *COM_EnumerateFilesPackage (const char *match, const char *package, unsigned int flags, int (QDECL *func)(const char *, qofs_t, time_t mtime, void *, searchpathfuncs_t*), void *parm) -{ //special version that takes an explicit package name to search inside. + if (match && *match) + if (!handle->EnumerateFiles(handle, match, func, parm)) + return false; + } + return true; +} +static int FS_EnumerateFilesEachSys (const char *syspath, char *matches, int (*func)(const char *, qofs_t, time_t modtime, void *, searchpathfuncs_t *), void *parm, searchpathfuncs_t *spath) +{ + char cleanpath[MAX_QPATH]; + const char *match; + char *sep; + for (; matches; matches = sep) + { + sep = strchr(matches, ':'); + if (sep) + { + *sep = 0; + match = FS_GetCleanPath(matches, true, cleanpath, sizeof(cleanpath)); + *sep++ = ':'; + } + else + match = FS_GetCleanPath(matches, true, cleanpath, sizeof(cleanpath)); + + if (!Sys_EnumerateFiles(syspath, match, func, parm, spath)) + return false; + } + return true; +} +searchpathfuncs_t *COM_EnumerateFilesPackage (char *matches, const char *package, unsigned int flags, int (QDECL *func)(const char *, qofs_t, time_t mtime, void *, searchpathfuncs_t*), void *parm) +{ //special version of COM_EnumerateFiles that takes an explicit package name to search inside. + //additionally accepts multiple patterns (separated by : chsrs) searchpathfuncs_t *handle; searchpath_t *search; const char *sp; @@ -2696,8 +2742,8 @@ searchpathfuncs_t *COM_EnumerateFilesPackage (const char *match, const char *pac continue; //ignore this package } foundpackage = true; - // is the element a pak file? - if (!search->handle->EnumerateFiles(search->handle, match, func, parm)) + + if (!FS_EnumerateFilesEach(search->handle, matches, func, parm)) break; } @@ -2733,7 +2779,7 @@ searchpathfuncs_t *COM_EnumerateFilesPackage (const char *match, const char *pac } if (handle) - handle->EnumerateFiles(handle, match, func, parm); + FS_EnumerateFilesEach(handle, matches, func, parm); return handle; //caller can use this for context, but is expected to tidy it up too. } else @@ -2744,11 +2790,11 @@ searchpathfuncs_t *COM_EnumerateFilesPackage (const char *match, const char *pac if (com_homepathenabled) { Q_snprintfz(syspath, sizeof(syspath), "%s%s", com_homepath, package); - Sys_EnumerateFiles(syspath, match, func, parm, NULL); + FS_EnumerateFilesEachSys(syspath, matches, func, parm, NULL); } Q_snprintfz(syspath, sizeof(syspath), "%s%s", com_gamepath, package); - Sys_EnumerateFiles(syspath, match, func, parm, NULL); + FS_EnumerateFilesEachSys(syspath, matches, func, parm, NULL); } } return NULL; diff --git a/engine/common/pr_bgcmd.c b/engine/common/pr_bgcmd.c index a8f0f9beb..94a1c7f6b 100644 --- a/engine/common/pr_bgcmd.c +++ b/engine/common/pr_bgcmd.c @@ -3037,12 +3037,13 @@ void QCBUILTIN PF_whichpack (pubprogfuncs_t *prinst, struct globalvars_s *pr_glo enum { - QCSEARCH_INSENSITIVE = 1u<<0, //for dp, we're always insensitive you prick. +// QCSEARCH_INSENSITIVE = 1u<<0, //for dp, we're always insensitive you prick. QCSEARCH_FULLPACKAGE = 1u<<1, //package names include gamedir prefix etc. QCSEARCH_ALLOWDUPES = 1u<<2, //don't filter out dupes, allowing entries hidden by later packages to be shown. QCSEARCH_FORCESEARCH = 1u<<3, //force the search to succeed even if the gamedir/package is not active. + QCSEARCH_MULTISEARCH = 1u<<4, //to avoid possible string manipulation exploits? }; -searchpathfuncs_t *COM_EnumerateFilesPackage (const char *match, const char *package, unsigned int flags, int (QDECL *func)(const char *, qofs_t, time_t mtime, void *, searchpathfuncs_t*), void *parm); +searchpathfuncs_t *COM_EnumerateFilesPackage (char *matches, const char *package, unsigned int flags, int (QDECL *func)(const char *, qofs_t, time_t mtime, void *, searchpathfuncs_t*), void *parm); typedef struct prvmsearch_s { pubprogfuncs_t *fromprogs; //share across menu/server @@ -3142,7 +3143,7 @@ static int QDECL search_enumerate(const char *name, qofs_t fsize, time_t mtime, return true; } -//float search_begin(string pattern, float caseinsensitive, float quiet) = #74; +//float search_begin(string pattern, float flags, float quiet) = #74; void QCBUILTIN PF_search_begin (pubprogfuncs_t *prinst, struct globalvars_s *pr_globals) { //< 0 for error, >= 0 for handle. //error includes bad search patterns, but not no files @@ -3153,7 +3154,7 @@ void QCBUILTIN PF_search_begin (pubprogfuncs_t *prinst, struct globalvars_s *pr_ prvmsearch_t *s; size_t j; - if (!*pattern || (*pattern == '.' && pattern[1] == '.') || *pattern == '/' || *pattern == '\\' || strchr(pattern, ':')) + if (!*pattern || (*pattern == '.' && pattern[1] == '.') || *pattern == '/' || *pattern == '\\' || (!(flags&QCSEARCH_MULTISEARCH)&&strchr(pattern, ':'))) { PF_Warningf(prinst, "PF_search_begin: bad search pattern \"%s\"\n", pattern); G_FLOAT(OFS_RETURN) = -1; @@ -3183,7 +3184,7 @@ void QCBUILTIN PF_search_begin (pubprogfuncs_t *prinst, struct globalvars_s *pr_ s->fsflags |= WP_FORCE; Q_strncpyz(s->searchinfo.purepath, package?package:"", sizeof(s->searchinfo.purepath)); - s->searchinfo.handle = COM_EnumerateFilesPackage(pattern, package?s->searchinfo.purepath:NULL, s->fsflags, search_enumerate, s); + s->searchinfo.handle = COM_EnumerateFilesPackage(s->pattern, package?s->searchinfo.purepath:NULL, s->fsflags, search_enumerate, s); G_FLOAT(OFS_RETURN) = j; } diff --git a/engine/server/pr_cmds.c b/engine/server/pr_cmds.c index 6ad94d722..7c1a981b8 100644 --- a/engine/server/pr_cmds.c +++ b/engine/server/pr_cmds.c @@ -10628,7 +10628,13 @@ static BuiltinList_t BuiltinList[] = { //nq qw h2 ebfs {"cvar_string", PF_Fixme, 0, 0, 0, 71, D("string(string name)", "Returns the value of a cvar, as a string.")}, {"crash", PF_Fixme, 0, 0, 0, 72, D("void()", "Demonstrates that no program is bug free.")}, {"stackdump", PF_Fixme, 0, 0, 0, 73, D("void()", "Prints out the QC's stack, for console-based error reports.")}, - {"search_begin", PF_Fixme, 0, 0, 0, 74, "searchhandle(string pattern, enumflags:float{SB_CASEINSENSITIVE=1<<0,SB_FULLPACKAGEPATH=1<<1,SB_ALLOWDUPES=1<<2,SB_FORCESEARCH=1<<3} flags, float quiet, optional string package)"}, + {"search_begin", PF_Fixme, 0, 0, 0, 74, "searchhandle(string pattern, enumflags:float{" + "SB_CASEINSENSITIVE=1<<0," + "SB_FULLPACKAGEPATH=1<<1," + "SB_ALLOWDUPES=1<<2," + "SB_FORCESEARCH=1<<3" + "SB_MULTISEARCH=1<<4" + "} flags, float quiet, optional string package)"}, {"search_end", PF_Fixme, 0, 0, 0, 75, "void(searchhandle handle)"}, {"search_getsize", PF_Fixme, 0, 0, 0, 76, "float(searchhandle handle)"}, {"search_getfilename",PF_Fixme, 0, 0, 0, 77, "string(searchhandle handle, float num)"},