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. */
82 return -1; /* I think we're at EOF here... */
85 return count
+ hdr_len
;
88 #elif defined(LINUX_BROKEN_SENDFILE_API)
91 * We must use explicit 32 bit types here. This code path means Linux
92 * won't do proper 64-bit sendfile. JRA.
95 extern int32
sendfile (int out_fd
, int in_fd
, int32
*offset
, uint32 count
);
99 #define MSG_MORE 0x8000
102 ssize_t
sys_sendfile(int tofd
, int fromfd
, const DATA_BLOB
*header
, SMB_OFF_T offset
, size_t count
)
107 uint32 small_total
= 0;
111 * Fix for broken Linux 2.4 systems with no working sendfile64().
112 * If the offset+count > 2 GB then pretend we don't have the
113 * system call sendfile at all. The upper layer catches this
114 * and uses a normal read. JRA.
117 if ((sizeof(SMB_OFF_T
) >= 8) && (offset
+ count
> (SMB_OFF_T
)0x7FFFFFFF)) {
123 * Send the header first.
124 * Use MSG_MORE to cork the TCP output until sendfile is called.
128 hdr_len
= header
->length
;
129 while (total
< hdr_len
) {
130 ret
= sys_send(tofd
, header
->data
+ total
,hdr_len
- total
, MSG_MORE
);
137 small_total
= (uint32
)count
;
138 small_offset
= (int32
)offset
;
140 while (small_total
) {
143 nwritten
= sendfile(tofd
, fromfd
, &small_offset
, small_total
);
144 } while (nwritten
== -1 && errno
== EINTR
);
145 if (nwritten
== -1) {
146 if (errno
== ENOSYS
|| errno
== EINVAL
) {
147 /* Ok - we're in a world of pain here. We just sent
148 * the header, but the sendfile failed. We have to
149 * emulate the sendfile at an upper layer before we
150 * disable it's use. So we do something really ugly.
151 * We set the errno to a strange value so we can detect
152 * this at the upper level and take care of it without
153 * layer violation. JRA.
155 errno
= EINTR
; /* Normally we can never return this. */
160 return -1; /* I think we're at EOF here... */
161 small_total
-= nwritten
;
163 return count
+ hdr_len
;
167 #elif defined(SOLARIS_SENDFILE_API)
170 * Solaris sendfile code written by Pierre Belanger <belanger@pobox.com>.
173 #include <sys/sendfile.h>
175 ssize_t
sys_sendfile(int tofd
, int fromfd
, const DATA_BLOB
*header
, SMB_OFF_T offset
, size_t count
)
178 size_t total
, xferred
;
179 struct sendfilevec vec
[2];
185 vec
[0].sfv_fd
= SFV_FD_SELF
;
187 vec
[0].sfv_off
= (off_t
)header
->data
;
188 vec
[0].sfv_len
= hdr_len
= header
->length
;
190 vec
[1].sfv_fd
= fromfd
;
192 vec
[1].sfv_off
= offset
;
193 vec
[1].sfv_len
= count
;
198 vec
[0].sfv_fd
= fromfd
;
200 vec
[0].sfv_off
= offset
;
201 vec
[0].sfv_len
= count
;
204 total
= count
+ hdr_len
;
210 * Although not listed in the API error returns, this is almost certainly
211 * a slow system call and will be interrupted by a signal with EINTR. JRA.
216 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_SENDFILEV64)
217 nwritten
= sendfilev64(tofd
, vec
, sfvcnt
, &xferred
);
219 nwritten
= sendfilev(tofd
, vec
, sfvcnt
, &xferred
);
221 if (nwritten
== -1 && errno
== EINTR
) {
223 continue; /* Nothing written yet. */
231 return -1; /* I think we're at EOF here... */
234 * If this was a short (signal interrupted) write we may need
235 * to subtract it from the header data, or null out the header
236 * data altogether if we wrote more than vec[0].sfv_len bytes.
237 * We move vec[1].* to vec[0].* and set sfvcnt to 1
240 if (sfvcnt
== 2 && nwritten
>= vec
[0].sfv_len
) {
241 vec
[1].sfv_off
+= nwritten
- vec
[0].sfv_len
;
242 vec
[1].sfv_len
-= nwritten
- vec
[0].sfv_len
;
244 /* Move vec[1].* to vec[0].* and set sfvcnt to 1 */
248 vec
[0].sfv_off
+= nwritten
;
249 vec
[0].sfv_len
-= nwritten
;
253 return count
+ hdr_len
;
256 #elif defined(HPUX_SENDFILE_API)
258 #include <sys/socket.h>
261 ssize_t
sys_sendfile(int tofd
, int fromfd
, const DATA_BLOB
*header
, SMB_OFF_T offset
, size_t count
)
264 struct iovec hdtrl
[2];
268 /* Set up the header/trailer iovec. */
269 hdtrl
[0].iov_base
= header
->data
;
270 hdtrl
[0].iov_len
= hdr_len
= header
->length
;
272 hdtrl
[0].iov_base
= NULL
;
273 hdtrl
[0].iov_len
= hdr_len
= 0;
275 hdtrl
[1].iov_base
= NULL
;
276 hdtrl
[1].iov_len
= 0;
279 while (total
+ hdtrl
[0].iov_len
) {
283 * HPUX guarantees that if any data was written before
284 * a signal interrupt then sendfile returns the number of
285 * bytes written (which may be less than requested) not -1.
286 * nwritten includes the header data sent.
290 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_SENDFILE64)
291 nwritten
= sendfile64(tofd
, fromfd
, offset
, total
, &hdtrl
[0], 0);
293 nwritten
= sendfile(tofd
, fromfd
, offset
, total
, &hdtrl
[0], 0);
295 } while (nwritten
== -1 && errno
== EINTR
);
299 return -1; /* I think we're at EOF here... */
302 * If this was a short (signal interrupted) write we may need
303 * to subtract it from the header data, or null out the header
304 * data altogether if we wrote more than hdtrl[0].iov_len bytes.
305 * We change nwritten to be the number of file bytes written.
308 if (hdtrl
[0].iov_base
&& hdtrl
[0].iov_len
) {
309 if (nwritten
>= hdtrl
[0].iov_len
) {
310 nwritten
-= hdtrl
[0].iov_len
;
311 hdtrl
[0].iov_base
= NULL
;
312 hdtrl
[0].iov_len
= 0;
314 /* iov_base is defined as a void *... */
315 hdtrl
[0].iov_base
= ((char *)hdtrl
[0].iov_base
) + nwritten
;
316 hdtrl
[0].iov_len
-= nwritten
;
323 return count
+ hdr_len
;
326 #elif defined(FREEBSD_SENDFILE_API)
328 #include <sys/types.h>
329 #include <sys/socket.h>
332 ssize_t
sys_sendfile(int tofd
, int fromfd
, const DATA_BLOB
*header
, SMB_OFF_T offset
, size_t count
)
339 hdr
.headers
= &hdtrl
;
344 /* Set up the header iovec. */
346 hdtrl
.iov_base
= header
->data
;
347 hdtrl
.iov_len
= hdr_len
= header
->length
;
349 hdtrl
.iov_base
= NULL
;
354 while (total
+ hdtrl
.iov_len
) {
359 * FreeBSD sendfile returns 0 on success, -1 on error.
360 * Remember, the tofd and fromfd are reversed..... :-).
361 * nwritten includes the header data sent.
365 ret
= sendfile(fromfd
, tofd
, offset
, total
, &hdr
, &nwritten
, 0);
366 } while (ret
== -1 && errno
== EINTR
);
371 return -1; /* I think we're at EOF here... */
374 * If this was a short (signal interrupted) write we may need
375 * to subtract it from the header data, or null out the header
376 * data altogether if we wrote more than hdtrl.iov_len bytes.
377 * We change nwritten to be the number of file bytes written.
380 if (hdtrl
.iov_base
&& hdtrl
.iov_len
) {
381 if (nwritten
>= hdtrl
.iov_len
) {
382 nwritten
-= hdtrl
.iov_len
;
383 hdtrl
.iov_base
= NULL
;
387 (caddr_t
)hdtrl
.iov_base
+ nwritten
;
388 hdtrl
.iov_len
-= nwritten
;
395 return count
+ hdr_len
;
398 #elif defined(AIX_SENDFILE_API)
400 /* BEGIN AIX SEND_FILE */
402 /* Contributed by William Jojo <jojowil@hvcc.edu> */
403 #include <sys/socket.h>
405 ssize_t
sys_sendfile(int tofd
, int fromfd
, const DATA_BLOB
*header
, SMB_OFF_T offset
, size_t count
)
407 struct sf_parms hdtrl
;
409 /* Set up the header/trailer struct params. */
411 hdtrl
.header_data
= header
->data
;
412 hdtrl
.header_length
= header
->length
;
414 hdtrl
.header_data
= NULL
;
415 hdtrl
.header_length
= 0;
417 hdtrl
.trailer_data
= NULL
;
418 hdtrl
.trailer_length
= 0;
420 hdtrl
.file_descriptor
= fromfd
;
421 hdtrl
.file_offset
= offset
;
422 hdtrl
.file_bytes
= count
;
424 while ( hdtrl
.file_bytes
+ hdtrl
.header_length
) {
430 There are three possible return values from send_file:
434 -1 an error has occurred, errno contains the error code.
436 0 the command has completed successfully.
438 1 the command was completed partially, some data has been
439 transmitted but the command has to return for some reason,
440 for example, the command was interrupted by signals.
443 ret
= send_file(&tofd
, &hdtrl
, 0);
444 } while ( (ret
== 1) || (ret
== -1 && errno
== EINTR
) );
449 return count
+ header
->length
;
451 /* END AIX SEND_FILE */
453 #else /* No sendfile implementation. Return error. */
455 ssize_t
sys_sendfile(int tofd
, int fromfd
, const DATA_BLOB
*header
, SMB_OFF_T offset
, size_t count
)
457 /* No sendfile syscall. */