/* ===================== SV_WipeSavegame Delete save/<XXX>/ ===================== */ static void SV_WipeSavegame (const char *savename) { char name[MAX_OSPATH]; char *s; Com_DPrintf("SV_WipeSaveGame(%s)\n", savename); Com_sprintf (name, sizeof(name), "%s/save/%s/server.ssv", FS_Gamedir (), savename); FS_RemoveFile(name); Com_sprintf (name, sizeof(name), "%s/save/%s/game.ssv", FS_Gamedir (), savename); FS_RemoveFile(name); Com_sprintf (name, sizeof(name), "%s/save/%s/*.sav", FS_Gamedir (), savename); s = Sys_FindFirst( name, 0, 0 ); while (s) { FS_RemoveFile(s); s = Sys_FindNext( 0, 0 ); } Sys_FindClose (); Com_sprintf (name, sizeof(name), "%s/save/%s/*.sv2", FS_Gamedir (), savename); s = Sys_FindFirst(name, 0, 0 ); while (s) { FS_RemoveFile(s); s = Sys_FindNext( 0, 0 ); } Sys_FindClose (); }
void Sys_Mkfifo (const char *ospath, qFILE *f) { FILE *fifo; int result; struct stat buf; /* if file already exists AND is a pipefile, remove it */ if (!stat(ospath, &buf) && S_ISFIFO(buf.st_mode)) FS_RemoveFile(ospath); result = mkfifo(ospath, 0600); if (result != 0) return; fifo = fopen(ospath, "w+"); if (fifo) { const int fn = fileno(fifo); fcntl(fn, F_SETFL, O_NONBLOCK); } if (fifo) { f->f = fifo; } else { Com_Printf("WARNING: Could not create fifo pipe at %s.\n", ospath); f->f = NULL; } }
/* * SV_Demo_Stop */ static void SV_Demo_Stop( bool cancel, bool silent ) { if( !svs.demo.file ) { if( !silent ) { Com_Printf( "No server demo recording in progress\n" ); } return; } if( cancel ) { Com_Printf( "Canceled server demo recording: %s\n", svs.demo.filename ); } else { SNAP_StopDemoRecording( svs.demo.file ); Com_Printf( "Stopped server demo recording: %s\n", svs.demo.filename ); } FS_FCloseFile( svs.demo.file ); svs.demo.file = 0; if( cancel ) { if( !FS_RemoveFile( svs.demo.tempname ) ) Com_Printf( "Error: Failed to delete the temporary server demo file\n" ); } else { // write some meta information about the match/demo SV_SetDemoMetaKeyValue( "hostname", sv.configstrings[CS_HOSTNAME] ); SV_SetDemoMetaKeyValue( "localtime", va( "%u", svs.demo.localtime ) ); SV_SetDemoMetaKeyValue( "multipov", "1" ); SV_SetDemoMetaKeyValue( "duration", va( "%u", (int)ceil( svs.demo.duration/1000.0f ) ) ); SV_SetDemoMetaKeyValue( "mapname", sv.configstrings[CS_MAPNAME] ); SV_SetDemoMetaKeyValue( "gametype", sv.configstrings[CS_GAMETYPENAME] ); SV_SetDemoMetaKeyValue( "levelname", sv.configstrings[CS_MESSAGE] ); SV_SetDemoMetaKeyValue( "matchname", sv.configstrings[CS_MATCHNAME] ); SV_SetDemoMetaKeyValue( "matchscore", sv.configstrings[CS_MATCHSCORE] ); SV_SetDemoMetaKeyValue( "matchuuid", sv.configstrings[CS_MATCHUUID] ); SNAP_WriteDemoMetaData( svs.demo.tempname, svs.demo.meta_data, svs.demo.meta_data_realsize ); if( !FS_MoveFile( svs.demo.tempname, svs.demo.filename ) ) Com_Printf( "Error: Failed to rename the server demo file\n" ); } svs.demo.localtime = 0; svs.demo.basetime = svs.demo.duration = 0; SNAP_FreeClientFrames( &svs.demo.client ); Mem_ZoneFree( svs.demo.filename ); svs.demo.filename = NULL; Mem_ZoneFree( svs.demo.tempname ); svs.demo.tempname = NULL; }
/* * ML_Restart * Restart map list stuff */ void ML_Restart( qboolean forcemaps ) { ML_Shutdown(); if( forcemaps ) FS_RemoveFile( MLIST_CACHE ); FS_Rescan(); ML_Init(); }
/* * TV_Upstream_StopDemoRecord */ void TV_Upstream_StopDemoRecord( upstream_t *upstream, qboolean silent, qboolean cancel ) { assert( upstream ); if( !upstream->demo.recording ) { if( !silent ) Com_Printf( "Not recording a demo.\n" ); return; } // finish up SNAP_StopDemoRecording( upstream->demo.filehandle ); FS_FCloseFile( upstream->demo.filehandle ); // cancel the demos if( cancel ) { // remove the file that correspond to cls.demo.file if( !silent ) Com_Printf( "Canceling demo: %s\n", upstream->demo.filename ); if( !FS_RemoveFile( upstream->demo.tempname ) && !silent ) Com_Printf( "Error canceling demo." ); } else { // write some meta information about the match/demo TV_Upstream_SetDemoMetaKeyValue( upstream, "hostname", upstream->configstrings[CS_HOSTNAME] ); TV_Upstream_SetDemoMetaKeyValue( upstream, "localtime", va( "%u", upstream->demo.localtime ) ); TV_Upstream_SetDemoMetaKeyValue( upstream, "multipov", "1" ); TV_Upstream_SetDemoMetaKeyValue( upstream, "duration", va( "%u", (int)ceil( upstream->demo.duration/1000.0f ) ) ); TV_Upstream_SetDemoMetaKeyValue( upstream, "mapname", upstream->configstrings[CS_MAPNAME] ); TV_Upstream_SetDemoMetaKeyValue( upstream, "gametype", upstream->configstrings[CS_GAMETYPENAME] ); TV_Upstream_SetDemoMetaKeyValue( upstream, "levelname", upstream->configstrings[CS_MESSAGE] ); TV_Upstream_SetDemoMetaKeyValue( upstream, "matchname", upstream->configstrings[CS_MATCHNAME] ); TV_Upstream_SetDemoMetaKeyValue( upstream, "matchscore", upstream->configstrings[CS_MATCHSCORE] ); TV_Upstream_SetDemoMetaKeyValue( upstream, "matchuuid", upstream->configstrings[CS_MATCHUUID] ); SNAP_WriteDemoMetaData( upstream->demo.tempname, upstream->demo.meta_data, upstream->demo.meta_data_realsize ); if( !FS_MoveFile( upstream->demo.tempname, upstream->demo.filename ) ) Com_Printf( "Error: Failed to rename the demo file\n" ); } if( !silent ) Com_Printf( "Stopped demo: %s\n", upstream->demo.filename ); upstream->demo.filehandle = 0; // file id Mem_ZoneFree( upstream->demo.filename ); upstream->demo.filename = NULL; Mem_ZoneFree( upstream->demo.tempname ); upstream->demo.tempname = NULL; upstream->demo.recording = qfalse; upstream->demo.autorecording = qfalse; }
/** * @brief Removes a user created team */ void GAME_TeamDelete_f (void) { if (Cmd_Argc() != 2) { Com_Printf("Usage: %s <filename>\n", Cmd_Argv(0)); return; } const char* team = Cmd_Argv(1); char buf[MAX_OSPATH]; GAME_GetAbsoluteSavePath(buf, sizeof(buf)); Q_strcat(buf, sizeof(buf), "%s", team); FS_RemoveFile(buf); }
/** * @note Both client and server can use this, and it will * do the appropriate things. */ void Com_Error (int code, const char* fmt, ...) { va_list argptr; static char msg[MAXPRINTMSG]; static bool recursive = false; if (recursive) Sys_Error("recursive error after: %s", msg); recursive = true; va_start(argptr, fmt); Q_vsnprintf(msg, sizeof(msg), fmt, argptr); va_end(argptr); switch (code) { case ERR_DISCONNECT: Com_Printf("%s\n", msg); CL_Drop(); recursive = false; Com_Drop(); case ERR_DROP: Com_Printf("********************\n"); Com_Printf("ERROR: %s\n", msg); Com_Printf("********************\n"); Sys_Backtrace(); SV_Shutdown("Server crashed.", false); CL_Drop(); recursive = false; Com_Drop(); default: Com_Printf("%s\n", msg); SV_Shutdown("Server fatal crashed", false); /* send an receive net messages a last time */ NET_Wait(0); FS_CloseFile(&logfile); if (pipefile.f != nullptr) { FS_CloseFile(&pipefile); FS_RemoveFile(va("%s/%s", FS_Gamedir(), pipefile.name)); } CL_Shutdown(); Qcommon_Shutdown(); Sys_Error("Shutdown"); } }
/* * SNAP_WriteDemoMetaData */ void SNAP_WriteDemoMetaData( const char *filename, const char *meta_data, size_t meta_data_realsize ) { unsigned i; unsigned v; char tmpn[256]; int filenum, filelen; msg_t msg; uint8_t msg_buffer[MAX_MSGLEN]; void *compressed_msg; MSG_Init( &msg, msg_buffer, sizeof( msg_buffer ) ); // write to a temp file v = 0; for( i = 0; filename[i]; i++ ) { v = ( v + i ) * 37 + tolower( filename[i] ); // case insensitivity } Q_snprintfz( tmpn, sizeof( tmpn ), "%u.tmp", v ); if( FS_FOpenFile( tmpn, &filenum, FS_WRITE|SNAP_DEMO_GZ ) == -1 ) { return; } SNAP_DemoMetaDataMessage( &msg, meta_data, meta_data_realsize ); SNAP_RecordDemoMetaDataMessage( filenum, &msg ); // now open the original file in update mode and overwrite metadata // important note: we need to the load the temp file before closing it // because in the case of gz compression, closing the file may actually // write some data we don't want to copy filelen = FS_LoadFile( tmpn, &compressed_msg, NULL, 0 ); if( compressed_msg ) { int origfile; if( FS_FOpenFile( filename, &origfile, FS_READ|FS_UPDATE ) != -1 ) { FS_Write( compressed_msg, filelen, origfile ); FS_FCloseFile( origfile ); } FS_FreeFile( compressed_msg ); } FS_FCloseFile( filenum ); FS_RemoveFile( tmpn ); }
/* <2af4b> ../engine/hashpak.c:1678 */ void HPAK_CheckSize(char *pakname) { char fullname[MAX_PATH]; float maxSize; float actualSize; FileHandle_t hfile; maxSize = hpk_maxsize.value; if (!maxSize || pakname == NULL) return; if (maxSize < 0.0f) { Con_Printf("hpk_maxsize < 0, setting to 0\n"); Cvar_DirectSet(&hpk_maxsize, "0"); return; } Q_snprintf(fullname, ARRAYSIZE(fullname), "%s", pakname); #ifdef REHLDS_FIXES fullname[ARRAYSIZE(fullname) - 1] = 0; #endif // REHLDS_FIXES COM_DefaultExtension(fullname, HASHPAK_EXTENSION); COM_FixSlashes(fullname); actualSize = 0.0f; maxSize *= 1000000.0f; hfile = FS_Open(fullname, "rb"); if (hfile) { actualSize = (float)FS_Size(hfile); FS_Close(hfile); } if (actualSize >= maxSize) { Con_Printf("Server: Size of %s > %f MB, deleting.\n", fullname, hpk_maxsize.value); Log_Printf("Server: Size of %s > %f MB, deleting.\n", fullname, hpk_maxsize.value); FS_RemoveFile(fullname, 0); } }
/** * Both client and server can use this, and it will * do the appropriate things. */ void Com_Quit (void) { #ifdef DEDICATED_ONLY Com_WriteConfigToFile("dedconfig.cfg"); #else Com_WriteConfigToFile("config.cfg"); #endif SV_Shutdown("Server quit.", false); SV_Clear(); CL_Shutdown(); /* send an receive net messages a last time */ NET_Wait(0); FS_CloseFile(&logfile); if (pipefile.f != nullptr) { FS_CloseFile(&pipefile); FS_RemoveFile(va("%s/%s", FS_Gamedir(), pipefile.name)); } Sys_Quit(); }
/* <2afb5> ../engine/hashpak.c:1728 */ void HPAK_ValidatePak(char *fullpakname) { hash_pack_header_t header; hash_pack_directory_t directory; hash_pack_entry_t *entry; char szFileName[MAX_PATH]; FileHandle_t fp; byte *pData; byte md5[16]; MD5Context_t ctx; HPAK_FlushHostQueue(); fp = FS_Open(fullpakname, "rb"); if (!fp) return; FS_Read(&header, sizeof(hash_pack_header_t), 1, fp); if (header.version != HASHPAK_VERSION || Q_strncmp(header.szFileStamp, "HPAK", sizeof(header.szFileStamp)) != 0) { Con_Printf("%s is not a PAK file, deleting\n", fullpakname); FS_Close(fp); FS_RemoveFile(fullpakname, 0); return; } FS_Seek(fp, header.nDirectoryOffset, FILESYSTEM_SEEK_HEAD); FS_Read(&directory, 4, 1, fp); if (directory.nEntries < 1 || (unsigned int)directory.nEntries > MAX_FILE_ENTRIES) { Con_Printf("ERROR: HPAK %s had bogus # of directory entries: %i, deleting\n", fullpakname, directory.nEntries); FS_Close(fp); FS_RemoveFile(fullpakname, 0); return; } directory.p_rgEntries = (hash_pack_entry_t *)Mem_Malloc(sizeof(hash_pack_entry_t) * directory.nEntries); FS_Read(directory.p_rgEntries, sizeof(hash_pack_entry_t) * directory.nEntries, 1, fp); for (int nCurrent = 0; nCurrent < directory.nEntries; nCurrent++) { entry = &directory.p_rgEntries[nCurrent]; COM_FileBase(entry->resource.szFileName, szFileName); if ((unsigned int)entry->nFileLength >= MAX_FILE_SIZE) { Con_Printf("Mismatched data in HPAK file %s, deleting\n", fullpakname); Con_Printf("Unable to MD5 hash data lump %i, size invalid: %i\n", nCurrent + 1, entry->nFileLength); FS_Close(fp); FS_RemoveFile(fullpakname, 0); Mem_Free(directory.p_rgEntries); return; } pData = (byte *)Mem_Malloc(entry->nFileLength + 1); Q_memset(pData, 0, entry->nFileLength); FS_Seek(fp, entry->nOffset, FILESYSTEM_SEEK_HEAD); FS_Read(pData, entry->nFileLength, 1, fp); Q_memset(&ctx, 0, sizeof(MD5Context_t)); MD5Init(&ctx); MD5Update(&ctx, pData, entry->nFileLength); MD5Final(md5, &ctx); if (pData) Mem_Free(pData); if (Q_memcmp(entry->resource.rgucMD5_hash, md5, sizeof(md5)) != 0) { Con_Printf("Mismatched data in HPAK file %s, deleting\n", fullpakname); FS_Close(fp); FS_RemoveFile(fullpakname, 0); Mem_Free(directory.p_rgEntries); return; } } FS_Close(fp); Mem_Free(directory.p_rgEntries); }
/** * @brief A download finished, find out what it was, whether there were any errors and * if so, how severe. If none, rename file and other such stuff. */ static void CL_FinishHTTPDownload (void) { int messagesInQueue, i; CURLcode result; CURL *curl; long responseCode; double timeTaken, fileSize; char tempName[MAX_OSPATH]; bool isFile; do { CURLMsg *msg = curl_multi_info_read(multi, &messagesInQueue); dlhandle_t *dl = NULL; if (!msg) { Com_Printf("CL_FinishHTTPDownload: Odd, no message for us...\n"); return; } if (msg->msg != CURLMSG_DONE) { Com_Printf("CL_FinishHTTPDownload: Got some weird message...\n"); continue; } curl = msg->easy_handle; /* curl doesn't provide reverse-lookup of the void * ptr, so search for it */ for (i = 0; i < 4; i++) { if (cls.HTTPHandles[i].curl == curl) { dl = &cls.HTTPHandles[i]; break; } } if (!dl) Com_Error(ERR_DROP, "CL_FinishHTTPDownload: Handle not found"); /* we mark everything as done even if it errored to prevent multiple attempts. */ dl->queueEntry->state = DLQ_STATE_DONE; /* filelist processing is done on read */ if (dl->file) isFile = true; else isFile = false; if (isFile) { fclose(dl->file); dl->file = NULL; } /* might be aborted */ if (pendingCount) pendingCount--; handleCount--; /* Com_Printf("finished dl: hc = %d\n", handleCount); */ cls.downloadName[0] = 0; cls.downloadPosition = 0; result = msg->data.result; switch (result) { /* for some reason curl returns CURLE_OK for a 404... */ case CURLE_HTTP_RETURNED_ERROR: case CURLE_OK: curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &responseCode); if (responseCode == 404) { const char *extension = Com_GetExtension(dl->queueEntry->ufoPath); if (extension != NULL && Q_streq(extension, "pk3")) downloadingPK3 = false; if (isFile) FS_RemoveFile(dl->filePath); Com_Printf("HTTP(%s): 404 File Not Found [%d remaining files]\n", dl->queueEntry->ufoPath, pendingCount); curl_easy_getinfo(curl, CURLINFO_SIZE_DOWNLOAD, &fileSize); if (fileSize > 512) { /* ick */ isFile = false; result = CURLE_FILESIZE_EXCEEDED; Com_Printf("Oversized 404 body received (%d bytes), aborting HTTP downloading.\n", (int)fileSize); } else { curl_multi_remove_handle(multi, dl->curl); continue; } } else if (responseCode == 200) { if (!isFile && !abortDownloads) CL_ParseFileList(dl); break; } /* every other code is treated as fatal, fallthrough here */ /* fatal error, disable http */ case CURLE_COULDNT_RESOLVE_HOST: case CURLE_COULDNT_CONNECT: case CURLE_COULDNT_RESOLVE_PROXY: if (isFile) FS_RemoveFile(dl->filePath); Com_Printf("Fatal HTTP error: %s\n", curl_easy_strerror(result)); curl_multi_remove_handle(multi, dl->curl); if (abortDownloads) continue; CL_CancelHTTPDownloads(true); continue; default: i = strlen(dl->queueEntry->ufoPath); if (Q_streq(dl->queueEntry->ufoPath + i - 4, ".pk3")) downloadingPK3 = false; if (isFile) FS_RemoveFile(dl->filePath); Com_Printf("HTTP download failed: %s\n", curl_easy_strerror(result)); curl_multi_remove_handle(multi, dl->curl); continue; } if (isFile) { /* rename the temp file */ Com_sprintf(tempName, sizeof(tempName), "%s/%s", FS_Gamedir(), dl->queueEntry->ufoPath); if (!FS_RenameFile(dl->filePath, tempName, false)) Com_Printf("Failed to rename %s for some odd reason...", dl->filePath); /* a pk3 file is very special... */ i = strlen(tempName); if (Q_streq(tempName + i - 4, ".pk3")) { FS_RestartFilesystem(NULL); CL_ReVerifyHTTPQueue(); downloadingPK3 = false; } } /* show some stats */ curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &timeTaken); curl_easy_getinfo(curl, CURLINFO_SIZE_DOWNLOAD, &fileSize); /** @todo * technically i shouldn't need to do this as curl will auto reuse the * existing handle when you change the URL. however, the handleCount goes * all weird when reusing a download slot in this way. if you can figure * out why, please let me know. */ curl_multi_remove_handle(multi, dl->curl); Com_Printf("HTTP(%s): %.f bytes, %.2fkB/sec [%d remaining files]\n", dl->queueEntry->ufoPath, fileSize, (fileSize / 1024.0) / timeTaken, pendingCount); } while (messagesInQueue > 0); if (handleCount == 0) { if (abortDownloads == HTTPDL_ABORT_SOFT) abortDownloads = HTTPDL_ABORT_NONE; else if (abortDownloads == HTTPDL_ABORT_HARD) cls.downloadServer[0] = 0; } /* done current batch, see if we have more to dl - maybe a .bsp needs downloaded */ if (cls.state == ca_connected && !CL_PendingHTTPDownloads()) CL_RequestNextDownload(); }
/** * @brief Writes lines containing "bind key value" * @param[in] filename Path to print the keybinding too * @sa Com_WriteConfigToFile */ void Key_WriteBindings (const char* filename) { int i; /* this gets true in case of an error */ qboolean deleteFile = qfalse; qFILE f; int cnt = 0; OBJZERO(f); FS_OpenFile(filename, &f, FILE_WRITE); if (!f.f) { Com_Printf("Couldn't write %s.\n", filename); return; } FS_Printf(&f, "// generated by ufo, do not modify\n"); FS_Printf(&f, "// If you want to know the keyname of a specific key - set in_debug cvar to 1 and press the key\n"); FS_Printf(&f, "unbindallmenu\n"); FS_Printf(&f, "unbindall\n"); FS_Printf(&f, "unbindallbattle\n"); /* failfast, stops loop for first occurred error in fprintf */ for (i = 0; i < K_LAST_KEY && !deleteFile; i++) if (menuKeyBindings[i] && menuKeyBindings[i][0]) { if (FS_Printf(&f, "bindmenu %s \"%s\"\n", Key_KeynumToString(i), menuKeyBindings[i]) < 0) deleteFile = qtrue; cnt++; } for (i = 0; i < K_LAST_KEY && !deleteFile; i++) if (keyBindings[i] && keyBindings[i][0]) { if (FS_Printf(&f, "bind %s \"%s\"\n", Key_KeynumToString(i), keyBindings[i]) < 0) deleteFile = qtrue; cnt++; } for (i = 0; i < K_LAST_KEY && !deleteFile; i++) if (battleKeyBindings[i] && battleKeyBindings[i][0]) { if (FS_Printf(&f, "bindbattle %s \"%s\"\n", Key_KeynumToString(i), battleKeyBindings[i]) < 0) deleteFile = qtrue; cnt++; } for (i = 0; i < UI_GetKeyBindingCount(); i++) { const char *path; uiKeyBinding_t*binding = UI_GetKeyBindingByIndex (i); if (binding->node == NULL) continue; if (binding->property == NULL) path = va("%s", UI_GetPath(binding->node)); else path = va("%s@%s", UI_GetPath(binding->node), binding->property->string); if (FS_Printf(&f, "bindui %s \"%s\"\n", Key_KeynumToString(binding->key), path) < 0) deleteFile = qtrue; } FS_CloseFile(&f); if (!deleteFile && cnt) Com_Printf("Wrote %s\n", filename); else /* error in writing the keys.cfg - remove the file again */ FS_RemoveFile(va("%s/%s", FS_Gamedir(), filename)); }
/* * SV_Demo_Purge_f * * Removes the server demo files */ void SV_Demo_Purge_f( void ) { char *buffer; char *p, *s, num[8]; char path[256]; size_t extlen, length, bufSize; unsigned int i, numdemos, numautodemos, maxautodemos; if( Cmd_Argc() > 2 ) { Com_Printf( "Usage: serverrecordpurge [maxautodemos]\n" ); return; } maxautodemos = 0; if( Cmd_Argc() == 2 ) maxautodemos = atoi( Cmd_Argv( 1 ) ); numdemos = FS_GetFileListExt( SV_DEMO_DIR, APP_DEMO_EXTENSION_STR, NULL, &bufSize, 0, 0 ); if( !numdemos ) return; extlen = strlen( APP_DEMO_EXTENSION_STR ); buffer = Mem_TempMalloc( bufSize ); FS_GetFileList( SV_DEMO_DIR, APP_DEMO_EXTENSION_STR, buffer, bufSize, 0, 0 ); numautodemos = 0; s = buffer; for( i = 0; i < numdemos; i++, s += length + 1 ) { length = strlen( s ); if( length < strlen( "_auto9999" ) + extlen ) continue; p = s + length - strlen( "_auto9999" ) - extlen; if( strncmp( p, "_auto", strlen( "_auto" ) ) ) continue; p += strlen( "_auto" ); Q_snprintfz( num, sizeof( num ), "%04i", atoi( p ) ); if( strncmp( p, num, 4 ) ) continue; numautodemos++; } if( numautodemos <= maxautodemos ) { Mem_TempFree( buffer ); return; } s = buffer; for( i = 0; i < numdemos; i++, s += length + 1 ) { length = strlen( s ); if( length < strlen( "_auto9999" ) + extlen ) continue; p = s + length - strlen( "_auto9999" ) - extlen; if( strncmp( p, "_auto", strlen( "_auto" ) ) ) continue; p += strlen( "_auto" ); Q_snprintfz( num, sizeof( num ), "%04i", atoi( p ) ); if( strncmp( p, num, 4 ) ) continue; Q_snprintfz( path, sizeof( path ), "%s/%s", SV_DEMO_DIR, s ); Com_Printf( "Removing old autorecord demo: %s\n", path ); if( !FS_RemoveFile( path ) ) { Com_Printf( "Error, couldn't remove file: %s\n", path ); continue; } if( --numautodemos == maxautodemos ) break; } Mem_TempFree( buffer ); }