2
Unix SMB/Netbios implementation.
4
sendfile implementations.
5
Copyright (C) Jeremy Allison 2002.
7
This program is free software; you can redistribute it and/or modify
8
it under the terms of the GNU General Public License as published by
9
the Free Software Foundation; either version 3 of the License, or
10
(at your option) any later version.
11
This program is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
GNU General Public License for more details.
16
You should have received a copy of the GNU General Public License
17
along with this program; if not, see <http://www.gnu.org/licenses/>.
21
* This file handles the OS dependent sendfile implementations.
22
* The API is such that it returns -1 on error, else returns the
23
* number of bytes written.
28
#if defined(LINUX_SENDFILE_API)
30
#include <sys/sendfile.h>
33
#define MSG_MORE 0x8000
36
ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
43
* Send the header first.
44
* Use MSG_MORE to cork the TCP output until sendfile is called.
48
hdr_len = header->length;
49
while (total < hdr_len) {
50
ret = sys_send(tofd, header->data + total,hdr_len - total, MSG_MORE);
61
#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_SENDFILE64)
62
nwritten = sendfile64(tofd, fromfd, &offset, total);
64
nwritten = sendfile(tofd, fromfd, &offset, total);
66
} while (nwritten == -1 && errno == EINTR);
68
if (errno == ENOSYS || errno == EINVAL) {
69
/* Ok - we're in a world of pain here. We just sent
70
* the header, but the sendfile failed. We have to
71
* emulate the sendfile at an upper layer before we
72
* disable it's use. So we do something really ugly.
73
* We set the errno to a strange value so we can detect
74
* this at the upper level and take care of it without
75
* layer violation. JRA.
77
errno = EINTR; /* Normally we can never return this. */
83
* EOF, return a short read
85
return hdr_len + (count - total);
89
return count + hdr_len;
92
#elif defined(LINUX_BROKEN_SENDFILE_API)
95
* We must use explicit 32 bit types here. This code path means Linux
96
* won't do proper 64-bit sendfile. JRA.
99
extern int32 sendfile (int out_fd, int in_fd, int32 *offset, uint32 count);
103
#define MSG_MORE 0x8000
106
ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
111
uint32 small_total = 0;
115
* Fix for broken Linux 2.4 systems with no working sendfile64().
116
* If the offset+count > 2 GB then pretend we don't have the
117
* system call sendfile at all. The upper layer catches this
118
* and uses a normal read. JRA.
121
if ((sizeof(SMB_OFF_T) >= 8) && (offset + count > (SMB_OFF_T)0x7FFFFFFF)) {
127
* Send the header first.
128
* Use MSG_MORE to cork the TCP output until sendfile is called.
132
hdr_len = header->length;
133
while (total < hdr_len) {
134
ret = sys_send(tofd, header->data + total,hdr_len - total, MSG_MORE);
141
small_total = (uint32)count;
142
small_offset = (int32)offset;
144
while (small_total) {
147
nwritten = sendfile(tofd, fromfd, &small_offset, small_total);
148
} while (nwritten == -1 && errno == EINTR);
149
if (nwritten == -1) {
150
if (errno == ENOSYS || errno == EINVAL) {
151
/* Ok - we're in a world of pain here. We just sent
152
* the header, but the sendfile failed. We have to
153
* emulate the sendfile at an upper layer before we
154
* disable it's use. So we do something really ugly.
155
* We set the errno to a strange value so we can detect
156
* this at the upper level and take care of it without
157
* layer violation. JRA.
159
errno = EINTR; /* Normally we can never return this. */
165
* EOF, return a short read
167
return hdr_len + (((uint32)count) - small_total);
169
small_total -= nwritten;
171
return count + hdr_len;
175
#elif defined(SOLARIS_SENDFILE_API)
178
* Solaris sendfile code written by Pierre Belanger <belanger@pobox.com>.
181
#include <sys/sendfile.h>
183
ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
186
size_t total, xferred;
187
struct sendfilevec vec[2];
193
vec[0].sfv_fd = SFV_FD_SELF;
195
vec[0].sfv_off = (off_t)header->data;
196
vec[0].sfv_len = hdr_len = header->length;
198
vec[1].sfv_fd = fromfd;
200
vec[1].sfv_off = offset;
201
vec[1].sfv_len = count;
206
vec[0].sfv_fd = fromfd;
208
vec[0].sfv_off = offset;
209
vec[0].sfv_len = count;
212
total = count + hdr_len;
218
* Although not listed in the API error returns, this is almost certainly
219
* a slow system call and will be interrupted by a signal with EINTR. JRA.
224
#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_SENDFILEV64)
225
nwritten = sendfilev64(tofd, vec, sfvcnt, &xferred);
227
nwritten = sendfilev(tofd, vec, sfvcnt, &xferred);
229
if (nwritten == -1 && errno == EINTR) {
231
continue; /* Nothing written yet. */
239
return -1; /* I think we're at EOF here... */
242
* If this was a short (signal interrupted) write we may need
243
* to subtract it from the header data, or null out the header
244
* data altogether if we wrote more than vec[0].sfv_len bytes.
245
* We move vec[1].* to vec[0].* and set sfvcnt to 1
248
if (sfvcnt == 2 && nwritten >= vec[0].sfv_len) {
249
vec[1].sfv_off += nwritten - vec[0].sfv_len;
250
vec[1].sfv_len -= nwritten - vec[0].sfv_len;
252
/* Move vec[1].* to vec[0].* and set sfvcnt to 1 */
256
vec[0].sfv_off += nwritten;
257
vec[0].sfv_len -= nwritten;
261
return count + hdr_len;
264
#elif defined(HPUX_SENDFILE_API)
266
#include <sys/socket.h>
269
ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
272
struct iovec hdtrl[2];
276
/* Set up the header/trailer iovec. */
277
hdtrl[0].iov_base = header->data;
278
hdtrl[0].iov_len = hdr_len = header->length;
280
hdtrl[0].iov_base = NULL;
281
hdtrl[0].iov_len = hdr_len = 0;
283
hdtrl[1].iov_base = NULL;
284
hdtrl[1].iov_len = 0;
287
while (total + hdtrl[0].iov_len) {
291
* HPUX guarantees that if any data was written before
292
* a signal interrupt then sendfile returns the number of
293
* bytes written (which may be less than requested) not -1.
294
* nwritten includes the header data sent.
298
#if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_SENDFILE64)
299
nwritten = sendfile64(tofd, fromfd, offset, total, &hdtrl[0], 0);
301
nwritten = sendfile(tofd, fromfd, offset, total, &hdtrl[0], 0);
303
} while (nwritten == -1 && errno == EINTR);
307
return -1; /* I think we're at EOF here... */
310
* If this was a short (signal interrupted) write we may need
311
* to subtract it from the header data, or null out the header
312
* data altogether if we wrote more than hdtrl[0].iov_len bytes.
313
* We change nwritten to be the number of file bytes written.
316
if (hdtrl[0].iov_base && hdtrl[0].iov_len) {
317
if (nwritten >= hdtrl[0].iov_len) {
318
nwritten -= hdtrl[0].iov_len;
319
hdtrl[0].iov_base = NULL;
320
hdtrl[0].iov_len = 0;
322
/* iov_base is defined as a void *... */
323
hdtrl[0].iov_base = ((char *)hdtrl[0].iov_base) + nwritten;
324
hdtrl[0].iov_len -= nwritten;
331
return count + hdr_len;
334
#elif defined(FREEBSD_SENDFILE_API)
336
#include <sys/types.h>
337
#include <sys/socket.h>
340
ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
347
hdr.headers = &hdtrl;
352
/* Set up the header iovec. */
354
hdtrl.iov_base = header->data;
355
hdtrl.iov_len = hdr_len = header->length;
357
hdtrl.iov_base = NULL;
362
while (total + hdtrl.iov_len) {
367
* FreeBSD sendfile returns 0 on success, -1 on error.
368
* Remember, the tofd and fromfd are reversed..... :-).
369
* nwritten includes the header data sent.
373
ret = sendfile(fromfd, tofd, offset, total, &hdr, &nwritten, 0);
374
} while (ret == -1 && errno == EINTR);
379
return -1; /* I think we're at EOF here... */
382
* If this was a short (signal interrupted) write we may need
383
* to subtract it from the header data, or null out the header
384
* data altogether if we wrote more than hdtrl.iov_len bytes.
385
* We change nwritten to be the number of file bytes written.
388
if (hdtrl.iov_base && hdtrl.iov_len) {
389
if (nwritten >= hdtrl.iov_len) {
390
nwritten -= hdtrl.iov_len;
391
hdtrl.iov_base = NULL;
395
(caddr_t)hdtrl.iov_base + nwritten;
396
hdtrl.iov_len -= nwritten;
403
return count + hdr_len;
406
#elif defined(AIX_SENDFILE_API)
408
/* BEGIN AIX SEND_FILE */
410
/* Contributed by William Jojo <jojowil@hvcc.edu> */
411
#include <sys/socket.h>
413
ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
415
struct sf_parms hdtrl;
417
/* Set up the header/trailer struct params. */
419
hdtrl.header_data = header->data;
420
hdtrl.header_length = header->length;
422
hdtrl.header_data = NULL;
423
hdtrl.header_length = 0;
425
hdtrl.trailer_data = NULL;
426
hdtrl.trailer_length = 0;
428
hdtrl.file_descriptor = fromfd;
429
hdtrl.file_offset = offset;
430
hdtrl.file_bytes = count;
432
while ( hdtrl.file_bytes + hdtrl.header_length ) {
438
There are three possible return values from send_file:
442
-1 an error has occurred, errno contains the error code.
444
0 the command has completed successfully.
446
1 the command was completed partially, some data has been
447
transmitted but the command has to return for some reason,
448
for example, the command was interrupted by signals.
451
ret = send_file(&tofd, &hdtrl, 0);
452
} while ( (ret == 1) || (ret == -1 && errno == EINTR) );
457
return count + header->length;
459
/* END AIX SEND_FILE */
461
#else /* No sendfile implementation. Return error. */
463
ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
465
/* No sendfile syscall. */