/** * @brief Recursively removes files matching a given pattern from homepath. * Useful for removing incomplete downloads and other garbage. * Files listed in the com_cleanWhitelist cvar are protected from deletion. */ void Cmd_CleanHomepath_f(void) { int i, j, numFiles = 0, delFiles = 0, totalNumFiles = 0; char **pFiles = NULL, *tokens; char path[MAX_OSPATH], whitelist[MAX_OSPATH]; qboolean whitelisted; if (Cmd_Argc() < 3) { // basically files are downloaded again when required - but better print a warning for inexperienced users Com_Printf("usage: clean <mod> <pattern[1]> <pattern[n]>\nexample: clean all *tmp */zzz* etmain/etkey\nwarning: This command deletes files in fs_homepath. If you are not sure how to use this command do not play with fire!"); return; } // avoid unreferenced pk3 runtime issues (not on HD but still referenced in game) #ifndef DEDICATED if (cls.state != CA_DISCONNECTED) { Com_Printf("You are connected to a server - '/disconnect' to run '/clean'.\n"); return; } #else if (com_sv_running && com_sv_running->integer) { Com_Printf("Server is running - '/killserver' to run '/clean'.\n"); return; } #endif // DEDICATED Cvar_VariableStringBuffer("fs_homepath", path, sizeof(path)); // If the first argument is "all" or "*", search the whole homepath // FIXME: add more options ? see #53 if (Q_stricmp(Cmd_Argv(1), "all") && Q_stricmp(Cmd_Argv(1), "*")) { Q_strcat(path, sizeof(path), va("%c%s", PATH_SEP, Cmd_Argv(1))); } for (i = 2; i < Cmd_Argc(); i++) { pFiles = Sys_ListFiles(path, NULL, Cmd_Argv(i), &numFiles, qtrue); Com_Printf("Found %i files matching the pattern \"%s\" under %s\n", numFiles, Cmd_Argv(i), path); // debug //for (j = 0; j < numFiles; j++) //{ // Com_Printf("FILE[%i]: %s - pattern: %s\n", j + 1, pFiles[j], Cmd_Argv(i)); //} for (j = 0; j < numFiles; j++) { whitelisted = qfalse; totalNumFiles++; // FIXME: - don't let admins force this! - move to dat file? // - optimize - don't do this each loop! -> strtok modifies the input string, which is undefined behaviour on a literal char[], at least in C99 // & print the whitelist files on top again Cvar_VariableStringBuffer("com_cleanwhitelist", whitelist, sizeof(whitelist)); // Prevent clumsy users from deleting important files - keep leading space! Q_strcat(whitelist, sizeof(whitelist), " .txt .cfg .dat .gm .way .so .dll"); // *.so and *.dll are denied per default in FS_Remove but throw a Com_Error() -> game aborts //Com_DPrintf("Whitelist files/patterns: %s\n", whitelist); // Check if this file is in the whitelist tokens = strtok(whitelist, " ,;"); while (tokens != NULL) { if (strstr(pFiles[j], tokens)) { Com_Printf("- skipping file[%i]: %s%c%s - pattern: %s\n", j + 1, path, PATH_SEP, pFiles[j], tokens); whitelisted = qtrue; break; } tokens = strtok(NULL, " ,;"); } if (whitelisted) { continue; } Com_Printf("- removing file[%i]: %s%c%s\n", j + 1, path, PATH_SEP, pFiles[j]); //remove(va("%s%c%s", path, PATH_SEP, pFiles[j])); // enable *.so & *.dll lib deletion - see whitelist FS_Remove(va("%s%c%s", path, PATH_SEP, pFiles[j])); delFiles++; } Sys_FreeFileList(pFiles); numFiles = 0; } Com_Printf("Path of fs_homepath cleaned - %i matches - %i files skipped - %i files deleted.\n", totalNumFiles, totalNumFiles - delFiles, delFiles); }
/* ================ CreateResourceIDs_f ================ */ void CreateResourceIDs_f( const idCmdArgs &args ) { int i, j; idStr path, fileName; idStrList resourceFiles; idLexer src; idToken token; idStrList dialogs; idStrList resources; idStrList bitmaps; idStrList icons; idStrList strings; idStrList controls; idStrList commands; if ( args.Argc() > 1 ) { path = args.Argv(1); } else { path = SOURCE_CODE_BASE_FOLDER"/"; path.Append( __FILE__ ); path.StripFilename(); path.BackSlashesToSlashes(); } common->Printf( "%s\n", path.c_str() ); Sys_ListFiles( path, "_resource.h", resourceFiles ); for ( i = 0; i < resourceFiles.Num(); i++ ) { fileName = path + "/" + resourceFiles[i]; common->Printf( "creating IDs for %s...\n", fileName.c_str() ); if ( !src.LoadFile( fileName, true ) ) { common->Warning( "couldn't load %s", fileName.c_str() ); continue; } dialogs.Clear(); resources.Clear(); bitmaps.Clear(); icons.Clear(); strings.Clear(); controls.Clear(); commands.Clear(); while( src.ReadToken( &token ) ) { if ( token == "#" ) { src.ExpectAnyToken( &token ); if ( token == "ifdef" || token == "ifndef" ) { src.SkipRestOfLine(); } else if ( token == "define" ) { src.ExpectTokenType( TT_NAME, 0, &token ); if ( token.Icmpn( "_APS_", 5 ) == 0 ) { continue; } if ( token.Icmpn( "IDD_", 4 ) == 0 ) { dialogs.AddUnique( token ); } else if ( token.Icmpn( "IDR_", 4 ) == 0 ) { resources.AddUnique( token ); } else if ( token.Icmpn( "IDB_", 4 ) == 0 ) { bitmaps.AddUnique( token ); } else if ( token.Icmpn( "IDI_", 4 ) == 0 ) { icons.AddUnique( token ); } else if ( token.Icmpn( "IDS_", 4 ) == 0 || token.Icmpn( "IDP_", 4 ) == 0 ) { strings.AddUnique( token ); } else if ( token.Icmpn( "IDC_", 4 ) == 0 ) { controls.AddUnique( token ); } else { commands.AddUnique( token ); } } } } src.FreeSource(); idFile *f; int curResource, curControl, curCommand; curResource = i ? i * 1000 : 100; curCommand = 20000 + i * 1000; curControl = i * 1000 + 200; f = fileSystem->OpenExplicitFileWrite( fileName ); if ( !f ) { common->Warning( "couldn't write %s", fileName.c_str() ); continue; } f->WriteFloatString( "//{{NO_DEPENDENCIES}}\n" "// Microsoft Visual C++ generated include file.\n" "// Used by .rc\n" "//\n\n" ); for ( j = 0; j < dialogs.Num(); j++ ) { f->WriteFloatString( "#define %-40s %d\n", dialogs[j].c_str(), curResource++ ); } for ( j = 0; j < resources.Num(); j++ ) { f->WriteFloatString( "#define %-40s %d\n", resources[j].c_str(), curResource++ ); } for ( j = 0; j < bitmaps.Num(); j++ ) { f->WriteFloatString( "#define %-40s %d\n", bitmaps[j].c_str(), curResource++ ); } for ( j = 0; j < icons.Num(); j++ ) { f->WriteFloatString( "#define %-40s %d\n", icons[j].c_str(), curResource++ ); } for ( j = 0; j < strings.Num(); j++ ) { f->WriteFloatString( "#define %-40s %d\n", strings[j].c_str(), curResource++ ); } f->WriteFloatString( "\n" ); for ( j = 0; j < controls.Num(); j++ ) { f->WriteFloatString( "#define %-40s %d\n", controls[j].c_str(), curControl++ ); } f->WriteFloatString( "\n" ); for ( j = 0; j < commands.Num(); j++ ) { // NOTE: special hack for Radiant if ( commands[j].Cmp( "ID_ENTITY_START" ) == 0 ) { f->WriteFloatString( "#define %-40s %d\n", commands[j].c_str(), 40000 ); continue; } if ( commands[j].Cmp( "ID_ENTITY_END" ) == 0 ) { f->WriteFloatString( "#define %-40s %d\n", commands[j].c_str(), 45000 ); continue; } f->WriteFloatString( "#define %-40s %d\n", commands[j].c_str(), curCommand++ ); } f->WriteFloatString( "\n// Next default values for new objects\n" "// \n" "#ifdef APSTUDIO_INVOKED\n" "#ifndef APSTUDIO_READONLY_SYMBOLS\n" "#define _APS_3D_CONTROLS 1\n" "#define _APS_NEXT_RESOURCE_VALUE %d\n" "#define _APS_NEXT_COMMAND_VALUE %d\n" "#define _APS_NEXT_CONTROL_VALUE %d\n" "#define _APS_NEXT_SYMED_VALUE %d\n" "#endif\n" "#endif\n", curResource, curCommand, curControl, curResource ); fileSystem->CloseFile( f ); } }
/** * @brief Recursively removes files matching a given pattern from homepath. * * Useful for removing incomplete downloads and other garbage. * Files listed in the com_cleanWhitelist cvar are protected from deletion. * Additionally, executable and configuration files are protected unless 'force' * argument is passed to this command. */ void Cmd_CleanHomepath_f(void) { int i, j, patternFiles = 0, delFiles = 0, totalFiles = 0; char path[MAX_OSPATH]; qboolean force = qfalse, pretend = qfalse; // *.so and *.dll are denied per default in FS_Remove but throw a Com_Error() -> game aborts const char whitelist[] = ".txt .cfg .dat .gm .way .so .dll"; if (Cmd_Argc() < 3) { // files in fs_homepath are downloaded again when required - but better print a warning for inexperienced users Com_Printf("usage: clean [force | pretend] [modname / all] [pattern 1] [pattern n]\n" "example: clean all *tmp */zzz* etmain/etkey\n" "Warning: This command deletes files in fs_homepath. If you are not sure how to use this command do not play with fire!\n"); return; } // if home- and basepath are same better don't start to clean ... if (FS_IsSamePath(Cvar_VariableString("fs_homepath"), Cvar_VariableString("fs_basepath"))) { Com_Printf("Invalid configuration to run clean cmd - 'fs_homepath' and 'fs_basepath' are equal.\n"); return; } // avoid unreferenced pk3 runtime issues (not on HD but still referenced in game) #ifndef DEDICATED if (cls.state != CA_DISCONNECTED) { Com_Printf("You are connected to a server - enter '/disconnect' to run '/clean'.\n"); return; } #else if (com_sv_running && com_sv_running->integer) { Com_Printf("Server is running - enter '/killserver' to run '/clean'.\n"); return; } #endif // DEDICATED Cvar_VariableStringBuffer("fs_homepath", path, sizeof(path)); // if there are any command options, they must be at the very beginning for (i = 1; i < Cmd_Argc(); i++) { if (!Q_stricmp(Cmd_Argv(i), "force") || !Q_stricmp(Cmd_Argv(i), "f")) { force = qtrue; continue; } if (!Q_stricmp(Cmd_Argv(i), "pretend") || !Q_stricmp(Cmd_Argv(i), "p")) { pretend = qtrue; continue; } break; } // if the first argument is "all" or "*", search the whole homepath if (Q_stricmp(Cmd_Argv(i), "all") && Q_stricmp(Cmd_Argv(i), "*")) { Q_strcat(path, sizeof(path), va("%c%s", PATH_SEP, Cmd_Argv(i))); // check if it points to a valid directory if (FS_OSStatFile(path) != 1) { Com_Printf("Cannot commence cleaning, because \"%s\" is not a valid directory under fs_homepath (%s)\n", Cmd_Argv(i), path); return; } } for (i++; i < Cmd_Argc(); i++) { char **pFiles = NULL; pFiles = Sys_ListFiles(path, NULL, Cmd_Argv(i), &patternFiles, qtrue); Com_Printf("Found %i files matching the pattern \"%s\" under %s\n", patternFiles, Cmd_Argv(i), path); for (j = 0; j < patternFiles; j++) { char *tokens; char tmp_whitelist[MAX_OSPATH]; qboolean whitelisted = qfalse; totalFiles++; Q_strncpyz(tmp_whitelist, (force ? Cvar_VariableString("com_cleanwhitelist") : va("%s %s", Cvar_VariableString("com_cleanwhitelist"), whitelist)), sizeof(tmp_whitelist)); // Check if this file is in the whitelist tokens = strtok(tmp_whitelist, " ,;"); while (tokens != NULL) { if (strstr(pFiles[j], tokens)) { Com_Printf("- skipping file[%i]: %s%c%s (whitelisted by pattern: %s)\n", j + 1, path, PATH_SEP, pFiles[j], tokens); whitelisted = qtrue; break; } tokens = strtok(NULL, " ,;"); } if (whitelisted) { continue; } if (!pretend) { Com_Printf("- removing file[%i]: %s%c%s\n", j + 1, path, PATH_SEP, pFiles[j]); if (force) { remove(va("%s%c%s", path, PATH_SEP, pFiles[j])); // enable *.so & *.dll lib deletion } else { FS_Remove(va("%s%c%s", path, PATH_SEP, pFiles[j])); } delFiles++; } else { Com_Printf("- pretending to remove file[%i]: %s%c%s\n", j + 1, path, PATH_SEP, pFiles[j]); } } Sys_FreeFileList(pFiles); patternFiles = 0; } Com_Printf("Path of fs_homepath cleaned - %i matches - %i files skipped - %i files deleted.\n", totalFiles, totalFiles - delFiles, delFiles); }
// returns true if at least one set of skin data was read, else false... // static bool Skins_Read(LPCSTR psModelFilename) { LPCSTR psError = NULL; CWaitCursor; LPCSTR psSkinsPath = Skins_ModelNameToSkinPath(psModelFilename); // eg "models/characters/skins" if (psSkinsPath) { string strThisModelBaseName(String_ToLower(Filename_WithoutExt(Filename_WithoutPath(psModelFilename)))); char **ppsSkinFiles; int iSkinFiles; // scan for skin files... // ppsSkinFiles = //ri.FS_ListFiles( "shaders", ".shader", &iSkinFiles ); Sys_ListFiles( va("%s%s",gamedir,psSkinsPath),// const char *directory, ".g2skin", // const char *extension, NULL, // char *filter, &iSkinFiles,// int *numfiles, qfalse // qboolean wantsubs ); if ( !ppsSkinFiles || !iSkinFiles ) { CurrentSkins.clear(); CurrentSkinsSurfacePrefs.clear(); return false; } if ( iSkinFiles > MAX_SKIN_FILES ) { WarningBox(va("%d skin files found, capping to %d\n\n(tell me if this ever happens -Ste)", iSkinFiles, MAX_SKIN_FILES )); iSkinFiles = MAX_SKIN_FILES; } // load and parse skin files... // // for now, I just scan each file and if it's out of date then I invalidate it's model-prefs info... // extern bool GetFileTime(LPCSTR psFileName, FILETIME &ft); for (int i=0; i<iSkinFiles; i++) { bool bReParseThisFile = false; char sFileName[MAX_QPATH]; LPCSTR psFileName = ppsSkinFiles[i]; Com_sprintf( sFileName, sizeof( sFileName ), "%s/%s", psSkinsPath, psFileName ); psFileName = &sFileName[0]; // have a go at getting this time/date stamp if not already present... // if (!SkinFileTimeDates[psFileName].bValid) { FILETIME ft; if (GetFileTime(psFileName, ft)) { SkinFileTimeDates[psFileName].ft = ft; SkinFileTimeDates[psFileName].bValid = true; } } // now see if there's a valid time-stamp, and use it if so, else give up and re-scan all files... // if (SkinFileTimeDates[psFileName].bValid) { FILETIME ft; if (GetFileTime(psFileName, ft)) { LONG l = CompareFileTime( &SkinFileTimeDates[psFileName].ft, &ft); bReParseThisFile = (l<0); } else { bReParseThisFile = true; } } else { bReParseThisFile = true; } if (bReParseThisFile) { G2SkinModelPrefs[sFileName].clear(); } } if (1)//bReParseSkinFiles || !CurrentSkins.size()) { CurrentSkins.clear(); CurrentSkinsSurfacePrefs.clear(); char *buffers[MAX_SKIN_FILES]={0}; // long iTotalBytesLoaded = 0; for ( int i=0; i<iSkinFiles && !psError; i++ ) { char sFileName[MAX_QPATH]; string strThisSkinFile(ppsSkinFiles[i]); Com_sprintf( sFileName, sizeof( sFileName ), "%s/%s", psSkinsPath, strThisSkinFile.c_str() ); StatusMessage( va("Scanning skin %d/%d: \"%s\"...",i+1,iSkinFiles,sFileName)); //ri.Printf( PRINT_ALL, "...loading '%s'\n", sFileName ); bool _bDiskLoadOccured = false; // debug use only, but wtf? #define LOAD_SKIN_FILE \ /*iTotalBytesLoaded += */ ri.FS_ReadFile( sFileName, (void **)&buffers[i] ); \ if ( !buffers[i] ) \ { \ CurrentSkins.clear(); \ CurrentSkinsSurfacePrefs.clear(); \ \ ri.Error( ERR_DROP, "Couldn't load %s", sFileName );\ } \ _bDiskLoadOccured = true; // see if we should pay attention to the contents of this file... // CGPGroup *pFileGroup = NULL; CGPGroup *pParseGroup_Prefs = NULL; CGenericParser2 SkinParser; // bool bParseThisFile = false; // // if we have any information about this skin file as regards what models it refers to, use the info... // if (G2SkinModelPrefs[sFileName].size()) { map<string, int>::iterator it = G2SkinModelPrefs[sFileName].find( strThisModelBaseName ); if (it != G2SkinModelPrefs[sFileName].end()) { // this skin file contains this entry, so just check that we can setup the parse groups ok... // LOAD_SKIN_FILE; char *psDataPtr = buffers[i]; if (SkinParser.Parse(&psDataPtr, true)) { pFileGroup = SkinParser.GetBaseParseGroup(); if (pFileGroup) { pParseGroup_Prefs = pFileGroup->FindSubGroup(sSKINKEYWORD_PREFS);//, true); if (pParseGroup_Prefs) { bParseThisFile = true; } } } else { ErrorBox(va("{} - Brace mismatch error in file \"%s\"!",sFileName)); } } } else { // no size info for this file, so check it manually... // LOAD_SKIN_FILE; if (Skins_ParseThisFile(SkinParser, buffers[i], strThisModelBaseName, pFileGroup, pParseGroup_Prefs, sFileName, G2SkinModelPrefs) ) { bParseThisFile = true; } } if (bParseThisFile) { psError = Skins_Parse( strThisSkinFile, pFileGroup, pParseGroup_Prefs); if (psError) { ErrorBox(va("Skins_Read(): Error reading file \"%s\"!\n\n( Skins will be ignored for this model )\n\nError was:\n\n",sFileName,psError)); } } else { //OutputDebugString(va("Skipping parse of file \"%s\" %s\n",sFileName, _bDiskLoadOccured?"":"( and no load! )")); } } // // free loaded skin files... // for ( i=0; i<iSkinFiles; i++ ) { if (buffers[i]) { ri.FS_FreeFile( buffers[i] ); } } } StatusMessage(NULL); Sys_FreeFileList( ppsSkinFiles ); } else { CurrentSkins.clear(); CurrentSkinsSurfacePrefs.clear(); } if (psError) { return false; } return !!(CurrentSkins.size()); }
/** * @brief Recursively removes files matching a given pattern from homepath. * Useful for removing incomplete downloads and other garbage. * Files listed in the com_cleanWhitelist cvar are protected from deletion. */ void Cmd_CleanHomepath_f(void) { int i, j, k, numFiles = 0; char **pFiles = NULL, *tokens; char path[MAX_OSPATH], whitelist[MAX_OSPATH]; qboolean whitelisted; if (Cmd_Argc() < 3) { Com_Printf("usage: clean <mod> <pattern[s]>\n"); Com_Printf("example: clean all *tmp zzz* etmain/etkey\n"); return; } Cvar_VariableStringBuffer("fs_homepath", path, sizeof(path)); Cvar_VariableStringBuffer("com_cleanwhitelist", whitelist, sizeof(whitelist)); // Prevent clumsy users from deleting important files Q_strcat(whitelist, sizeof(whitelist), " .txt .cfg .dat .gm .way omnibot_et.so omnibot_et.dll"); Com_DPrintf("Whitelist: %s\n", whitelist); // If the first argument is "all" or "*", search the whole homepath if (Q_stricmp(Cmd_Argv(1), "all") && Q_stricmp(Cmd_Argv(1), "*")) { Q_strcat(path, sizeof(path), va("%c%s", PATH_SEP, Cmd_Argv(1))); } for (i = 2; i < Cmd_Argc(); i++) { pFiles = Sys_ListFiles(path, NULL, Cmd_Argv(i), &numFiles, qtrue); Com_Printf("Found %i files matching the pattern \"%s\" under %s\n", numFiles, Cmd_Argv(i), path); for (j = 0; j < numFiles; j++) { for (k = 0; k < ARRAY_LEN(whitelist); k++) { whitelisted = qfalse; // Check if this file is in the whitelist tokens = strtok(whitelist, " ,;"); while (tokens != NULL) { if (strstr(pFiles[j], tokens)) { Com_Printf("- skipping whitelisted file %s\n", pFiles[j]); whitelisted = qtrue; break; } tokens = strtok(NULL, " ,;"); } if (whitelisted) { break; } if (k == STRARRAY_LEN(whitelist)) { Com_Printf("- removing %s\n", pFiles[j]); FS_Remove(va("%s%c%s", path, PATH_SEP, pFiles[j])); } } } Sys_FreeFileList(pFiles); numFiles = 0; } }