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
, 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 nwritten
= sendfile(tofd
, fromfd
, &offset
, total
);
62 #if defined(EWOULDBLOCK)
63 } while (nwritten
== -1 && (errno
== EINTR
|| errno
== EAGAIN
|| errno
== EWOULDBLOCK
));
65 } while (nwritten
== -1 && (errno
== EINTR
|| errno
== EAGAIN
));
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
, 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(off_t
) >= 8) && (offset
+ count
> (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 #if defined(EWOULDBLOCK)
149 } while (nwritten
== -1 && (errno
== EINTR
|| errno
== EAGAIN
|| errno
== EWOULDBLOCK
));
151 } while (nwritten
== -1 && (errno
== EINTR
|| errno
== EAGAIN
));
153 if (nwritten
== -1) {
154 if (errno
== ENOSYS
|| errno
== EINVAL
) {
155 /* Ok - we're in a world of pain here. We just sent
156 * the header, but the sendfile failed. We have to
157 * emulate the sendfile at an upper layer before we
158 * disable it's use. So we do something really ugly.
159 * We set the errno to a strange value so we can detect
160 * this at the upper level and take care of it without
161 * layer violation. JRA.
163 errno
= EINTR
; /* Normally we can never return this. */
169 * EOF, return a short read
171 return hdr_len
+ (((uint32
)count
) - small_total
);
173 small_total
-= nwritten
;
175 return count
+ hdr_len
;
179 #elif defined(SOLARIS_SENDFILE_API)
182 * Solaris sendfile code written by Pierre Belanger <belanger@pobox.com>.
185 #include <sys/sendfile.h>
187 ssize_t
sys_sendfile(int tofd
, int fromfd
, const DATA_BLOB
*header
, off_t offset
, size_t count
)
190 size_t total
, xferred
;
191 struct sendfilevec vec
[2];
197 vec
[0].sfv_fd
= SFV_FD_SELF
;
199 vec
[0].sfv_off
= (off_t
)header
->data
;
200 vec
[0].sfv_len
= hdr_len
= header
->length
;
202 vec
[1].sfv_fd
= fromfd
;
204 vec
[1].sfv_off
= offset
;
205 vec
[1].sfv_len
= count
;
210 vec
[0].sfv_fd
= fromfd
;
212 vec
[0].sfv_off
= offset
;
213 vec
[0].sfv_len
= count
;
216 total
= count
+ hdr_len
;
222 * Although not listed in the API error returns, this is almost certainly
223 * a slow system call and will be interrupted by a signal with EINTR. JRA.
228 nwritten
= sendfilev(tofd
, vec
, sfvcnt
, &xferred
);
229 #if defined(EWOULDBLOCK)
230 if (nwritten
== -1 && (errno
== EINTR
|| errno
== EAGAIN
|| errno
== EWOULDBLOCK
)) {
232 if (nwritten
== -1 && (errno
== EINTR
|| errno
== EAGAIN
)) {
235 continue; /* Nothing written yet. */
243 return -1; /* I think we're at EOF here... */
246 * If this was a short (signal interrupted) write we may need
247 * to subtract it from the header data, or null out the header
248 * data altogether if we wrote more than vec[0].sfv_len bytes.
249 * We move vec[1].* to vec[0].* and set sfvcnt to 1
252 if (sfvcnt
== 2 && nwritten
>= vec
[0].sfv_len
) {
253 vec
[1].sfv_off
+= nwritten
- vec
[0].sfv_len
;
254 vec
[1].sfv_len
-= nwritten
- vec
[0].sfv_len
;
256 /* Move vec[1].* to vec[0].* and set sfvcnt to 1 */
260 vec
[0].sfv_off
+= nwritten
;
261 vec
[0].sfv_len
-= nwritten
;
265 return count
+ hdr_len
;
268 #elif defined(HPUX_SENDFILE_API)
270 #include <sys/socket.h>
273 ssize_t
sys_sendfile(int tofd
, int fromfd
, const DATA_BLOB
*header
, off_t offset
, size_t count
)
276 struct iovec hdtrl
[2];
280 /* Set up the header/trailer iovec. */
281 hdtrl
[0].iov_base
= (void *)header
->data
;
282 hdtrl
[0].iov_len
= hdr_len
= header
->length
;
284 hdtrl
[0].iov_base
= NULL
;
285 hdtrl
[0].iov_len
= hdr_len
= 0;
287 hdtrl
[1].iov_base
= NULL
;
288 hdtrl
[1].iov_len
= 0;
291 while (total
+ hdtrl
[0].iov_len
) {
295 * HPUX guarantees that if any data was written before
296 * a signal interrupt then sendfile returns the number of
297 * bytes written (which may be less than requested) not -1.
298 * nwritten includes the header data sent.
302 nwritten
= sendfile(tofd
, fromfd
, offset
, total
, &hdtrl
[0], 0);
303 #if defined(EWOULDBLOCK)
304 } while (nwritten
== -1 && (errno
== EINTR
|| errno
== EAGAIN
|| errno
== EWOULDBLOCK
));
306 } while (nwritten
== -1 && (errno
== EINTR
|| errno
== EAGAIN
));
311 return -1; /* I think we're at EOF here... */
314 * If this was a short (signal interrupted) write we may need
315 * to subtract it from the header data, or null out the header
316 * data altogether if we wrote more than hdtrl[0].iov_len bytes.
317 * We change nwritten to be the number of file bytes written.
320 if (hdtrl
[0].iov_base
&& hdtrl
[0].iov_len
) {
321 if (nwritten
>= hdtrl
[0].iov_len
) {
322 nwritten
-= hdtrl
[0].iov_len
;
323 hdtrl
[0].iov_base
= NULL
;
324 hdtrl
[0].iov_len
= 0;
326 /* iov_base is defined as a void *... */
327 hdtrl
[0].iov_base
= (void *)(((char *)hdtrl
[0].iov_base
) + nwritten
);
328 hdtrl
[0].iov_len
-= nwritten
;
335 return count
+ hdr_len
;
338 #elif defined(FREEBSD_SENDFILE_API)
340 #include <sys/types.h>
341 #include <sys/socket.h>
344 ssize_t
sys_sendfile(int tofd
, int fromfd
, const DATA_BLOB
*header
, off_t offset
, size_t count
)
351 hdr
.headers
= &hdtrl
;
356 /* Set up the header iovec. */
358 hdtrl
.iov_base
= (void *)header
->data
;
359 hdtrl
.iov_len
= hdr_len
= header
->length
;
361 hdtrl
.iov_base
= NULL
;
366 while (total
+ hdtrl
.iov_len
) {
371 * FreeBSD sendfile returns 0 on success, -1 on error.
372 * Remember, the tofd and fromfd are reversed..... :-).
373 * nwritten includes the header data sent.
377 ret
= sendfile(fromfd
, tofd
, offset
, total
, &hdr
, &nwritten
, 0);
378 #if defined(EWOULDBLOCK)
379 } while (ret
== -1 && (errno
== EINTR
|| errno
== EAGAIN
|| errno
== EWOULDBLOCK
));
381 } while (ret
== -1 && (errno
== EINTR
|| errno
== EAGAIN
));
387 return -1; /* I think we're at EOF here... */
390 * If this was a short (signal interrupted) write we may need
391 * to subtract it from the header data, or null out the header
392 * data altogether if we wrote more than hdtrl.iov_len bytes.
393 * We change nwritten to be the number of file bytes written.
396 if (hdtrl
.iov_base
&& hdtrl
.iov_len
) {
397 if (nwritten
>= hdtrl
.iov_len
) {
398 nwritten
-= hdtrl
.iov_len
;
399 hdtrl
.iov_base
= NULL
;
403 (void *)((caddr_t
)hdtrl
.iov_base
+ nwritten
);
404 hdtrl
.iov_len
-= nwritten
;
411 return count
+ hdr_len
;
414 #elif defined(AIX_SENDFILE_API)
416 /* BEGIN AIX SEND_FILE */
418 /* Contributed by William Jojo <jojowil@hvcc.edu> */
419 #include <sys/socket.h>
421 ssize_t
sys_sendfile(int tofd
, int fromfd
, const DATA_BLOB
*header
, off_t offset
, size_t count
)
423 struct sf_parms hdtrl
;
425 /* Set up the header/trailer struct params. */
427 hdtrl
.header_data
= header
->data
;
428 hdtrl
.header_length
= header
->length
;
430 hdtrl
.header_data
= NULL
;
431 hdtrl
.header_length
= 0;
433 hdtrl
.trailer_data
= NULL
;
434 hdtrl
.trailer_length
= 0;
436 hdtrl
.file_descriptor
= fromfd
;
437 hdtrl
.file_offset
= offset
;
438 hdtrl
.file_bytes
= count
;
440 while ( hdtrl
.file_bytes
+ hdtrl
.header_length
) {
446 There are three possible return values from send_file:
450 -1 an error has occurred, errno contains the error code.
452 0 the command has completed successfully.
454 1 the command was completed partially, some data has been
455 transmitted but the command has to return for some reason,
456 for example, the command was interrupted by signals.
459 ret
= send_file(&tofd
, &hdtrl
, 0);
460 #if defined(EWOULDBLOCK)
461 } while ((ret
== 1) || (ret
== -1 && (errno
== EINTR
|| errno
== EAGAIN
|| errno
== EWOULDBLOCK
)));
463 } while ((ret
== 1) || (ret
== -1 && (errno
== EINTR
|| errno
== EAGAIN
)));
469 return count
+ header
->length
;
471 /* END AIX SEND_FILE */
473 #else /* No sendfile implementation. Return error. */
475 ssize_t
sys_sendfile(int tofd
, int fromfd
, const DATA_BLOB
*header
, off_t offset
, size_t count
)
477 /* No sendfile syscall. */