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
= (void *)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
= (void *)(((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
= (void *)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 (void *)((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. */