2014-03-15 16:59:03 +00:00
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1998-2000 by DooM Legacy Team.
// Copyright (C) 1999-2014 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file d_netfil.c
/// \brief Transfer a file using HSendPacket.
# include <stdio.h>
# ifndef _WIN32_WCE
# ifdef __OS2__
# include <sys/types.h>
# endif // __OS2__
# include <sys/stat.h>
# endif
# if !defined (UNDER_CE)
# include <time.h>
# endif
# if ((defined (_WIN32) && !defined (_WIN32_WCE)) || defined (__DJGPP__)) && !defined (_XBOX)
# include <io.h>
# include <direct.h>
# elif !defined (_WIN32_WCE) && !(defined (_XBOX) && !defined (__GNUC__))
# include <sys/types.h>
# include <dirent.h>
# include <utime.h>
# endif
# ifdef __GNUC__
# include <unistd.h>
# include <limits.h>
# elif defined (_WIN32) && !defined (_WIN32_WCE)
# include <sys/utime.h>
# endif
# ifdef __DJGPP__
# include <dir.h>
# include <utime.h>
# endif
# include "doomdef.h"
# include "doomstat.h"
# include "d_main.h"
# include "g_game.h"
# include "i_net.h"
# include "i_system.h"
# include "m_argv.h"
# include "d_net.h"
# include "w_wad.h"
# include "d_netfil.h"
# include "z_zone.h"
# include "byteptr.h"
# include "p_setup.h"
# include "m_misc.h"
# include "m_menu.h"
# include "md5.h"
# include "filesrch.h"
2014-04-14 05:14:58 +00:00
# include <errno.h>
2014-03-15 16:59:03 +00:00
static void SendFile ( INT32 node , const char * filename , UINT8 fileid ) ;
// sender structure
typedef struct filetx_s
{
INT32 ram ;
char * filename ; // name of the file or ptr of the data in ram
UINT32 size ;
UINT8 fileid ;
INT32 node ; // destination
struct filetx_s * next ; // a queue
} filetx_t ;
// current transfers (one for each node)
typedef struct filetran_s
{
filetx_t * txlist ;
UINT32 position ;
FILE * currentfile ;
} filetran_t ;
static filetran_t transfer [ MAXNETNODES ] ;
// read time of file: stat _stmtime
// write time of file: utime
// receiver structure
INT32 fileneedednum ;
fileneeded_t fileneeded [ MAX_WADFILES ] ;
char downloaddir [ 256 ] = " DOWNLOAD " ;
# ifdef CLIENT_LOADINGSCREEN
// for cl loading screen
INT32 lastfilenum = 0 ;
# endif
/** Fills a serverinfo packet with information about wad files loaded.
*
* \ todo Give this function a better name since it is in global scope .
*/
UINT8 * PutFileNeeded ( void )
{
size_t i , count = 0 ;
UINT8 * p = netbuffer - > u . serverinfo . fileneeded ;
char wadfilename [ MAX_WADPATH ] = " " ;
UINT8 filestatus ;
size_t bytesused = 0 ;
for ( i = 0 ; i < numwadfiles ; i + + )
{
// if it has only music/sound lumps, mark it as unimportant
if ( W_VerifyNMUSlumps ( wadfiles [ i ] - > filename ) )
filestatus = 0 ;
else
filestatus = 1 ; // important
// Store in the upper four bits
if ( ! cv_downloading . value )
filestatus + = ( 2 < < 4 ) ; // won't send
else if ( ( wadfiles [ i ] - > filesize > ( UINT32 ) cv_maxsend . value * 1024 ) )
filestatus + = ( 0 < < 4 ) ; // won't send
else
filestatus + = ( 1 < < 4 ) ; // will send if requested
bytesused + = ( nameonlylength ( wadfilename ) + 22 ) ;
// Don't write too far...
if ( bytesused > sizeof ( netbuffer - > u . serverinfo . fileneeded ) )
I_Error ( " Too many wad files added to host a game. (%s, stopped on %s) \n " , sizeu1 ( bytesused ) , wadfilename ) ;
WRITEUINT8 ( p , filestatus ) ;
count + + ;
WRITEUINT32 ( p , wadfiles [ i ] - > filesize ) ;
nameonly ( strcpy ( wadfilename , wadfiles [ i ] - > filename ) ) ;
WRITESTRINGN ( p , wadfilename , MAX_WADPATH ) ;
WRITEMEM ( p , wadfiles [ i ] - > md5sum , 16 ) ;
}
netbuffer - > u . serverinfo . fileneedednum = ( UINT8 ) count ;
return p ;
}
// parse the serverinfo packet and fill fileneeded table on client
void D_ParseFileneeded ( INT32 fileneedednum_parm , UINT8 * fileneededstr )
{
INT32 i ;
UINT8 * p ;
UINT8 filestatus ;
fileneedednum = fileneedednum_parm ;
p = ( UINT8 * ) fileneededstr ;
for ( i = 0 ; i < fileneedednum ; i + + )
{
fileneeded [ i ] . status = FS_NOTFOUND ;
filestatus = READUINT8 ( p ) ;
fileneeded [ i ] . important = ( UINT8 ) ( filestatus & 3 ) ;
fileneeded [ i ] . willsend = ( UINT8 ) ( filestatus > > 4 ) ;
fileneeded [ i ] . totalsize = READUINT32 ( p ) ;
fileneeded [ i ] . phandle = NULL ;
READSTRINGN ( p , fileneeded [ i ] . filename , MAX_WADPATH ) ;
READMEM ( p , fileneeded [ i ] . md5sum , 16 ) ;
}
}
void CL_PrepareDownloadSaveGame ( const char * tmpsave )
{
fileneedednum = 1 ;
fileneeded [ 0 ] . status = FS_REQUESTED ;
fileneeded [ 0 ] . totalsize = UINT32_MAX ;
fileneeded [ 0 ] . phandle = NULL ;
memset ( fileneeded [ 0 ] . md5sum , 0 , 16 ) ;
strcpy ( fileneeded [ 0 ] . filename , tmpsave ) ;
}
/** Checks the server to see if we CAN download all the files,
* before starting to create them and requesting .
*/
boolean CL_CheckDownloadable ( void )
{
UINT8 i , dlstatus = 0 ;
for ( i = 0 ; i < fileneedednum ; i + + )
if ( fileneeded [ i ] . status ! = FS_FOUND & & fileneeded [ i ] . status ! = FS_OPEN & & fileneeded [ i ] . important )
{
if ( fileneeded [ i ] . willsend = = 1 )
continue ;
if ( fileneeded [ i ] . willsend = = 0 )
dlstatus = 1 ;
else //if (fileneeded[i].willsend == 2)
dlstatus = 2 ;
}
// Downloading locally disabled
if ( ! dlstatus & & M_CheckParm ( " -nodownload " ) )
dlstatus = 3 ;
if ( ! dlstatus )
return true ;
// not downloadable, put reason in console
CONS_Alert ( CONS_NOTICE , M_GetText ( " You need additional files to connect to this server: \n " ) ) ;
for ( i = 0 ; i < fileneedednum ; i + + )
if ( fileneeded [ i ] . status ! = FS_FOUND & & fileneeded [ i ] . status ! = FS_OPEN & & fileneeded [ i ] . important )
{
CONS_Printf ( " * \" %s \" (%dK) " , fileneeded [ i ] . filename , fileneeded [ i ] . totalsize > > 10 ) ;
if ( fileneeded [ i ] . status = = FS_NOTFOUND )
CONS_Printf ( M_GetText ( " not found, md5: " ) ) ;
else if ( fileneeded [ i ] . status = = FS_MD5SUMBAD )
CONS_Printf ( M_GetText ( " wrong version, md5: " ) ) ;
{
INT32 j ;
char md5tmp [ 33 ] ;
for ( j = 0 ; j < 16 ; j + + )
sprintf ( & md5tmp [ j * 2 ] , " %02x " , fileneeded [ i ] . md5sum [ j ] ) ;
CONS_Printf ( " %s " , md5tmp ) ;
}
CONS_Printf ( " \n " ) ;
}
switch ( dlstatus )
{
case 1 :
CONS_Printf ( M_GetText ( " Some files are larger than the server is willing to send. \n " ) ) ;
break ;
case 2 :
CONS_Printf ( M_GetText ( " The server is not allowing download requests. \n " ) ) ;
break ;
case 3 :
CONS_Printf ( M_GetText ( " All files downloadable, but you have chosen to disable downloading locally. \n " ) ) ;
break ;
}
return false ;
}
/** Send requests for files in the ::fileneeded table with a status of
* : : FS_NOTFOUND .
*/
boolean CL_SendRequestFile ( void )
{
char * p ;
INT32 i ;
INT64 totalfreespaceneeded = 0 , availablefreespace ;
# ifdef PARANOIA
if ( M_CheckParm ( " -nodownload " ) )
I_Error ( " Attempted to download files in -nodownload mode " ) ;
for ( i = 0 ; i < fileneedednum ; i + + )
if ( fileneeded [ i ] . status ! = FS_FOUND & & fileneeded [ i ] . status ! = FS_OPEN
& & fileneeded [ i ] . important & & ( fileneeded [ i ] . willsend = = 0 | | fileneeded [ i ] . willsend = = 2 ) )
{
I_Error ( " Attempted to download files that were not sendable " ) ;
}
# endif
netbuffer - > packettype = PT_REQUESTFILE ;
p = ( char * ) netbuffer - > u . textcmd ;
for ( i = 0 ; i < fileneedednum ; i + + )
if ( ( fileneeded [ i ] . status = = FS_NOTFOUND | | fileneeded [ i ] . status = = FS_MD5SUMBAD )
& & fileneeded [ i ] . important )
{
totalfreespaceneeded + = fileneeded [ i ] . totalsize ;
nameonly ( fileneeded [ i ] . filename ) ;
WRITEUINT8 ( p , i ) ; // fileid
WRITESTRINGN ( p , fileneeded [ i ] . filename , MAX_WADPATH ) ;
// put it in download dir
strcatbf ( fileneeded [ i ] . filename , downloaddir , " / " ) ;
fileneeded [ i ] . status = FS_REQUESTED ;
}
WRITEUINT8 ( p , 0xFF ) ;
I_GetDiskFreeSpace ( & availablefreespace ) ;
if ( totalfreespaceneeded > availablefreespace )
I_Error ( " To play on this server you must download %s KB, \n "
" but you have only %s KB free space on this drive \n " ,
sizeu1 ( ( size_t ) ( totalfreespaceneeded > > 10 ) ) , sizeu2 ( ( size_t ) ( availablefreespace > > 10 ) ) ) ;
// prepare to download
I_mkdir ( downloaddir , 0755 ) ;
return HSendPacket ( servernode , true , 0 , p - ( char * ) netbuffer - > u . textcmd ) ;
}
// get request filepak and put it on the send queue
void Got_RequestFilePak ( INT32 node )
{
char wad [ MAX_WADPATH + 1 ] ;
UINT8 * p = netbuffer - > u . textcmd ;
UINT8 id ;
while ( p < netbuffer - > u . textcmd + MAXTEXTCMD - 1 ) // Don't allow hacked client to overflow
{
id = READUINT8 ( p ) ;
if ( id = = 0xFF )
break ;
READSTRINGN ( p , wad , MAX_WADPATH ) ;
SendFile ( node , wad , id ) ;
}
}
// client check if the fileneeded aren't already loaded or on the disk
INT32 CL_CheckFiles ( void )
{
INT32 i , j ;
char wadfilename [ MAX_WADPATH ] ;
INT32 ret = 1 ;
// if (M_CheckParm("-nofiles"))
// return 1;
// the first is the iwad (the main wad file)
// we don't care if it's called srb2.srb or srb2.wad.
// Never download the IWAD, just assume it's there and identical
fileneeded [ 0 ] . status = FS_OPEN ;
// Modified game handling -- check for an identical file list
// must be identical in files loaded AND in order
// Return 2 on failure -- disconnect from server
if ( modifiedgame )
{
CONS_Debug ( DBG_NETPLAY , " game is modified; only doing basic checks \n " ) ;
for ( i = 1 , j = 1 ; i < fileneedednum | | j < numwadfiles ; )
{
if ( i < fileneedednum & & ! fileneeded [ i ] . important )
{
// Eh whatever, don't care
+ + i ;
continue ;
}
if ( j < numwadfiles & & W_VerifyNMUSlumps ( wadfiles [ j ] - > filename ) )
{
// unimportant on our side. still don't care.
+ + j ;
continue ;
}
// If this test is true, we've reached the end of one file list
// and the other still has a file that's important
if ( i > = fileneedednum | | j > = numwadfiles )
return 2 ;
// for the sake of speed, only bother with a md5 check
if ( memcmp ( wadfiles [ j ] - > md5sum , fileneeded [ i ] . md5sum , 16 ) )
return 2 ;
// it's accounted for! let's keep going.
CONS_Debug ( DBG_NETPLAY , " '%s' accounted for \n " , fileneeded [ i ] . filename ) ;
fileneeded [ i ] . status = FS_OPEN ;
+ + i ;
+ + j ;
}
return 1 ;
}
for ( i = 1 ; i < fileneedednum ; i + + )
{
CONS_Debug ( DBG_NETPLAY , " searching for '%s' " , fileneeded [ i ] . filename ) ;
// check in allready loaded files
for ( j = 1 ; wadfiles [ j ] ; j + + )
{
nameonly ( strcpy ( wadfilename , wadfiles [ j ] - > filename ) ) ;
if ( ! stricmp ( wadfilename , fileneeded [ i ] . filename ) & &
! memcmp ( wadfiles [ j ] - > md5sum , fileneeded [ i ] . md5sum , 16 ) )
{
CONS_Debug ( DBG_NETPLAY , " already loaded \n " ) ;
fileneeded [ i ] . status = FS_OPEN ;
break ;
}
}
if ( fileneeded [ i ] . status ! = FS_NOTFOUND | | ! fileneeded [ i ] . important )
continue ;
fileneeded [ i ] . status = findfile ( fileneeded [ i ] . filename , fileneeded [ i ] . md5sum , true ) ;
CONS_Debug ( DBG_NETPLAY , " found %d \n " , fileneeded [ i ] . status ) ;
if ( fileneeded [ i ] . status ! = FS_FOUND )
ret = 0 ;
}
return ret ;
}
// load it now
void CL_LoadServerFiles ( void )
{
INT32 i ;
// if (M_CheckParm("-nofiles"))
// return;
for ( i = 1 ; i < fileneedednum ; i + + )
{
if ( fileneeded [ i ] . status = = FS_OPEN )
continue ; // already loaded
else if ( fileneeded [ i ] . status = = FS_FOUND )
{
P_AddWadFile ( fileneeded [ i ] . filename , NULL ) ;
G_SetGameModified ( true ) ;
fileneeded [ i ] . status = FS_OPEN ;
}
else if ( fileneeded [ i ] . status = = FS_MD5SUMBAD )
{
// If the file is marked important, don't even bother proceeding.
if ( fileneeded [ i ] . important )
I_Error ( " Wrong version of important file %s " , fileneeded [ i ] . filename ) ;
// If it isn't, no need to worry the user with a console message,
// although it can't hurt to put something in the debug file.
// ...but wait a second. What if the local version is "important"?
if ( ! W_VerifyNMUSlumps ( fileneeded [ i ] . filename ) )
I_Error ( " File %s should only contain music and sound effects! " ,
fileneeded [ i ] . filename ) ;
// Okay, NOW we know it's safe. Whew.
P_AddWadFile ( fileneeded [ i ] . filename , NULL ) ;
if ( fileneeded [ i ] . important )
G_SetGameModified ( true ) ;
fileneeded [ i ] . status = FS_OPEN ;
DEBFILE ( va ( " File %s found but with different md5sum \n " , fileneeded [ i ] . filename ) ) ;
}
else if ( fileneeded [ i ] . important )
I_Error ( " Try to load file %s with status of %d \n " , fileneeded [ i ] . filename ,
fileneeded [ i ] . status ) ;
}
}
// little optimization to test if there is a file in the queue
static INT32 filetosend = 0 ;
static void SendFile ( INT32 node , const char * filename , UINT8 fileid )
{
filetx_t * * q ;
filetx_t * p ;
INT32 i ;
char wadfilename [ MAX_WADPATH ] ;
q = & transfer [ node ] . txlist ;
while ( * q )
q = & ( ( * q ) - > next ) ;
p = * q = ( filetx_t * ) malloc ( sizeof ( filetx_t ) ) ;
if ( p )
memset ( p , 0 , sizeof ( filetx_t ) ) ;
else
I_Error ( " SendFile: No more ram \n " ) ;
p - > filename = ( char * ) malloc ( MAX_WADPATH ) ;
if ( ! p - > filename )
I_Error ( " SendFile: No more ram \n " ) ;
// a minimum of security, can get only file in srb2 direcory
strlcpy ( p - > filename , filename , MAX_WADPATH ) ;
nameonly ( p - > filename ) ;
// check first in wads loaded the majority of case
for ( i = 0 ; wadfiles [ i ] ; i + + )
{
strlcpy ( wadfilename , wadfiles [ i ] - > filename , MAX_WADPATH ) ;
nameonly ( wadfilename ) ;
if ( ! stricmp ( wadfilename , p - > filename ) )
{
// copy filename with full path
strlcpy ( p - > filename , wadfiles [ i ] - > filename , MAX_WADPATH ) ;
break ;
}
}
if ( ! wadfiles [ i ] )
{
DEBFILE ( va ( " %s not found in wadfiles \n " , filename ) ) ;
// this formerly checked if (!findfile(p->filename, NULL, true))
// not found
// don't inform client (probably hacker)
DEBFILE ( va ( " Client %d request %s: not found \n " , node , filename ) ) ;
free ( p - > filename ) ;
free ( p ) ;
* q = NULL ;
return ;
}
if ( wadfiles [ i ] - > filesize > ( UINT32 ) cv_maxsend . value * 1024 )
{
// too big
// don't inform client (client sucks, man)
DEBFILE ( va ( " Client %d request %s: file too big, not sending \n " , node , filename ) ) ;
free ( p - > filename ) ;
free ( p ) ;
* q = NULL ;
return ;
}
DEBFILE ( va ( " Sending file %s (id=%d) to %d \n " , filename , fileid , node ) ) ;
p - > ram = SF_FILE ;
p - > fileid = fileid ;
p - > next = NULL ; // end of list
filetosend + + ;
}
void SendRam ( INT32 node , void * data , size_t size , freemethod_t freemethod , UINT8 fileid )
{
filetx_t * * q ;
filetx_t * p ;
q = & transfer [ node ] . txlist ;
while ( * q )
q = & ( ( * q ) - > next ) ;
p = * q = ( filetx_t * ) malloc ( sizeof ( filetx_t ) ) ;
if ( p )
memset ( p , 0 , sizeof ( filetx_t ) ) ;
else
I_Error ( " SendRam: No more ram \n " ) ;
p - > ram = freemethod ;
p - > filename = data ;
p - > size = ( UINT32 ) size ;
p - > fileid = fileid ;
p - > next = NULL ; // end of list
DEBFILE ( va ( " Sending ram %p(size:%u) to %d (id=%u) \n " , p - > filename , p - > size , node , fileid ) ) ;
filetosend + + ;
}
static void EndSend ( INT32 node )
{
filetx_t * p = transfer [ node ] . txlist ;
switch ( p - > ram )
{
case SF_FILE :
if ( transfer [ node ] . currentfile )
fclose ( transfer [ node ] . currentfile ) ;
free ( p - > filename ) ;
break ;
case SF_Z_RAM :
Z_Free ( p - > filename ) ;
break ;
case SF_RAM :
free ( p - > filename ) ;
case SF_NOFREERAM :
break ;
}
transfer [ node ] . txlist = p - > next ;
transfer [ node ] . currentfile = NULL ;
free ( p ) ;
filetosend - - ;
}
# define PACKETPERTIC net_bandwidth / (TICRATE*software_MAXPACKETLENGTH)
void FiletxTicker ( void )
{
static INT32 currentnode = 0 ;
filetx_pak * p ;
size_t size ;
filetx_t * f ;
INT32 packetsent = PACKETPERTIC , ram , i ;
if ( ! filetosend )
return ;
if ( ! packetsent )
packetsent + + ;
// (((sendbytes-nowsentbyte)*TICRATE)/(I_GetTime()-starttime)<(UINT32)net_bandwidth)
while ( packetsent - - & & filetosend ! = 0 )
{
for ( i = currentnode , ram = 0 ; ram < MAXNETNODES ;
i = ( i + 1 ) % MAXNETNODES , ram + + )
{
if ( transfer [ i ] . txlist )
goto found ;
}
// no transfer to do
I_Error ( " filetosend=%d but no filetosend found \n " , filetosend ) ;
found :
currentnode = ( i + 1 ) % MAXNETNODES ;
f = transfer [ i ] . txlist ;
ram = f - > ram ;
if ( ! transfer [ i ] . currentfile ) // file not already open
{
if ( ! ram )
{
long filesize ;
transfer [ i ] . currentfile =
fopen ( f - > filename , " rb " ) ;
if ( ! transfer [ i ] . currentfile )
I_Error ( " File %s does not exist " ,
f - > filename ) ;
fseek ( transfer [ i ] . currentfile , 0 , SEEK_END ) ;
filesize = ftell ( transfer [ i ] . currentfile ) ;
// Nobody wants to transfer a file bigger
// than 4GB!
if ( filesize > = LONG_MAX )
I_Error ( " filesize of %s is too large " , f - > filename ) ;
if ( - 1 = = filesize )
I_Error ( " Error getting filesize of %s " , f - > filename ) ;
f - > size = ( UINT32 ) filesize ;
fseek ( transfer [ i ] . currentfile , 0 , SEEK_SET ) ;
}
else
transfer [ i ] . currentfile = ( FILE * ) 1 ;
transfer [ i ] . position = 0 ;
}
p = & netbuffer - > u . filetxpak ;
size = software_MAXPACKETLENGTH - ( FILETXHEADER + BASEPACKETSIZE ) ;
if ( f - > size - transfer [ i ] . position < size )
size = f - > size - transfer [ i ] . position ;
if ( ram )
M_Memcpy ( p - > data , & f - > filename [ transfer [ i ] . position ] , size ) ;
else if ( fread ( p - > data , 1 , size , transfer [ i ] . currentfile ) ! = size )
I_Error ( " FiletxTicker: can't read %s byte on %s at %d because %s " , sizeu1 ( size ) , f - > filename , transfer [ i ] . position , strerror ( ferror ( transfer [ i ] . currentfile ) ) ) ;
p - > position = LONG ( transfer [ i ] . position ) ;
// put flag so receiver know the totalsize
if ( transfer [ i ] . position + size = = f - > size )
p - > position | = LONG ( 0x80000000 ) ;
p - > fileid = f - > fileid ;
p - > size = SHORT ( ( UINT16 ) size ) ;
netbuffer - > packettype = PT_FILEFRAGMENT ;
if ( ! HSendPacket ( i , true , 0 , FILETXHEADER + size ) ) // reliable SEND
{ // not sent for some odd reason, retry at next call
if ( ! ram )
fseek ( transfer [ i ] . currentfile , transfer [ i ] . position , SEEK_SET ) ;
// exit the while (can't send this one so why should i send the next?)
break ;
}
else // success
{
transfer [ i ] . position = ( UINT32 ) ( size + transfer [ i ] . position ) ;
if ( transfer [ i ] . position = = f - > size ) // finish ?
EndSend ( i ) ;
}
}
}
void Got_Filetxpak ( void )
{
INT32 filenum = netbuffer - > u . filetxpak . fileid ;
static INT32 filetime = 0 ;
if ( filenum > = fileneedednum )
{
DEBFILE ( va ( " fileframent not needed %d>%d \n " , filenum , fileneedednum ) ) ;
return ;
}
if ( fileneeded [ filenum ] . status = = FS_REQUESTED )
{
if ( fileneeded [ filenum ] . phandle ) I_Error ( " Got_Filetxpak: allready open file \n " ) ;
fileneeded [ filenum ] . phandle = fopen ( fileneeded [ filenum ] . filename , " wb " ) ;
2014-04-14 05:14:58 +00:00
if ( ! fileneeded [ filenum ] . phandle ) I_Error ( " Can't create file %s: %s " , fileneeded [ filenum ] . filename , strerror ( errno ) ) ;
2014-03-15 16:59:03 +00:00
CONS_Printf ( " \r %s... \n " , fileneeded [ filenum ] . filename ) ;
fileneeded [ filenum ] . currentsize = 0 ;
fileneeded [ filenum ] . status = FS_DOWNLOADING ;
}
if ( fileneeded [ filenum ] . status = = FS_DOWNLOADING )
{
UINT32 pos = LONG ( netbuffer - > u . filetxpak . position ) ;
UINT16 size = SHORT ( netbuffer - > u . filetxpak . size ) ;
// use a special tric to know when file is finished (not allways used)
// WARNING: filepak can arrive out of order so don't stop now !
if ( pos & 0x80000000 )
{
pos & = ~ 0x80000000 ;
fileneeded [ filenum ] . totalsize = pos + size ;
}
// we can receive packet in the wrong order, anyway all os support gaped file
fseek ( fileneeded [ filenum ] . phandle , pos , SEEK_SET ) ;
if ( fwrite ( netbuffer - > u . filetxpak . data , size , 1 , fileneeded [ filenum ] . phandle ) ! = 1 )
2014-04-14 05:14:58 +00:00
I_Error ( " Can't write to %s: %s \n " , fileneeded [ filenum ] . filename , strerror ( ferror ( fileneeded [ filenum ] . phandle ) ) ) ;
2014-03-15 16:59:03 +00:00
fileneeded [ filenum ] . currentsize + = size ;
// finished?
if ( fileneeded [ filenum ] . currentsize = = fileneeded [ filenum ] . totalsize )
{
fclose ( fileneeded [ filenum ] . phandle ) ;
fileneeded [ filenum ] . phandle = NULL ;
fileneeded [ filenum ] . status = FS_FOUND ;
CONS_Printf ( M_GetText ( " Downloading %s...(done) \n " ) ,
fileneeded [ filenum ] . filename ) ;
}
}
else
I_Error ( " Received a file not requested \n " ) ;
// send ack back quickly
if ( + + filetime = = 3 )
{
Net_SendAcks ( servernode ) ;
filetime = 0 ;
}
# ifdef CLIENT_LOADINGSCREEN
lastfilenum = filenum ;
# endif
}
void AbortSendFiles ( INT32 node )
{
while ( transfer [ node ] . txlist )
EndSend ( node ) ;
}
void CloseNetFile ( void )
{
INT32 i ;
// is sending?
for ( i = 0 ; i < MAXNETNODES ; i + + )
AbortSendFiles ( i ) ;
// receiving a file?
for ( i = 0 ; i < MAX_WADFILES ; i + + )
if ( fileneeded [ i ] . status = = FS_DOWNLOADING & & fileneeded [ i ] . phandle )
{
fclose ( fileneeded [ i ] . phandle ) ;
// file is not complete delete it
remove ( fileneeded [ i ] . filename ) ;
}
// remove FILEFRAGMENT from acknledge list
Net_AbortPacketType ( PT_FILEFRAGMENT ) ;
}
// functions cut and pasted from doomatic :)
void nameonly ( char * s )
{
size_t j , len ;
void * ns ;
for ( j = strlen ( s ) ; j ! = ( size_t ) - 1 ; j - - )
if ( ( s [ j ] = = ' \\ ' ) | | ( s [ j ] = = ' : ' ) | | ( s [ j ] = = ' / ' ) )
{
ns = & ( s [ j + 1 ] ) ;
len = strlen ( ns ) ;
if ( false )
M_Memcpy ( s , ns , len + 1 ) ;
else
memmove ( s , ns , len + 1 ) ;
return ;
}
}
// Returns the length in characters of the last element of a path.
size_t nameonlylength ( const char * s )
{
size_t j , len = strlen ( s ) ;
for ( j = len ; j ! = ( size_t ) - 1 ; j - - )
if ( ( s [ j ] = = ' \\ ' ) | | ( s [ j ] = = ' : ' ) | | ( s [ j ] = = ' / ' ) )
return len - j - 1 ;
return len ;
}
# ifndef O_BINARY
# define O_BINARY 0
# endif
filestatus_t checkfilemd5 ( char * filename , const UINT8 * wantedmd5sum )
{
# if defined (NOMD5) || defined (_arch_dreamcast)
( void ) wantedmd5sum ;
( void ) filename ;
# else
FILE * fhandle ;
UINT8 md5sum [ 16 ] ;
if ( ! wantedmd5sum )
return FS_FOUND ;
fhandle = fopen ( filename , " rb " ) ;
if ( fhandle )
{
md5_stream ( fhandle , md5sum ) ;
fclose ( fhandle ) ;
if ( ! memcmp ( wantedmd5sum , md5sum , 16 ) )
return FS_FOUND ;
return FS_MD5SUMBAD ;
}
I_Error ( " Couldn't open %s for md5 check " , filename ) ;
# endif
return FS_FOUND ; // will never happen, but makes the compiler shut up
}
filestatus_t findfile ( char * filename , const UINT8 * wantedmd5sum , boolean completepath )
{
filestatus_t homecheck = filesearch ( filename , srb2home , wantedmd5sum , false , 10 ) ;
if ( homecheck = = FS_FOUND )
return filesearch ( filename , srb2home , wantedmd5sum , completepath , 10 ) ;
homecheck = filesearch ( filename , srb2path , wantedmd5sum , false , 10 ) ;
if ( homecheck = = FS_FOUND )
return filesearch ( filename , srb2path , wantedmd5sum , completepath , 10 ) ;
# ifdef _arch_dreamcast
return filesearch ( filename , " /cd " , wantedmd5sum , completepath , 10 ) ;
# else
return filesearch ( filename , " . " , wantedmd5sum , completepath , 10 ) ;
# endif
}