int Web_Get( const char *url, const char *referer, const char *name, int resume, int max_downloading_time, int timeout, int ( *_progress )(double), int noreuse ) { CURLcode code; int fsize; // init/reinit curl Web_Init(); code = curl_easy_setopt( curl, CURLOPT_URL, url ); if( code != CURLE_OK ) { Com_Printf( "Failed to set url\n" );; return 0; } if( referer ) { code = curl_easy_setopt( curl, CURLOPT_REFERER, referer ); if( code != CURLE_OK ) { Com_Printf( "Failed to set Referer\n" ); return 0; } } // connection timeout code = curl_easy_setopt( curl, CURLOPT_CONNECTTIMEOUT, timeout ); if( code != CURLE_OK ) { Com_Printf( "Failed to set libcurl connection timeout\n" ); return 0; } code = curl_easy_setopt( curl, CURLOPT_TIMEOUT, max_downloading_time ); if( code != CURLE_OK ) { Com_Printf( "Failed to set libcurl global timeout\n" ); return 0; } if( noreuse ) { code = curl_easy_setopt( curl, CURLOPT_FORBID_REUSE, 1 ); if( code != CURLE_OK ) { Com_Printf( "Failed to forbid reuse\n" ); return 0; } } if( resume == 1 ) { // test if file exist fsize = FS_FOpenAbsoluteFile( name, NULL, FS_READ ); if( fsize < 0 ) goto new_file; // file does not exist code = curl_easy_setopt( curl, CURLOPT_RESUME_FROM, fsize ); if( code != CURLE_OK ) { Com_Printf( "Failed to set file resume from length\n" ); return 0; } } else { // we will append to the file so if it already exist we will have twice the data // so delete the file if it exist FS_RemoveAbsoluteFile( name ); } new_file: code = curl_easy_setopt( curl, CURLOPT_WRITEDATA, name ); if( code != CURLE_OK ) { Com_Printf( "Failed to set writer data\n" ); return 0; } Com_DPrintf( "Downloading %s from %s\n", name, url ); // set callback progress = _progress; code = curl_easy_perform( curl ); if( code != CURLE_OK ) { Com_Printf( "Failed to download %s from %s\n", name, url ); Com_Printf( "Error: %s\n", curl_err ); Web_Cleanup(); return 0; } Web_Cleanup(); return 1; }
/* * SV_WebDownload */ static qboolean SV_WebDownload( const char *baseUrl, const char *filepath, qboolean overwrite, qboolean silent ) { qboolean success; int alloc_size; char *temppath, *writepath, *url; if( developer->integer ) silent = qfalse; if( !baseUrl || !baseUrl[0] || !filepath ) return qfalse; if( !strrchr( baseUrl, '/' ) ) { if( !silent ) Com_Printf( "SV_WebDownload: Invalid URL\n" ); return qfalse; } if( filepath[0] == '/' ) // filepath should never begin with a slash filepath++; if( !COM_ValidateRelativeFilename( filepath ) ) { if( !silent ) Com_Printf( "SV_WebDownload: Invalid filename\n" ); return qfalse; } if( !COM_FileExtension( filepath ) ) { if( !silent ) Com_Printf( "SV_WebDownload: no file extension\n" ); return qfalse; } // full url (baseurl + path) alloc_size = strlen( baseUrl ) + 1 + strlen( filepath ) + 1; url = Mem_TempMalloc( alloc_size ); if( baseUrl[ strlen( baseUrl ) - 1 ] == '/' ) // url includes last slash Q_snprintfz( url, alloc_size, "%s%s", baseUrl, filepath ); else Q_snprintfz( url, alloc_size, "%s/%s", baseUrl, filepath ); // add .tmp (relative + .tmp) alloc_size = strlen( filepath ) + strlen( ".tmp" ) + 1; temppath = Mem_TempMalloc( alloc_size ); Q_snprintfz( temppath, alloc_size, "%s.tmp", filepath ); // full write path for curl alloc_size = strlen( FS_WriteDirectory() ) + 1 + strlen( temppath ) + 1; writepath = Mem_TempMalloc( alloc_size ); Q_snprintfz( writepath, alloc_size, "%s/%s", FS_WriteDirectory(), temppath ); webDownloadPercentPrint = 0; webDownloadPercentStarted = qfalse; success = Web_Get( url, NULL, writepath, qtrue, 60 * 30, 60, SV_WebDownloadProgress, qfalse ); if( webDownloadPercentStarted ) Com_Printf( "\n" ); if( !success ) { if( !silent ) Com_Printf( "Failed to download remote file.\n" ); goto failed; } // rename the downloaded file if( !FS_MoveBaseFile( temppath, filepath ) ) { if( !overwrite ) { if( !silent ) Com_Printf( "Failed to rename temporary file.\n" ); goto failed; } // check if it failed because there already exists a file with the same name // and in this case remove this file if( FS_FOpenBaseFile( filepath, NULL, FS_READ ) != -1 ) { char *backfile; alloc_size = strlen( filepath ) + strlen( ".bak" ) + 1; backfile = Mem_TempMalloc( alloc_size ); Q_snprintfz( backfile, alloc_size, "%s.bak", filepath ); // if there is already a .bak file, destroy it if( FS_FOpenBaseFile( backfile, NULL, FS_READ ) != -1 ) FS_RemoveBaseFile( backfile ); // move the current file into .bak file if( !FS_MoveBaseFile( filepath, backfile ) ) { Mem_TempFree( backfile ); if( !silent ) Com_Printf( "Failed to backup destination file.\n" ); goto failed; } // now try renaming the downloaded file again if( !FS_MoveBaseFile( temppath, filepath ) ) { // didn't work, so restore the backup file if( FS_MoveBaseFile( backfile, filepath ) ) { if( !silent ) Com_Printf( "Failed to rename temporary file, restoring from backup.\n" ); } else { if( !silent ) Com_Printf( "Failed to rename temporary file and restore from backup.\n" ); } Mem_TempFree( backfile ); goto failed; } Mem_TempFree( backfile ); } } Mem_TempFree( temppath ); Mem_TempFree( writepath ); Mem_TempFree( url ); return qtrue; failed: if( !silent ) Com_Printf( "Removing temporary file: %s\n", writepath ); FS_RemoveAbsoluteFile( writepath ); Mem_TempFree( temppath ); Mem_TempFree( writepath ); Mem_TempFree( url ); return qfalse; }
/* * Com_UnloadGameLibrary */ void Com_UnloadGameLibrary( void **handle ) { gamelib_t *gamelib, *iter, *prev; assert( handle ); if( !handle ) return; gamelib = (gamelib_t *)*handle; if( !gamelib ) return; // remove it from the linked list if( gamelib == gamelibs ) { gamelibs = gamelib->next; } else { prev = NULL; iter = gamelibs; while( iter ) { if( iter == gamelib ) { assert( prev ); prev->next = iter->next; } prev = iter; iter = iter->next; } } // close lib, if not statically linked if( gamelib->lib ) { if( !Sys_Library_Close( gamelib->lib ) ) Com_Error( ERR_FATAL, "Sys_CloseLibrary failed" ); gamelib->lib = NULL; } // remove tempfile if it's not used by other instances if( gamelib->fullname ) { iter = gamelibs; while( iter ) { if( !strcmp( gamelib->fullname, iter->fullname ) ) break; iter = iter->next; } if( !iter ) { char *p; FS_RemoveAbsoluteFile( gamelib->fullname ); p = strrchr( gamelib->fullname, '/' ); if( p ) { *p = '\0'; FS_RemoveAbsoluteDirectory( gamelib->fullname ); } } Mem_ZoneFree( gamelib->fullname ); } Mem_ZoneFree( gamelib ); *handle = NULL; }