mirror of
https://github.com/FWGS/xash3d-fwgs.git
synced 2026-08-05 03:24:56 +08:00
filesystem: use sendfile for faster FS_FileCopy on Linux
This commit is contained in:
@@ -24,6 +24,9 @@ GNU General Public License for more details.
|
|||||||
#if XASH_WIN32
|
#if XASH_WIN32
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
#endif
|
#endif
|
||||||
|
#if XASH_LINUX
|
||||||
|
#include <sys/sendfile.h>
|
||||||
|
#endif
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -1027,10 +1030,75 @@ FS_FileCopy
|
|||||||
*/
|
*/
|
||||||
qboolean FS_FileCopy( file_t *pOutput, file_t *pInput, int fileSize )
|
qboolean FS_FileCopy( file_t *pOutput, file_t *pInput, int fileSize )
|
||||||
{
|
{
|
||||||
char *buf = Mem_Malloc( fs_mempool, FILE_COPY_SIZE );
|
char *buf;
|
||||||
int size, readSize;
|
int size, readSize;
|
||||||
qboolean done = true;
|
qboolean done = true;
|
||||||
|
|
||||||
|
#if XASH_LINUX && !defined( XASH_REDUCE_FD )
|
||||||
|
// sendfile can't decompress, and we'd skip past userspace-buffered bytes
|
||||||
|
if( !FBitSet( pInput->flags, FILE_DEFLATED ) && pInput->ungetc == EOF && pInput->buff_ind == pInput->buff_len )
|
||||||
|
{
|
||||||
|
off_t out_pos;
|
||||||
|
|
||||||
|
// mirror FS_Write's pre-write fixup so the output fd offset matches file_t's position
|
||||||
|
if( pOutput->buff_ind != pOutput->buff_len )
|
||||||
|
lseek( pOutput->handle, pOutput->buff_ind - pOutput->buff_len, SEEK_CUR );
|
||||||
|
|
||||||
|
FS_Purge( pOutput );
|
||||||
|
|
||||||
|
off_t in_off = pInput->offset + pInput->position;
|
||||||
|
|
||||||
|
while( fileSize > 0 )
|
||||||
|
{
|
||||||
|
ssize_t sent = sendfile( pOutput->handle, pInput->handle, &in_off, fileSize );
|
||||||
|
|
||||||
|
if( sent < 0 )
|
||||||
|
{
|
||||||
|
if( errno == EINTR )
|
||||||
|
continue;
|
||||||
|
// some kernels/filesystems don't support sendfile between these fds
|
||||||
|
if( errno == EINVAL || errno == ENOSYS || errno == EOPNOTSUPP )
|
||||||
|
break;
|
||||||
|
Con_Reportf( S_ERROR "%s: sendfile failed: %s\n", __func__, strerror( errno ));
|
||||||
|
done = false;
|
||||||
|
fileSize = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( sent == 0 )
|
||||||
|
{
|
||||||
|
Con_Reportf( S_ERROR "%s: unexpected end of input file\n", __func__ );
|
||||||
|
done = false;
|
||||||
|
fileSize = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fileSize -= sent;
|
||||||
|
}
|
||||||
|
|
||||||
|
pInput->position = in_off - pInput->offset;
|
||||||
|
|
||||||
|
out_pos = lseek( pOutput->handle, 0, SEEK_CUR );
|
||||||
|
if( out_pos < 0 )
|
||||||
|
{
|
||||||
|
Con_Reportf( S_ERROR "%s: lseek failed: %s\n", __func__, strerror( errno ));
|
||||||
|
done = false;
|
||||||
|
fileSize = 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pOutput->position = out_pos;
|
||||||
|
if( pOutput->real_length < pOutput->position )
|
||||||
|
pOutput->real_length = pOutput->position;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( fileSize <= 0 )
|
||||||
|
return done;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
buf = Mem_Malloc( fs_mempool, FILE_COPY_SIZE );
|
||||||
|
|
||||||
while( fileSize > 0 )
|
while( fileSize > 0 )
|
||||||
{
|
{
|
||||||
if( fileSize > FILE_COPY_SIZE )
|
if( fileSize > FILE_COPY_SIZE )
|
||||||
|
|||||||
Reference in New Issue
Block a user