mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2025-03-20 17:31:08 +00:00
Avoid creating // in path names.
This commit is contained in:
parent
ba8ca132a9
commit
bbf2ac0204
1 changed files with 136 additions and 66 deletions
|
@ -608,6 +608,63 @@ no_config:
|
|||
qfs_gd_plist = PL_GetPropertyList (qfs_default_dirconf);
|
||||
}
|
||||
|
||||
/*
|
||||
contains_updir
|
||||
|
||||
Checks if a string contains an updir ('..'), either at the ends or
|
||||
surrounded by slashes ('/'). Doesn't check for leading slash.
|
||||
Assumes canonical (compressed) path.
|
||||
*/
|
||||
static inline int
|
||||
contains_updir (const char *path, int levels)
|
||||
{
|
||||
do {
|
||||
if (path[0] != '.' || path[1] != '.'
|
||||
|| (path[2] != '/' && path[2] != 0))
|
||||
return 0;
|
||||
if (!path[2])
|
||||
break;
|
||||
// first part of path is ../
|
||||
if (levels <= 0)
|
||||
return 1;
|
||||
path += 3;
|
||||
} while (levels-- > 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
qfs_expand_path (dstring_t *full_path, const char *base, const char *path)
|
||||
{
|
||||
const char *separator = "/";
|
||||
char *cpath;
|
||||
int len;
|
||||
|
||||
if (!base || !*base) {
|
||||
errno = EACCES;
|
||||
return -1;
|
||||
}
|
||||
cpath = QFS_CompressPath (path);
|
||||
if (contains_updir (cpath, 0)) {
|
||||
free (cpath);
|
||||
errno = EACCES;
|
||||
return -1;
|
||||
}
|
||||
if (*cpath == '/')
|
||||
separator = "";
|
||||
len = strlen (base);
|
||||
if (base[len -1] == '/')
|
||||
len--;
|
||||
dsprintf (full_path, "%.*s%s%s", len, base, separator, cpath);
|
||||
free (cpath);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
qfs_expand_userpath (dstring_t *full_path, const char *path)
|
||||
{
|
||||
return qfs_expand_path (full_path, qfs_userpath, path);
|
||||
}
|
||||
|
||||
VISIBLE char *
|
||||
QFS_FileBase (const char *in)
|
||||
{
|
||||
|
@ -762,30 +819,6 @@ QFS_CompressPath (const char *pth)
|
|||
return path;
|
||||
}
|
||||
|
||||
/*
|
||||
contains_updir
|
||||
|
||||
Checks if a string contains an updir ('..'), either at the ends or
|
||||
surrounded by slashes ('/'). Doesn't check for leading slash.
|
||||
Assumes canonical (compressed) path.
|
||||
*/
|
||||
static inline int
|
||||
contains_updir (const char *path, int levels)
|
||||
{
|
||||
do {
|
||||
if (path[0] != '.' || path[1] != '.'
|
||||
|| (path[2] != '/' && path[2] != 0))
|
||||
return 0;
|
||||
if (!path[2])
|
||||
break;
|
||||
// first part of path is ../
|
||||
if (levels <= 0)
|
||||
return 1;
|
||||
path += 3;
|
||||
} while (levels-- > 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
VISIBLE int file_from_pak; // global indicating file came from pack file ZOID
|
||||
|
||||
/*
|
||||
|
@ -799,8 +832,6 @@ static int
|
|||
open_file (searchpath_t *search, const char *filename, QFile **gzfile,
|
||||
dstring_t *foundname, int zip)
|
||||
{
|
||||
char *netpath;
|
||||
|
||||
file_from_pak = 0;
|
||||
|
||||
// is the element a pak file?
|
||||
|
@ -823,22 +854,26 @@ open_file (searchpath_t *search, const char *filename, QFile **gzfile,
|
|||
}
|
||||
} else {
|
||||
// check a file in the directory tree
|
||||
netpath = nva ("%s/%s", search->filename, filename);
|
||||
dstring_t *netpath = dstring_new ();
|
||||
|
||||
if (foundname) {
|
||||
dstring_clearstr (foundname);
|
||||
dstring_appendstr (foundname, filename);
|
||||
if (qfs_expand_path (netpath, search->filename, filename) == 0) {
|
||||
if (foundname) {
|
||||
dstring_clearstr (foundname);
|
||||
dstring_appendstr (foundname, filename);
|
||||
}
|
||||
if (Sys_FileTime (netpath->str) == -1) {
|
||||
dstring_delete (netpath);
|
||||
return -1;
|
||||
}
|
||||
|
||||
Sys_DPrintf ("FindFile: %s\n", netpath->str);
|
||||
|
||||
*gzfile = QFS_OpenRead (netpath->str, -1, -1, zip);
|
||||
dstring_delete (netpath);
|
||||
return qfs_filesize;
|
||||
}
|
||||
if (Sys_FileTime (netpath) == -1) {
|
||||
free (netpath);
|
||||
return -1;
|
||||
}
|
||||
|
||||
Sys_DPrintf ("FindFile: %s\n", netpath);
|
||||
|
||||
*gzfile = QFS_OpenRead (netpath, -1, -1, zip);
|
||||
free (netpath);
|
||||
return qfs_filesize;
|
||||
dstring_delete (netpath);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
|
@ -1084,6 +1119,8 @@ QFS_LoadGameDirectory (const char *dir)
|
|||
pakfiles[i] = NULL;
|
||||
}
|
||||
|
||||
// at this point, dir is known to not have a trailing /, and
|
||||
// dirent->d_name definitely won't start with one.
|
||||
pakfiles[count] = nva ("%s/%s", dir, dirent->d_name);
|
||||
if (!pakfiles[count])
|
||||
Sys_Error ("QFS_LoadGameDirectory: MemoryAllocationFailure");
|
||||
|
@ -1145,12 +1182,14 @@ QFS_AddGameDirectory (const char *dir)
|
|||
const char *e;
|
||||
const char *s;
|
||||
dstring_t *s_dir;
|
||||
dstring_t *f_dir;
|
||||
|
||||
if (!*dir)
|
||||
return;
|
||||
e = fs_sharepath->string + strlen (fs_sharepath->string);
|
||||
s = e;
|
||||
s_dir = dstring_new ();
|
||||
f_dir = dstring_new ();
|
||||
|
||||
while (s >= fs_sharepath->string) {
|
||||
while (s != fs_sharepath->string && s[-1] !=':')
|
||||
|
@ -1158,17 +1197,24 @@ QFS_AddGameDirectory (const char *dir)
|
|||
if (s != e) {
|
||||
dsprintf (s_dir, "%.*s", (int) (e - s), s);
|
||||
if (strcmp (s_dir->str, fs_userpath->string) != 0) {
|
||||
Sys_DPrintf ("QFS_AddGameDirectory (\"%s/%s\")\n",
|
||||
s_dir->str, dir);
|
||||
if (qfs_expand_path (f_dir, s_dir->str, dir) != 0) {
|
||||
Sys_Printf ("dropping bad directory %s\n", dir);
|
||||
break;
|
||||
}
|
||||
Sys_DPrintf ("QFS_AddGameDirectory (\"%s\")\n", f_dir->str);
|
||||
|
||||
QFS_AddDirectory (va ("%s/%s", s_dir->str, dir));
|
||||
QFS_AddDirectory (f_dir->str);
|
||||
}
|
||||
}
|
||||
e = --s;
|
||||
}
|
||||
|
||||
Sys_DPrintf ("QFS_AddGameDirectory (\"%s/%s\")\n", qfs_userpath, dir);
|
||||
QFS_AddDirectory (va ("%s/%s", qfs_userpath, dir));
|
||||
qfs_expand_userpath (f_dir, dir);
|
||||
Sys_DPrintf ("QFS_AddGameDirectory (\"%s\")\n", f_dir->str);
|
||||
QFS_AddDirectory (f_dir->str);
|
||||
|
||||
dstring_delete (f_dir);
|
||||
dstring_delete (s_dir);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1251,15 +1297,26 @@ expand_squiggle (const char *path)
|
|||
return strdup (path);
|
||||
}
|
||||
|
||||
static void
|
||||
qfs_path_cvar (cvar_t *var)
|
||||
{
|
||||
char *cpath = QFS_CompressPath (var->string);
|
||||
if (strcmp (cpath, var->string))
|
||||
Cvar_Set (var, cpath);
|
||||
free (cpath);
|
||||
}
|
||||
|
||||
VISIBLE void
|
||||
QFS_Init (const char *game)
|
||||
{
|
||||
int i;
|
||||
|
||||
fs_sharepath = Cvar_Get ("fs_sharepath", FS_SHAREPATH, CVAR_ROM, NULL,
|
||||
fs_sharepath = Cvar_Get ("fs_sharepath", FS_SHAREPATH, CVAR_ROM,
|
||||
qfs_path_cvar,
|
||||
"location of shared (read-only) game "
|
||||
"directories");
|
||||
fs_userpath = Cvar_Get ("fs_userpath", FS_USERPATH, CVAR_ROM, NULL,
|
||||
fs_userpath = Cvar_Get ("fs_userpath", FS_USERPATH, CVAR_ROM,
|
||||
qfs_path_cvar,
|
||||
"location of your game directories");
|
||||
fs_dirconf = Cvar_Get ("fs_dirconf", "", CVAR_ROM, NULL,
|
||||
"full path to gamedir.conf FIXME");
|
||||
|
@ -1372,6 +1429,8 @@ QFS_NextFilename (dstring_t *filename, const char *prefix, const char *ext)
|
|||
{
|
||||
char *digits;
|
||||
int i;
|
||||
int ret = 0;
|
||||
dstring_t *full_path = dstring_new ();
|
||||
|
||||
dsprintf (filename, "%s0000%s", prefix, ext);
|
||||
digits = filename->str + strlen (prefix);
|
||||
|
@ -1381,10 +1440,17 @@ QFS_NextFilename (dstring_t *filename, const char *prefix, const char *ext)
|
|||
digits[1] = i / 100 % 10 + '0';
|
||||
digits[2] = i / 10 % 10 + '0';
|
||||
digits[3] = i % 10 + '0';
|
||||
if (Sys_FileTime (va ("%s/%s", qfs_userpath, filename->str)) == -1)
|
||||
return 1; // file doesn't exist
|
||||
|
||||
if (qfs_expand_userpath (full_path, filename->str) == -1)
|
||||
break;
|
||||
if (Sys_FileTime (full_path->str) == -1) {
|
||||
// file doesn't exist, so we can use this name
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
dstring_delete (full_path);
|
||||
return ret;
|
||||
}
|
||||
|
||||
VISIBLE QFile *
|
||||
|
@ -1393,14 +1459,9 @@ QFS_Open (const char *path, const char *mode)
|
|||
dstring_t *full_path = dstring_new ();
|
||||
QFile *file = 0;
|
||||
const char *m;
|
||||
char *cpath;
|
||||
int write = 0;
|
||||
|
||||
cpath = QFS_CompressPath (path);
|
||||
if (contains_updir (cpath, 0)) {
|
||||
errno = EACCES;
|
||||
} else {
|
||||
dsprintf (full_path, "%s/%s", qfs_userpath, cpath);
|
||||
if (qfs_expand_userpath (full_path, path) == 0) {
|
||||
Sys_DPrintf ("QFS_Open: %s %s\n", full_path->str, mode);
|
||||
for (m = mode; *m; m++)
|
||||
if (*m == 'w' || *m == '+' || *m == 'a')
|
||||
|
@ -1412,7 +1473,6 @@ QFS_Open (const char *path, const char *mode)
|
|||
}
|
||||
done:
|
||||
dstring_delete (full_path);
|
||||
free (cpath);
|
||||
return file;
|
||||
}
|
||||
|
||||
|
@ -1435,10 +1495,10 @@ QFS_Rename (const char *old_path, const char *new_path)
|
|||
dstring_t *full_new = dstring_new ();
|
||||
int ret;
|
||||
|
||||
dsprintf (full_old, "%s/%s", qfs_userpath, old_path);
|
||||
dsprintf (full_new, "%s/%s", qfs_userpath, new_path);
|
||||
if ((ret = QFS_CreatePath (full_new->str)) != -1)
|
||||
ret = Qrename (full_old->str, full_new->str);
|
||||
if ((ret = qfs_expand_userpath (full_old, old_path)) != -1)
|
||||
if ((ret = qfs_expand_userpath (full_new, old_path)) != -1)
|
||||
if ((ret = QFS_CreatePath (full_new->str)) != -1)
|
||||
ret = Qrename (full_old->str, full_new->str);
|
||||
dstring_delete (full_old);
|
||||
dstring_delete (full_new);
|
||||
return ret;
|
||||
|
@ -1450,8 +1510,8 @@ QFS_Remove (const char *path)
|
|||
dstring_t *full_path = dstring_new ();
|
||||
int ret;
|
||||
|
||||
dsprintf (full_path, "%s/%s", qfs_userpath, path);
|
||||
ret = Qremove (full_path->str);
|
||||
if ((ret = qfs_expand_userpath (full_path, path)) != -1)
|
||||
ret = Qremove (full_path->str);
|
||||
dstring_delete (full_path);
|
||||
return ret;
|
||||
}
|
||||
|
@ -1494,6 +1554,15 @@ QFS_FilelistFill (filelist_t *list, const char *path, const char *ext,
|
|||
searchpath_t *search;
|
||||
DIR *dir_ptr;
|
||||
struct dirent *dirent;
|
||||
char *cpath, *cp;
|
||||
const char *separator = "/";
|
||||
|
||||
if (strchr (ext, '/') || strchr (ext, '\\'))
|
||||
return;
|
||||
|
||||
cp = cpath = QFS_CompressPath (path);
|
||||
if (*cp == '/')
|
||||
separator = "";
|
||||
|
||||
for (search = qfs_searchpaths; search != NULL; search = search->next) {
|
||||
if (search->pack) {
|
||||
|
@ -1503,12 +1572,12 @@ QFS_FilelistFill (filelist_t *list, const char *path, const char *ext,
|
|||
for (i = 0; i < pak->numfiles; i++) {
|
||||
char *name = pak->files[i].name;
|
||||
|
||||
if (!fnmatch (va("%s*.%s", path, ext), name, FNM_PATHNAME)
|
||||
|| !fnmatch (va("%s*.%s.gz", path, ext), name, FNM_PATHNAME))
|
||||
if (!fnmatch (va("%s*.%s", cp, ext), name, FNM_PATHNAME)
|
||||
|| !fnmatch (va("%s*.%s.gz", cp, ext), name, FNM_PATHNAME))
|
||||
QFS_FilelistAdd (list, name, strip ? ext : 0);
|
||||
}
|
||||
} else {
|
||||
dir_ptr = opendir (va ("%s/%s", search->filename, path));
|
||||
dir_ptr = opendir (va ("%s/%s", search->filename, cp));
|
||||
if (!dir_ptr)
|
||||
continue;
|
||||
while ((dirent = readdir (dir_ptr)))
|
||||
|
@ -1518,6 +1587,7 @@ QFS_FilelistFill (filelist_t *list, const char *path, const char *ext,
|
|||
closedir (dir_ptr);
|
||||
}
|
||||
}
|
||||
free (cpath);
|
||||
}
|
||||
|
||||
VISIBLE void
|
||||
|
|
Loading…
Reference in a new issue