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 2 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, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 * This file handles the OS dependent sendfile implementations.
23 * The API is such that it returns -1 on error, else returns the
24 * number of bytes written.
29 #if defined(LINUX_SENDFILE_API)
31 #include <sys/sendfile.h>
34 #define MSG_MORE 0x8000
37 ssize_t
sys_sendfile(int tofd
, int fromfd
, const DATA_BLOB
*header
, SMB_OFF_T offset
, size_t count
)
44 * Send the header first.
45 * Use MSG_MORE to cork the TCP output until sendfile is called.
49 hdr_len
= header
->length
;
50 while (total
< hdr_len
) {
51 ret
= sys_send(tofd
, header
->data
+ total
,hdr_len
- total
, MSG_MORE
);
62 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_SENDFILE64)
63 nwritten
= sendfile64(tofd
, fromfd
, &offset
, total
);
65 nwritten
= sendfile(tofd
, fromfd
, &offset
, total
);
67 } while (nwritten
== -1 && errno
== EINTR
);
69 if (errno
== ENOSYS
) {
70 /* Ok - we're in a world of pain here. We just sent
71 * the header, but the sendfile failed. We have to
72 * emulate the sendfile at an upper layer before we
73 * disable it's use. So we do something really ugly.
74 * We set the errno to a strange value so we can detect
75 * this at the upper level and take care of it without
76 * layer violation. JRA.
78 errno
= EINTR
; /* Normally we can never return this. */
83 return -1; /* I think we're at EOF here... */
86 return count
+ hdr_len
;
89 #elif defined(LINUX_BROKEN_SENDFILE_API)
92 * We must use explicit 32 bit types here. This code path means Linux
93 * won't do proper 64-bit sendfile. JRA.
96 extern int32
sendfile (int out_fd
, int in_fd
, int32
*offset
, uint32 count
);
100 #define MSG_MORE 0x8000
103 ssize_t
sys_sendfile(int tofd
, int fromfd
, const DATA_BLOB
*header
, SMB_OFF_T offset
, size_t count
)
108 uint32 small_total
= 0;
112 * Fix for broken Linux 2.4 systems with no working sendfile64().
113 * If the offset+count > 2 GB then pretend we don't have the
114 * system call sendfile at all. The upper layer catches this
115 * and uses a normal read. JRA.
118 if ((sizeof(SMB_OFF_T
) >= 8) && (offset
+ count
> (SMB_OFF_T
)0x7FFFFFFF)) {
124 * Send the header first.
125 * Use MSG_MORE to cork the TCP output until sendfile is called.
129 hdr_len
= header
->length
;
130 while (total
< hdr_len
) {
131 ret
= sys_send(tofd
, header
->data
+ total
,hdr_len
- total
, MSG_MORE
);
138 small_total
= (uint32
)count
;
139 small_offset
= (int32
)offset
;
141 while (small_total
) {
144 nwritten
= sendfile(tofd
, fromfd
, &small_offset
, small_total
);
145 } while (nwritten
== -1 && errno
== EINTR
);
146 if (nwritten
== -1) {
147 if (errno
== ENOSYS
) {
148 /* Ok - we're in a world of pain here. We just sent
149 * the header, but the sendfile failed. We have to
150 * emulate the sendfile at an upper layer before we
151 * disable it's use. So we do something really ugly.
152 * We set the errno to a strange value so we can detect
153 * this at the upper level and take care of it without
154 * layer violation. JRA.
156 errno
= EINTR
; /* Normally we can never return this. */
161 return -1; /* I think we're at EOF here... */
162 small_total
-= nwritten
;
164 return count
+ hdr_len
;
168 #elif defined(SOLARIS_SENDFILE_API)
171 * Solaris sendfile code written by Pierre Belanger <belanger@pobox.com>.
174 #include <sys/sendfile.h>
176 ssize_t
sys_sendfile(int tofd
, int fromfd
, const DATA_BLOB
*header
, SMB_OFF_T offset
, size_t count
)
179 size_t total
, xferred
;
180 struct sendfilevec vec
[2];
186 vec
[0].sfv_fd
= SFV_FD_SELF
;
188 vec
[0].sfv_off
= (off_t
)header
->data
;
189 vec
[0].sfv_len
= hdr_len
= header
->length
;
191 vec
[1].sfv_fd
= fromfd
;
193 vec
[1].sfv_off
= offset
;
194 vec
[1].sfv_len
= count
;
199 vec
[0].sfv_fd
= fromfd
;
201 vec
[0].sfv_off
= offset
;
202 vec
[0].sfv_len
= count
;
205 total
= count
+ hdr_len
;
211 * Although not listed in the API error returns, this is almost certainly
212 * a slow system call and will be interrupted by a signal with EINTR. JRA.
217 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_SENDFILEV64)
218 nwritten
= sendfilev64(tofd
, vec
, sfvcnt
, &xferred
);
220 nwritten
= sendfilev(tofd
, vec
, sfvcnt
, &xferred
);
222 if (nwritten
== -1 && errno
== EINTR
) {
224 continue; /* Nothing written yet. */
232 return -1; /* I think we're at EOF here... */
235 * If this was a short (signal interrupted) write we may need
236 * to subtract it from the header data, or null out the header
237 * data altogether if we wrote more than vec[0].sfv_len bytes.
238 * We move vec[1].* to vec[0].* and set sfvcnt to 1
241 if (sfvcnt
== 2 && nwritten
>= vec
[0].sfv_len
) {
242 vec
[1].sfv_off
+= nwritten
- vec
[0].sfv_len
;
243 vec
[1].sfv_len
-= nwritten
- vec
[0].sfv_len
;
245 /* Move vec[1].* to vec[0].* and set sfvcnt to 1 */
249 vec
[0].sfv_off
+= nwritten
;
250 vec
[0].sfv_len
-= nwritten
;
254 return count
+ hdr_len
;
257 #elif defined(HPUX_SENDFILE_API)
259 #include <sys/socket.h>
262 ssize_t
sys_sendfile(int tofd
, int fromfd
, const DATA_BLOB
*header
, SMB_OFF_T offset
, size_t count
)
265 struct iovec hdtrl
[2];
269 /* Set up the header/trailer iovec. */
270 hdtrl
[0].iov_base
= header
->data
;
271 hdtrl
[0].iov_len
= hdr_len
= header
->length
;
273 hdtrl
[0].iov_base
= NULL
;
274 hdtrl
[0].iov_len
= hdr_len
= 0;
276 hdtrl
[1].iov_base
= NULL
;
277 hdtrl
[1].iov_len
= 0;
280 while (total
+ hdtrl
[0].iov_len
) {
284 * HPUX guarantees that if any data was written before
285 * a signal interrupt then sendfile returns the number of
286 * bytes written (which may be less than requested) not -1.
287 * nwritten includes the header data sent.
291 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_SENDFILE64)
292 nwritten
= sendfile64(tofd
, fromfd
, offset
, total
, &hdtrl
[0], 0);
294 nwritten
= sendfile(tofd
, fromfd
, offset
, total
, &hdtrl
[0], 0);
296 } while (nwritten
== -1 && errno
== EINTR
);
300 return -1; /* I think we're at EOF here... */
303 * If this was a short (signal interrupted) write we may need
304 * to subtract it from the header data, or null out the header
305 * data altogether if we wrote more than hdtrl[0].iov_len bytes.
306 * We change nwritten to be the number of file bytes written.
309 if (hdtrl
[0].iov_base
&& hdtrl
[0].iov_len
) {
310 if (nwritten
>= hdtrl
[0].iov_len
) {
311 nwritten
-= hdtrl
[0].iov_len
;
312 hdtrl
[0].iov_base
= NULL
;
313 hdtrl
[0].iov_len
= 0;
315 /* iov_base is defined as a void *... */
316 hdtrl
[0].iov_base
= ((char *)hdtrl
[0].iov_base
) + nwritten
;
317 hdtrl
[0].iov_len
-= nwritten
;
324 return count
+ hdr_len
;
327 #elif defined(FREEBSD_SENDFILE_API)
329 #include <sys/types.h>
330 #include <sys/socket.h>
333 ssize_t
sys_sendfile(int tofd
, int fromfd
, const DATA_BLOB
*header
, SMB_OFF_T offset
, size_t count
)
340 hdr
.headers
= &hdtrl
;
345 /* Set up the header iovec. */
347 hdtrl
.iov_base
= header
->data
;
348 hdtrl
.iov_len
= hdr_len
= header
->length
;
350 hdtrl
.iov_base
= NULL
;
355 while (total
+ hdtrl
.iov_len
) {
360 * FreeBSD sendfile returns 0 on success, -1 on error.
361 * Remember, the tofd and fromfd are reversed..... :-).
362 * nwritten includes the header data sent.
366 ret
= sendfile(fromfd
, tofd
, offset
, total
, &hdr
, &nwritten
, 0);
367 } while (ret
== -1 && errno
== EINTR
);
372 return -1; /* I think we're at EOF here... */
375 * If this was a short (signal interrupted) write we may need
376 * to subtract it from the header data, or null out the header
377 * data altogether if we wrote more than hdtrl.iov_len bytes.
378 * We change nwritten to be the number of file bytes written.
381 if (hdtrl
.iov_base
&& hdtrl
.iov_len
) {
382 if (nwritten
>= hdtrl
.iov_len
) {
383 nwritten
-= hdtrl
.iov_len
;
384 hdtrl
.iov_base
= NULL
;
387 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. */