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 #if defined(EWOULDBLOCK)
67 } while (nwritten
== -1 && (errno
== EINTR
|| errno
== EAGAIN
|| errno
== EWOULDBLOCK
));
69 } while (nwritten
== -1 && (errno
== EINTR
|| errno
== EAGAIN
));
72 if (errno
== ENOSYS
|| errno
== EINVAL
) {
73 /* Ok - we're in a world of pain here. We just sent
74 * the header, but the sendfile failed. We have to
75 * emulate the sendfile at an upper layer before we
76 * disable it's use. So we do something really ugly.
77 * We set the errno to a strange value so we can detect
78 * this at the upper level and take care of it without
79 * layer violation. JRA.
81 errno
= EINTR
; /* Normally we can never return this. */
87 * EOF, return a short read
89 return hdr_len
+ (count
- total
);
93 return count
+ hdr_len
;
96 #elif defined(LINUX_BROKEN_SENDFILE_API)
99 * We must use explicit 32 bit types here. This code path means Linux
100 * won't do proper 64-bit sendfile. JRA.
103 extern int32
sendfile (int out_fd
, int in_fd
, int32
*offset
, uint32 count
);
107 #define MSG_MORE 0x8000
110 ssize_t
sys_sendfile(int tofd
, int fromfd
, const DATA_BLOB
*header
, SMB_OFF_T offset
, size_t count
)
115 uint32 small_total
= 0;
119 * Fix for broken Linux 2.4 systems with no working sendfile64().
120 * If the offset+count > 2 GB then pretend we don't have the
121 * system call sendfile at all. The upper layer catches this
122 * and uses a normal read. JRA.
125 if ((sizeof(SMB_OFF_T
) >= 8) && (offset
+ count
> (SMB_OFF_T
)0x7FFFFFFF)) {
131 * Send the header first.
132 * Use MSG_MORE to cork the TCP output until sendfile is called.
136 hdr_len
= header
->length
;
137 while (total
< hdr_len
) {
138 ret
= sys_send(tofd
, header
->data
+ total
,hdr_len
- total
, MSG_MORE
);
145 small_total
= (uint32
)count
;
146 small_offset
= (int32
)offset
;
148 while (small_total
) {
151 nwritten
= sendfile(tofd
, fromfd
, &small_offset
, small_total
);
152 #if defined(EWOULDBLOCK)
153 } while (nwritten
== -1 && (errno
== EINTR
|| errno
== EAGAIN
|| errno
== EWOULDBLOCK
));
155 } while (nwritten
== -1 && (errno
== EINTR
|| errno
== EAGAIN
));
157 if (nwritten
== -1) {
158 if (errno
== ENOSYS
|| errno
== EINVAL
) {
159 /* Ok - we're in a world of pain here. We just sent
160 * the header, but the sendfile failed. We have to
161 * emulate the sendfile at an upper layer before we
162 * disable it's use. So we do something really ugly.
163 * We set the errno to a strange value so we can detect
164 * this at the upper level and take care of it without
165 * layer violation. JRA.
167 errno
= EINTR
; /* Normally we can never return this. */
173 * EOF, return a short read
175 return hdr_len
+ (((uint32
)count
) - small_total
);
177 small_total
-= nwritten
;
179 return count
+ hdr_len
;
183 #elif defined(SOLARIS_SENDFILE_API)
186 * Solaris sendfile code written by Pierre Belanger <belanger@pobox.com>.
189 #include <sys/sendfile.h>
191 ssize_t
sys_sendfile(int tofd
, int fromfd
, const DATA_BLOB
*header
, SMB_OFF_T offset
, size_t count
)
194 size_t total
, xferred
;
195 struct sendfilevec vec
[2];
201 vec
[0].sfv_fd
= SFV_FD_SELF
;
203 vec
[0].sfv_off
= (off_t
)header
->data
;
204 vec
[0].sfv_len
= hdr_len
= header
->length
;
206 vec
[1].sfv_fd
= fromfd
;
208 vec
[1].sfv_off
= offset
;
209 vec
[1].sfv_len
= count
;
214 vec
[0].sfv_fd
= fromfd
;
216 vec
[0].sfv_off
= offset
;
217 vec
[0].sfv_len
= count
;
220 total
= count
+ hdr_len
;
226 * Although not listed in the API error returns, this is almost certainly
227 * a slow system call and will be interrupted by a signal with EINTR. JRA.
232 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_SENDFILEV64)
233 nwritten
= sendfilev64(tofd
, vec
, sfvcnt
, &xferred
);
235 nwritten
= sendfilev(tofd
, vec
, sfvcnt
, &xferred
);
237 #if defined(EWOULDBLOCK)
238 if (nwritten
== -1 && (errno
== EINTR
|| errno
== EAGAIN
|| errno
== EWOULDBLOCK
)) {
240 if (nwritten
== -1 && (errno
== EINTR
|| errno
== EAGAIN
)) {
243 continue; /* Nothing written yet. */
251 return -1; /* I think we're at EOF here... */
254 * If this was a short (signal interrupted) write we may need
255 * to subtract it from the header data, or null out the header
256 * data altogether if we wrote more than vec[0].sfv_len bytes.
257 * We move vec[1].* to vec[0].* and set sfvcnt to 1
260 if (sfvcnt
== 2 && nwritten
>= vec
[0].sfv_len
) {
261 vec
[1].sfv_off
+= nwritten
- vec
[0].sfv_len
;
262 vec
[1].sfv_len
-= nwritten
- vec
[0].sfv_len
;
264 /* Move vec[1].* to vec[0].* and set sfvcnt to 1 */
268 vec
[0].sfv_off
+= nwritten
;
269 vec
[0].sfv_len
-= nwritten
;
273 return count
+ hdr_len
;
276 #elif defined(HPUX_SENDFILE_API)
278 #include <sys/socket.h>
281 ssize_t
sys_sendfile(int tofd
, int fromfd
, const DATA_BLOB
*header
, SMB_OFF_T offset
, size_t count
)
284 struct iovec hdtrl
[2];
288 /* Set up the header/trailer iovec. */
289 hdtrl
[0].iov_base
= (void *)header
->data
;
290 hdtrl
[0].iov_len
= hdr_len
= header
->length
;
292 hdtrl
[0].iov_base
= NULL
;
293 hdtrl
[0].iov_len
= hdr_len
= 0;
295 hdtrl
[1].iov_base
= NULL
;
296 hdtrl
[1].iov_len
= 0;
299 while (total
+ hdtrl
[0].iov_len
) {
303 * HPUX guarantees that if any data was written before
304 * a signal interrupt then sendfile returns the number of
305 * bytes written (which may be less than requested) not -1.
306 * nwritten includes the header data sent.
310 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_SENDFILE64)
311 nwritten
= sendfile64(tofd
, fromfd
, offset
, total
, &hdtrl
[0], 0);
313 nwritten
= sendfile(tofd
, fromfd
, offset
, total
, &hdtrl
[0], 0);
315 #if defined(EWOULDBLOCK)
316 } while (nwritten
== -1 && (errno
== EINTR
|| errno
== EAGAIN
|| errno
== EWOULDBLOCK
));
318 } while (nwritten
== -1 && (errno
== EINTR
|| errno
== EAGAIN
));
323 return -1; /* I think we're at EOF here... */
326 * If this was a short (signal interrupted) write we may need
327 * to subtract it from the header data, or null out the header
328 * data altogether if we wrote more than hdtrl[0].iov_len bytes.
329 * We change nwritten to be the number of file bytes written.
332 if (hdtrl
[0].iov_base
&& hdtrl
[0].iov_len
) {
333 if (nwritten
>= hdtrl
[0].iov_len
) {
334 nwritten
-= hdtrl
[0].iov_len
;
335 hdtrl
[0].iov_base
= NULL
;
336 hdtrl
[0].iov_len
= 0;
338 /* iov_base is defined as a void *... */
339 hdtrl
[0].iov_base
= (void *)(((char *)hdtrl
[0].iov_base
) + nwritten
);
340 hdtrl
[0].iov_len
-= nwritten
;
347 return count
+ hdr_len
;
350 #elif defined(FREEBSD_SENDFILE_API)
352 #include <sys/types.h>
353 #include <sys/socket.h>
356 ssize_t
sys_sendfile(int tofd
, int fromfd
, const DATA_BLOB
*header
, SMB_OFF_T offset
, size_t count
)
363 hdr
.headers
= &hdtrl
;
368 /* Set up the header iovec. */
370 hdtrl
.iov_base
= (void *)header
->data
;
371 hdtrl
.iov_len
= hdr_len
= header
->length
;
373 hdtrl
.iov_base
= NULL
;
378 while (total
+ hdtrl
.iov_len
) {
383 * FreeBSD sendfile returns 0 on success, -1 on error.
384 * Remember, the tofd and fromfd are reversed..... :-).
385 * nwritten includes the header data sent.
389 ret
= sendfile(fromfd
, tofd
, offset
, total
, &hdr
, &nwritten
, 0);
390 #if defined(EWOULDBLOCK)
391 } while (ret
== -1 && (errno
== EINTR
|| errno
== EAGAIN
|| errno
== EWOULDBLOCK
));
393 } while (ret
== -1 && (errno
== EINTR
|| errno
== EAGAIN
));
399 return -1; /* I think we're at EOF here... */
402 * If this was a short (signal interrupted) write we may need
403 * to subtract it from the header data, or null out the header
404 * data altogether if we wrote more than hdtrl.iov_len bytes.
405 * We change nwritten to be the number of file bytes written.
408 if (hdtrl
.iov_base
&& hdtrl
.iov_len
) {
409 if (nwritten
>= hdtrl
.iov_len
) {
410 nwritten
-= hdtrl
.iov_len
;
411 hdtrl
.iov_base
= NULL
;
415 (void *)((caddr_t
)hdtrl
.iov_base
+ nwritten
);
416 hdtrl
.iov_len
-= nwritten
;
423 return count
+ hdr_len
;
426 #elif defined(AIX_SENDFILE_API)
428 /* BEGIN AIX SEND_FILE */
430 /* Contributed by William Jojo <jojowil@hvcc.edu> */
431 #include <sys/socket.h>
433 ssize_t
sys_sendfile(int tofd
, int fromfd
, const DATA_BLOB
*header
, SMB_OFF_T offset
, size_t count
)
435 struct sf_parms hdtrl
;
437 /* Set up the header/trailer struct params. */
439 hdtrl
.header_data
= header
->data
;
440 hdtrl
.header_length
= header
->length
;
442 hdtrl
.header_data
= NULL
;
443 hdtrl
.header_length
= 0;
445 hdtrl
.trailer_data
= NULL
;
446 hdtrl
.trailer_length
= 0;
448 hdtrl
.file_descriptor
= fromfd
;
449 hdtrl
.file_offset
= offset
;
450 hdtrl
.file_bytes
= count
;
452 while ( hdtrl
.file_bytes
+ hdtrl
.header_length
) {
458 There are three possible return values from send_file:
462 -1 an error has occurred, errno contains the error code.
464 0 the command has completed successfully.
466 1 the command was completed partially, some data has been
467 transmitted but the command has to return for some reason,
468 for example, the command was interrupted by signals.
471 ret
= send_file(&tofd
, &hdtrl
, 0);
472 #if defined(EWOULDBLOCK)
473 } while ((ret
== 1) || (ret
== -1 && (errno
== EINTR
|| errno
== EAGAIN
|| errno
== EWOULDBLOCK
)));
475 } while ((ret
== 1) || (ret
== -1 && (errno
== EINTR
|| errno
== EAGAIN
)));
481 return count
+ header
->length
;
483 /* END AIX SEND_FILE */
485 #else /* No sendfile implementation. Return error. */
487 ssize_t
sys_sendfile(int tofd
, int fromfd
, const DATA_BLOB
*header
, SMB_OFF_T offset
, size_t count
)
489 /* No sendfile syscall. */