diff --git a/engine/qclib/packager.c b/engine/qclib/packager.c index 2da525932..874678ec8 100644 --- a/engine/qclib/packager.c +++ b/engine/qclib/packager.c @@ -9,7 +9,7 @@ #include #include #endif -void QCC_Canonicalize(char *fullname, size_t fullnamesize, const char *newfile, const char *base); +void QCC_JoinPaths(char *fullname, size_t fullnamesize, const char *newfile, const char *base); //package formats: //pakzip - files are uncompressed, with both a pak header and a zip trailer, allowing it to be read as either type of file. @@ -376,7 +376,7 @@ static void PKG_CreateOutput(struct pkgctx_s *ctx, struct dataset_s *s, const ch memset(o, 0, sizeof(*o)); strcpy(o->code, code); o->usediffs = diff; - QCC_Canonicalize(o->filename, sizeof(o->filename), path, ctx->gamepath); + QCC_JoinPaths(o->filename, sizeof(o->filename), path, ctx->gamepath); o->next = s->outputs; s->outputs = o; @@ -679,7 +679,7 @@ static void PKG_AddClassFiles(struct pkgctx_s *ctx, struct class_s *c, const cha char basepath[MAX_OSPATH], tmppath[MAX_OSPATH]; struct stat statbuf; - QCC_Canonicalize(basepath, sizeof(basepath), fname, ctx->sourcepath); + QCC_JoinPaths(basepath, sizeof(basepath), fname, ctx->sourcepath); QC_strlcat(basepath, "/", sizeof(basepath)); dir = opendir(basepath); if (!dir) @@ -691,8 +691,8 @@ static void PKG_AddClassFiles(struct pkgctx_s *ctx, struct class_s *c, const cha { if (*ent->d_name == '.') continue; - QCC_Canonicalize(basepath, sizeof(basepath), ent->d_name, fname); - QCC_Canonicalize(tmppath, sizeof(tmppath), basepath, ctx->sourcepath); + QCC_JoinPaths(basepath, sizeof(basepath), ent->d_name, fname); + QCC_JoinPaths(tmppath, sizeof(tmppath), basepath, ctx->sourcepath); if (stat(tmppath, &statbuf)!=0) continue; @@ -958,7 +958,7 @@ static void *PKG_OpenSourceFile(struct pkgctx_s *ctx, struct file_s *file, size_ *fsize = 0; - QCC_Canonicalize(fullname, sizeof(fullname), file->name, ctx->sourcepath); + QCC_JoinPaths(fullname, sizeof(fullname), file->name, ctx->sourcepath); strcpy(file->write.name, file->name); //WIN32 FIXME: use the utf16 version because microsoft suck and don't allow utf-8 @@ -996,7 +996,7 @@ static void *PKG_OpenSourceFile(struct pkgctx_s *ctx, struct file_s *file, size_ //delete temp file... fclose(f); - QCC_Canonicalize(tempname, sizeof(tempname), file->write.name, ctx->sourcepath); + QCC_JoinPaths(tempname, sizeof(tempname), file->write.name, ctx->sourcepath); f = fopen(tempname, "rb"); if (f) { @@ -1702,7 +1702,7 @@ void Packager_ParseText(struct pkgctx_s *ctx, char *scripttext) if (PKG_GetStringToken(ctx, cmd, sizeof(cmd))) { QC_strlcat(cmd, "/", sizeof(cmd)); - QCC_Canonicalize(ctx->sourcepath, sizeof(ctx->sourcepath), cmd, old); + QCC_JoinPaths(ctx->sourcepath, sizeof(ctx->sourcepath), cmd, old); } } else if (!strcmp(cmd, "rule")) diff --git a/engine/qclib/qcc_pr_lex.c b/engine/qclib/qcc_pr_lex.c index 911a9e91b..f15845392 100644 --- a/engine/qclib/qcc_pr_lex.c +++ b/engine/qclib/qcc_pr_lex.c @@ -218,56 +218,33 @@ pbool QCC_PR_UnInclude(void) return true; } -void QCC_Canonicalize(char *fullname, size_t fullnamesize, const char *newfile, const char *base) +//expresses a relative path relative to an existing FILEname. any directories in base must be / terminated properly. +void QCC_JoinPaths(char *fullname, size_t fullnamesize, const char *newfile, const char *base) { - int doubledots; - char *end = fullname; - - doubledots = 0; + char *end; - /*count how far up we need to go*/ - while(1) - { - if (!strncmp(newfile, "./", 2) || !strncmp(newfile, ".\\", 2)) - newfile+=2; - else if(!strncmp(newfile, "../", 3) || !strncmp(newfile, "..\\", 3)) - { - newfile+=3; - doubledots++; - } - else - break; + if (*newfile == '/' || *newfile == '\\') + { //its an absolute path... + QC_strlcpy(fullname, newfile, fullnamesize); + return; } - - //FIXME: length validation! - if (base) - strcpy(fullname, base); - else - *fullname = 0; + QC_strlcpy(fullname, base, fullnamesize); end = fullname+strlen(fullname); - while (end > fullname) { end--; - /*stop at the slash, unless we're meant to go further*/ if (*end == '/' || *end == '\\') { - if (!doubledots) - { - end++; - break; - } - doubledots--; + end++; + break; } } + QC_strlcpy(end, newfile, fullnamesize - (end-fullname)); - while (doubledots-- > 0) - { - strcpy(end, "../"); - end += 3; - } - - strcpy(end, newfile); + //FIXME: do we want to convert /segment/../ into just / ? + //fteqw might insist on it for its filesystem sandboxing. + //but it breaks symlink weirdness (itself a possible security hole). + //should probably be a separate function. } extern char qccmsourcedir[]; @@ -291,7 +268,7 @@ void QCC_FindBestInclude(char *newfile, char *currentfile, pbool verbose) currentfile = qccincludedir[includepath-1]; } - QCC_Canonicalize(fullname, sizeof(fullname), newfile, currentfile); + QCC_JoinPaths(fullname, sizeof(fullname), newfile, currentfile); { extern progfuncs_t *qccprogfuncs; @@ -954,7 +931,7 @@ static pbool QCC_PR_Precompiler(void) QCC_ImportProgs(pr_token); if (!*destfile && !destfile_explicit) { - QCC_Canonicalize(destfile, sizeof(destfile), pr_token, compilingfile); + QCC_JoinPaths(destfile, sizeof(destfile), pr_token, compilingfile); externs->Printf("Outputfile: %s\n", destfile); } @@ -1079,7 +1056,7 @@ static pbool QCC_PR_Precompiler(void) QCC_PR_SimpleGetString(); if (!destfile_explicit) { - QCC_Canonicalize(destfile, sizeof(destfile), pr_token, compilingfile); + QCC_JoinPaths(destfile, sizeof(destfile), pr_token, compilingfile); externs->Printf("Outputfile: %s\n", pr_token); } @@ -1213,7 +1190,7 @@ static pbool QCC_PR_Precompiler(void) QC_strlcat(qcc_token, "/", sizeof(qcc_token)); } - QCC_Canonicalize(newinc, sizeof(newinc), qcc_token, compilingfile); + QCC_JoinPaths(newinc, sizeof(newinc), qcc_token, compilingfile); QCC_PR_AddIncludePath(newinc); } else if (!QC_strcasecmp(qcc_token, "noref")) @@ -1332,7 +1309,7 @@ static pbool QCC_PR_Precompiler(void) QCC_COM_Parse(msg); if (!destfile_explicit) //if output file is named on the commandline, don't change it mid-compile - QCC_Canonicalize(destfile, sizeof(destfile), qcc_token, compilingfile); + QCC_JoinPaths(destfile, sizeof(destfile), qcc_token, compilingfile); if (strcmp(destfile, olddest)) externs->Printf("Outputfile: %s\n", destfile);