common: make COM_StripExtension and COM_DefaultExtension check buffers

Pass an input and output buffer in (can be the same pointer) and
ensure that no more is written to the output buffer than will fit.
COM_DefaultExtension now returns an error if it ran out of space
adding the extension.

Signed-off-by: Kevin Shanahan <kmshanah@disenchant.net>
This commit is contained in:
Kevin Shanahan 2013-04-15 13:11:14 +09:30
parent 4d0773d6a1
commit 376f9a7de5
10 changed files with 106 additions and 89 deletions

View File

@ -203,9 +203,8 @@ record <demoname> <map> [cd track]
void
CL_Record_f(void)
{
int c;
int c, track, length, err;
char name[MAX_OSPATH];
int track;
if (cmd_source != src_command)
return;
@ -234,22 +233,22 @@ CL_Record_f(void)
} else
track = -1;
sprintf(name, "%s/%s", com_gamedir, Cmd_Argv(1));
/* Grab the filename before our cmd args disappear */
length = snprintf(name, sizeof(name), "%s/%s", com_gamedir, Cmd_Argv(1));
err = COM_DefaultExtension(name, ".dem", name, sizeof(name));
if (length >= sizeof(name) || err) {
Con_Printf("Error: demo path name too long.\n");
return;
}
//
// start the map up
//
/* start the map up */
if (c > 2) {
Cmd_ExecuteString(va("map %s", Cmd_Argv(2)), src_command);
if (cls.state != ca_connected)
return;
}
//
// open the demo file
//
COM_DefaultExtension(name, ".dem");
/* open the demo file */
Con_Printf("recording to %s.\n", name);
cls.demofile = fopen(name, "wb");
if (!cls.demofile) {
@ -273,8 +272,8 @@ play [demoname]
void
CL_PlayDemo_f(void)
{
char name[256], forcetrack[12];
int i, c;
char name[MAX_QPATH], forcetrack[12];
int i, c, err;
if (cmd_source != src_command)
return;
@ -291,14 +290,18 @@ CL_PlayDemo_f(void)
//
// open the demo file
//
strcpy(name, Cmd_Argv(1));
COM_DefaultExtension(name, ".dem");
err = COM_DefaultExtension(Cmd_Argv(1), ".dem", name, sizeof(name));
if (err) {
Con_Printf("Error: demo filename too long\n");
cls.demonum = -1; /* stop demo loop */
return;
}
Con_Printf("Playing demo from %s.\n", name);
COM_FOpenFile(name, &cls.demofile);
if (!cls.demofile) {
Con_Printf("ERROR: couldn't open.\n");
cls.demonum = -1; // stop demo loop
cls.demonum = -1; /* stop demo loop */
return;
}

View File

@ -346,8 +346,7 @@ CL_ParseServerInfo(void)
// copy the naked name of the map file to the cl structure
mapname = COM_SkipPath(model_precache[1]);
snprintf(cl.mapname, sizeof(cl.mapname), "%s", mapname);
COM_StripExtension(cl.mapname);
COM_StripExtension(mapname, cl.mapname, sizeof(cl.mapname));
//
// now we try to load everything else until a cache allocation fails

View File

@ -276,9 +276,9 @@ Host_Savegame_f
static void
Host_Savegame_f(void)
{
char name[256];
char name[MAX_OSPATH];
FILE *f;
int i;
int i, length, err;
char comment[SAVEGAME_COMMENT_LENGTH + 1];
if (cmd_source != src_command)
@ -316,8 +316,12 @@ Host_Savegame_f(void)
}
}
sprintf(name, "%s/%s", com_gamedir, Cmd_Argv(1));
COM_DefaultExtension(name, ".sav");
length = snprintf(name, sizeof(name), "%s/%s", com_gamedir, Cmd_Argv(1));
err = COM_DefaultExtension(name, ".sav", name, sizeof(name));
if (length >= sizeof(name) || err) {
Con_Printf("ERROR: couldn't save, filename too long.\n");
return;
}
Con_Printf("Saving game to %s...\n", name);
f = fopen(name, "w");
@ -364,13 +368,13 @@ static void
Host_Loadgame_f(void)
{
char name[MAX_OSPATH];
FILE *f;
char mapname[MAX_QPATH];
FILE *f;
float time, tfloat;
char str[32768];
char *lightstyle;
const char *start;
int i, r;
int i, r, length, err;
edict_t *ent;
int entnum;
int version;
@ -386,8 +390,12 @@ Host_Loadgame_f(void)
cls.demonum = -1; // stop demo loop in case this fails
sprintf(name, "%s/%s", com_gamedir, Cmd_Argv(1));
COM_DefaultExtension(name, ".sav");
length = snprintf(name, sizeof(name), "%s/%s", com_gamedir, Cmd_Argv(1));
err = COM_DefaultExtension(name, ".sav", name, sizeof(name));
if (length >= sizeof(name) || err) {
Con_Printf("ERROR: couldn't open save game, filename too long.\n");
return;
}
// we can't call SCR_BeginLoadingPlaque, because too much stack space has
// been used. The menu calls it before stuffing loadgame command

View File

@ -389,7 +389,7 @@ CL_Record_f(void)
char name[MAX_OSPATH];
sizebuf_t buf;
byte buf_data[MAX_MSGLEN];
int n, i, j;
int n, i, j, length, err;
char *s;
const entity_t *ent;
entity_state_t *es, blankes;
@ -410,13 +410,14 @@ CL_Record_f(void)
if (cls.demorecording)
CL_Stop_f();
sprintf(name, "%s/%s", com_gamedir, Cmd_Argv(1));
//
// open the demo file
//
COM_DefaultExtension(name, ".qwd");
length = snprintf(name, sizeof(name), "%s/%s", com_gamedir, Cmd_Argv(1));
err = COM_DefaultExtension(name, ".qwd", name, sizeof(name));
if (length >= sizeof(name) || err) {
Con_Printf("ERROR: couldn't open demo, filename too long.\n");
return;
}
/* open the demo file */
cls.demofile = fopen(name, "wb");
if (!cls.demofile) {
Con_Printf("ERROR: couldn't open.\n");
@ -672,7 +673,7 @@ record <demoname>
void
CL_ReRecord_f(void)
{
int c;
int c, length, err;
char name[MAX_OSPATH];
c = Cmd_Argc();
@ -689,13 +690,14 @@ CL_ReRecord_f(void)
if (cls.demorecording)
CL_Stop_f();
sprintf(name, "%s/%s", com_gamedir, Cmd_Argv(1));
//
// open the demo file
//
COM_DefaultExtension(name, ".qwd");
length = snprintf(name, sizeof(name), "%s/%s", com_gamedir, Cmd_Argv(1));
err = COM_DefaultExtension(name, ".qwd", name, sizeof(name));
if (length >= sizeof(name) || err) {
Con_Printf("ERROR: open demo file, filename too long.\n");
return;
}
/* open the demo file */
cls.demofile = fopen(name, "wb");
if (!cls.demofile) {
Con_Printf("ERROR: couldn't open.\n");
@ -720,7 +722,8 @@ play [demoname]
void
CL_PlayDemo_f(void)
{
char name[256];
int err;
char name[MAX_QPATH];
if (Cmd_Argc() != 2) {
Con_Printf("play <demoname> : plays a demo\n");
@ -731,17 +734,19 @@ CL_PlayDemo_f(void)
//
CL_Disconnect();
//
// open the demo file
//
strcpy(name, Cmd_Argv(1));
COM_DefaultExtension(name, ".qwd");
err = COM_DefaultExtension(Cmd_Argv(1), ".qwd", name, sizeof(name));
if (err) {
Con_Printf("ERROR: couldn't open demo, filename too long.\n");
cls.demonum = -1; /* stop demo loop */
return;
}
/* open the demo file */
Con_Printf("Playing demo from %s.\n", name);
COM_FOpenFile(name, &cls.demofile);
if (!cls.demofile) {
Con_Printf("ERROR: couldn't open.\n");
cls.demonum = -1; // stop demo loop
cls.demonum = -1; /* stop demo loop */
return;
}

View File

@ -171,7 +171,7 @@ qboolean
CL_CheckOrDownloadFile(char *filename)
{
FILE *f;
int maxlen;
int err;
if (strstr(filename, "..")) {
Con_Printf("Refusing to download a path with ..\n");
@ -200,16 +200,12 @@ CL_CheckOrDownloadFile(char *filename)
* download to a temp name, and only rename to the real name when
* done, so if interrupted a runt file wont be left
*/
strcpy(cls.downloadtempname, cls.downloadname); /* same size */
COM_StripExtension(cls.downloadtempname);
/* make sure the .tmp extension fits... */
maxlen = sizeof(cls.downloadtempname);
if (strlen(cls.downloadtempname) + strlen(".tmp") > maxlen - 1) {
err = COM_DefaultExtension(cls.downloadname, ".tmp", cls.downloadtempname,
sizeof(cls.downloadtempname));
if (err) {
Con_Printf("Refusing download, pathname too long\n");
return true;
}
strcat(cls.downloadtempname, ".tmp");
MSG_WriteByte(&cls.netchan.message, clc_stringcmd);
MSG_WriteStringf(&cls.netchan.message, "download %s", cls.downloadname);
@ -897,15 +893,16 @@ CL_NewTranslation(int slot)
int top, bottom;
byte *dest, *source;
player_info_t *player;
char *skin;
const char *skin_key;
char skin[MAX_QPATH];
if (slot > MAX_CLIENTS)
Sys_Error("%s: slot > MAX_CLIENTS", __func__);
player = &cl.players[slot];
skin = Info_ValueForKey(player->userinfo, "skin");
COM_StripExtension(skin);
skin_key = Info_ValueForKey(player->userinfo, "skin");
COM_StripExtension(skin_key, skin, sizeof(skin));
if (player->skin && !strcasecmp(skin, player->skin->name))
player->skin = NULL;

View File

@ -48,7 +48,7 @@ Skin_Find(player_info_t * sc)
{
skin_t *skin;
int i;
char name[128];
char name[MAX_QPATH];
const char *skinname;
skinname = allskins;
@ -60,8 +60,7 @@ Skin_Find(player_info_t * sc)
if (strstr(skinname, "..") || skinname[0] == '.')
skinname = "base";
snprintf(name, sizeof(name), "%s", skinname);
COM_StripExtension(name);
COM_StripExtension(skinname, name, sizeof(name));
for (i = 0; i < numskins; i++) {
if (!strcmp(name, skins[i].name)) {

View File

@ -942,14 +942,22 @@ COM_StripExtension
============
*/
void
COM_StripExtension(char *filename)
COM_StripExtension(const char *filename, char *out, size_t buflen)
{
const char *start;
const char *start, *pos;
size_t copylen;
start = COM_SkipPath(filename);
char *pos = strrchr(start, '.');
if (pos && *pos)
*pos = 0;
pos = strrchr(start, '.');
if (out == filename) {
if (pos && *pos)
out[pos - filename] = 0;
return;
}
copylen = qmin((size_t)(pos - filename), buflen - 1);
memcpy(out, filename, copylen);
out[copylen] = 0;
}
/*
@ -1005,24 +1013,21 @@ COM_FileBase(const char *in, char *out, size_t buflen)
/*
==================
COM_DefaultExtension
Returns non-zero if the extension wouldn't fit in the output buffer
==================
*/
void
COM_DefaultExtension(char *path, const char *extension)
int
COM_DefaultExtension(const char *path, const char *extension, char *out,
size_t buflen)
{
const char *src;
COM_StripExtension(path, out, buflen);
if (strlen(out) + strlen(extension) + 1 > buflen)
return -1;
//
// if path doesn't have a .EXT, append extension
// (extension should include the .)
//
src = path + strlen(path) - 1;
while (*src != '/' && src != path) {
if (*src == '.')
return; // it has an extension
src--;
}
strcat(path, extension);
/* Copy extension, including terminating null */
memcpy(out + strlen(out), extension, strlen(extension) + 1);
return 0;
}
int

View File

@ -328,7 +328,7 @@ void
GL_LoadMeshData(const model_t *model, aliashdr_t *hdr, const mtriangle_t *tris,
const stvert_t *stverts, const trivertx_t **poseverts)
{
int i, j, tmp;
int i, j, tmp, err;
int *cmds;
trivertx_t *verts;
char cache[MAX_QPATH];
@ -341,10 +341,9 @@ GL_LoadMeshData(const model_t *model, aliashdr_t *hdr, const mtriangle_t *tris,
//
name = COM_SkipPath(model->name);
snprintf(cache, sizeof(cache), "%s/glquake/%s", com_gamedir, name);
COM_StripExtension(cache);
if (strlen(cache) + strlen(".ms2") + 1 > sizeof(cache))
err = COM_DefaultExtension(cache, ".ms2", cache, sizeof(cache));
if (err)
Sys_Error("%s: model pathname too long (%s)", __func__, model->name);
strncat(cache, ".ms2", 4);
f = fopen(cache, "rb");
if (f) {

View File

@ -367,7 +367,8 @@ R_TranslatePlayerSkin(int playernum)
const entity_t *e;
#endif
#ifdef QW_HACK
char *skin;
const char *skin_key;
char skin[MAX_QPATH];
#endif
GL_DisableMultitexture();
@ -380,8 +381,8 @@ R_TranslatePlayerSkin(int playernum)
if (!player->name[0])
return;
skin = Info_ValueForKey(player->userinfo, "skin");
COM_StripExtension(skin);
skin_key = Info_ValueForKey(player->userinfo, "skin");
COM_StripExtension(skin_key, skin, sizeof(skin));
if (player->skin && !strcasecmp(skin, player->skin->name))
player->skin = NULL;

View File

@ -183,9 +183,10 @@ void COM_Init(void);
void COM_InitArgv(int argc, const char **argv);
const char *COM_SkipPath(const char *pathname);
void COM_StripExtension(char *filename);
void COM_StripExtension(const char *filename, char *out, size_t buflen);
void COM_FileBase(const char *in, char *out, size_t buflen);
void COM_DefaultExtension(char *path, const char *extension);
int COM_DefaultExtension(const char *path, const char *extension,
char *out, size_t buflen);
int COM_CheckExtension(const char *path, const char *extn);
char *va(const char *format, ...) __attribute__((format(printf,1,2)));