/*
Unix SMB / Netbios implementation .
Version 2.2 . x / 3.0 . x
sendfile implementations .
Copyright ( C ) Jeremy Allison 2002.
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
/*
* This file handles the OS dependent sendfile implementations .
* The API is such that it returns - 1 on error , else returns the
* number of bytes written .
*/
# include "includes.h"
# if defined(LINUX_SENDFILE_API)
# include <sys/sendfile.h>
# ifndef MSG_MORE
# define MSG_MORE 0x8000
# endif
ssize_t sys_sendfile ( int tofd , int fromfd , const DATA_BLOB * header , SMB_OFF_T offset , size_t count )
{
size_t total = 0 ;
ssize_t ret ;
ssize_t hdr_len = 0 ;
/*
* Send the header first .
* Use MSG_MORE to cork the TCP output until sendfile is called .
*/
if ( header ) {
hdr_len = header - > length ;
while ( total < hd_len ) {
ret = sys_send ( tofd , header - > data + total , hdr_len - total , MSG_MORE ) ;
if ( ret = = - 1 )
return - 1 ;
total + = ret ;
}
}
total = count ;
while ( total ) {
ssize_t nwritten ;
do {
# if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(SENDFILE64)
nwritten = sendfile64 ( tofd , fromfd , & offset , total ) ;
# else
nwritten = sendfile ( tofd , fromfd , & offset , total ) ;
# endif
} while ( nwritten = = - 1 & & errno = = EINTR ) ;
if ( nwritten = = - 1 )
return - 1 ;
if ( nwritten = = 0 )
return - 1 ; /* I think we're at EOF here... */
total - = nwritten ;
}
return count + hdr_len ;
}
# elif defined(SOLARIS_SENDFILE_API)
ssize_t sys_sendfile ( int tofd , int fromfd , const DATA_BLOB * header , SMB_OFF_T offset , size_t count )
{
}
# elif defined(HPUX_SENDFILE_API)
# include <sys/socket.h>
# include <sys/uio.h>
ssize_t sys_sendfile ( int tofd , int fromfd , const DATA_BLOB * header , SMB_OFF_T offset , size_t count )
{
size_t total = 0 ;
struct iovec hdtrl [ 2 ] ;
size_t hdr_len = 0 ;
if ( header ) {
/* Set up the header/trailer iovec. */
hdtrl [ 0 ] . iov_base = header - > data ;
hdtrl [ 0 ] . iov_len = hdr_len = header - > length ;
} else {
hdtrl [ 0 ] . iov_base = NULL ;
hdtrl [ 0 ] . iov_len = hdr_len = 0 ;
}
hdtrl [ 1 ] . iov_base = NULL ;
hdtrl [ 1 ] . iov_base = 0 ;
total = count ;
while ( total + hdtrl [ 0 ] . iov_len ) {
ssize_t nwritten ;
/*
* HPUX guarantees that if any data was written before
* a signal interrupt then sendfile returns the number of
* bytes written ( which may be less than requested ) not - 1.
* nwritten includes the header data sent .
*/
do {
# if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(SENDFILE64)
nwritten = sendfile64 ( tofd , fromfd , offset , total , & hdtrl [ 0 ] , 0 ) ;
# else
nwritten = sendfile ( tofd , fromfd , offset , total , & hdtrl [ 0 ] , 0 ) ;
# endif
} while ( nwritten = = - 1 & & errno = = EINTR ) ;
if ( nwritten = = - 1 )
return - 1 ;
if ( nwritten = = 0 )
return - 1 ; /* I think we're at EOF here... */
/*
* If this was a short ( signal interrupted ) write we may need
* to subtract it from the header data , or null out the header
* data altogether if we wrote more than hdtrl [ 0 ] . iov_len bytes .
* We change nwritten to be the number of file bytes written .
*/
if ( hdtrl [ 0 ] . iov_base & & hdtrl [ 0 ] . iov_len ) {
if ( nwritten > = hdtrl [ 0 ] . iov_len ) {
nwritten - = hdtrl [ 0 ] . iov_len ;
hdtrl [ 0 ] . iov_base = NULL ;
hdtrl [ 0 ] . iov_len = 0 ;
} else {
nwritten = 0 ;
hdtrl [ 0 ] . iov_base + = nwritten ;
hdtrl [ 0 ] . iov_len - = nwritten ;
}
}
total - = nwritten ;
offset + = nwritten ;
}
return count + hdr_len ;
}
# elif defined(FREEBSD_SENDFILE_API)
# include <sys/types.h>
# include <sys/socket.h>
# include <sys/uio.h>
ssize_t sys_sendfile ( int tofd , int fromfd , const DATA_BLOB * header , SMB_OFF_T offset , size_t count )
{
size_t total = 0 ;
struct sf_hdtr hdr ;
struct iovec hdtrl ;
size_t hdr_len = 0 ;
hdr - > headers = & hdtrl ;
hdr - > hdr_cnt = 1 ;
hdr - > trailers = NULL ;
hdr - > trl_cnt = 0 ;
/* Set up the header iovec. */
if ( header ) {
hdtrl . iov_base = header - > data ;
hdtrl . iov_len = hdr_len = header - > length ;
} else {
hdtrl . iov_base = NULL ;
hdtrl . iov_len = 0 ;
}
total = count ;
while ( total + hdtrl . iov_len ) {
SMB_OFF_T nwritten ;
int ret ;
/*
* FreeBSD sendfile returns 0 on success , - 1 on error .
* Remember , the tofd and fromfd are reversed . . . . . : - ) .
* nwritten includes the header data sent .
*/
do {
ret = sendfile ( fromfd , tofd , offset , total , & hdr , & nwritten , 0 ) ;
} while ( ret = = - 1 & & errno = = EINTR ) ;
if ( ret = = - 1 )
return - 1 ;
if ( nwritten = = 0 )
return - 1 ; /* I think we're at EOF here... */
/*
* If this was a short ( signal interrupted ) write we may need
* to subtract it from the header data , or null out the header
* data altogether if we wrote more than hdtrl . iov_len bytes .
* We change nwritten to be the number of file bytes written .
*/
if ( hdtrl [ 0 ] . iov_base & & hdtrl . iov_len ) {
if ( nwritten > = hdtrl . iov_len ) {
nwritten - = hdtrl . iov_len ;
hdtrl . iov_base = NULL ;
hdtrl . iov_len = 0 ;
} else {
nwritten = 0 ;
hdtrl . iov_base + = nwritten ;
hdtrl . iov_len - = nwritten ;
}
}
total - = nwritten ;
offset + = nwritten ;
}
return count + hdr_len ;
}
# else /* No sendfile implementation. Return error. */
ssize_t sys_sendfile ( int tofd , int fromfd , const DATA_BLOB * header , SMB_OFF_T offset , size_t count )
{
/* No sendfile syscall. */
errno = ENOSYS ;
return - 1 ;
}
# endif