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 } while (nwritten
== -1 && (errno
== EINTR
|| errno
== EAGAIN
|| errno
== EWOULDBLOCK
));
64 if (errno
== ENOSYS
|| errno
== EINVAL
) {
65 /* Ok - we're in a world of pain here. We just sent
66 * the header, but the sendfile failed. We have to
67 * emulate the sendfile at an upper layer before we
68 * disable it's use. So we do something really ugly.
69 * We set the errno to a strange value so we can detect
70 * this at the upper level and take care of it without
71 * layer violation. JRA.
73 errno
= EINTR
; /* Normally we can never return this. */
79 * EOF, return a short read
81 return hdr_len
+ (count
- total
);
85 return count
+ hdr_len
;
88 #elif defined(SOLARIS_SENDFILE_API)
91 * Solaris sendfile code written by Pierre Belanger <belanger@pobox.com>.
94 #include <sys/sendfile.h>
96 ssize_t
sys_sendfile(int tofd
, int fromfd
, const DATA_BLOB
*header
, off_t offset
, size_t count
)
99 size_t total
, xferred
;
100 struct sendfilevec vec
[2];
106 vec
[0].sfv_fd
= SFV_FD_SELF
;
108 vec
[0].sfv_off
= (off_t
)header
->data
;
109 vec
[0].sfv_len
= hdr_len
= header
->length
;
111 vec
[1].sfv_fd
= fromfd
;
113 vec
[1].sfv_off
= offset
;
114 vec
[1].sfv_len
= count
;
119 vec
[0].sfv_fd
= fromfd
;
121 vec
[0].sfv_off
= offset
;
122 vec
[0].sfv_len
= count
;
125 total
= count
+ hdr_len
;
131 * Although not listed in the API error returns, this is almost certainly
132 * a slow system call and will be interrupted by a signal with EINTR. JRA.
137 nwritten
= sendfilev(tofd
, vec
, sfvcnt
, &xferred
);
138 if (nwritten
== -1 && (errno
== EINTR
|| errno
== EAGAIN
|| errno
== EWOULDBLOCK
)) {
140 continue; /* Nothing written yet. */
148 return -1; /* I think we're at EOF here... */
151 * If this was a short (signal interrupted) write we may need
152 * to subtract it from the header data, or null out the header
153 * data altogether if we wrote more than vec[0].sfv_len bytes.
154 * We move vec[1].* to vec[0].* and set sfvcnt to 1
157 if (sfvcnt
== 2 && nwritten
>= vec
[0].sfv_len
) {
158 vec
[1].sfv_off
+= nwritten
- vec
[0].sfv_len
;
159 vec
[1].sfv_len
-= nwritten
- vec
[0].sfv_len
;
161 /* Move vec[1].* to vec[0].* and set sfvcnt to 1 */
165 vec
[0].sfv_off
+= nwritten
;
166 vec
[0].sfv_len
-= nwritten
;
170 return count
+ hdr_len
;
173 #elif defined(HPUX_SENDFILE_API)
175 #include <sys/socket.h>
178 ssize_t
sys_sendfile(int tofd
, int fromfd
, const DATA_BLOB
*header
, off_t offset
, size_t count
)
181 struct iovec hdtrl
[2];
185 /* Set up the header/trailer iovec. */
186 hdtrl
[0].iov_base
= (void *)header
->data
;
187 hdtrl
[0].iov_len
= hdr_len
= header
->length
;
189 hdtrl
[0].iov_base
= NULL
;
190 hdtrl
[0].iov_len
= hdr_len
= 0;
192 hdtrl
[1].iov_base
= NULL
;
193 hdtrl
[1].iov_len
= 0;
196 while (total
+ hdtrl
[0].iov_len
) {
200 * HPUX guarantees that if any data was written before
201 * a signal interrupt then sendfile returns the number of
202 * bytes written (which may be less than requested) not -1.
203 * nwritten includes the header data sent.
207 nwritten
= sendfile(tofd
, fromfd
, offset
, total
, &hdtrl
[0], 0);
208 } while (nwritten
== -1 && (errno
== EINTR
|| errno
== EAGAIN
|| errno
== EWOULDBLOCK
));
212 return -1; /* I think we're at EOF here... */
215 * If this was a short (signal interrupted) write we may need
216 * to subtract it from the header data, or null out the header
217 * data altogether if we wrote more than hdtrl[0].iov_len bytes.
218 * We change nwritten to be the number of file bytes written.
221 if (hdtrl
[0].iov_base
&& hdtrl
[0].iov_len
) {
222 if (nwritten
>= hdtrl
[0].iov_len
) {
223 nwritten
-= hdtrl
[0].iov_len
;
224 hdtrl
[0].iov_base
= NULL
;
225 hdtrl
[0].iov_len
= 0;
227 /* iov_base is defined as a void *... */
228 hdtrl
[0].iov_base
= (void *)(((char *)hdtrl
[0].iov_base
) + nwritten
);
229 hdtrl
[0].iov_len
-= nwritten
;
236 return count
+ hdr_len
;
239 #elif defined(FREEBSD_SENDFILE_API) || defined(DARWIN_SENDFILE_API)
241 #include <sys/types.h>
242 #include <sys/socket.h>
245 ssize_t
sys_sendfile(int tofd
, int fromfd
,
246 const DATA_BLOB
*header
, off_t offset
, size_t count
)
248 struct sf_hdtr sf_header
= {0};
249 struct iovec io_header
= {0};
255 sf_header
.headers
= &io_header
;
256 sf_header
.hdr_cnt
= 1;
257 io_header
.iov_base
= header
->data
;
258 io_header
.iov_len
= header
->length
;
259 sf_header
.trailers
= NULL
;
260 sf_header
.trl_cnt
= 0;
266 #if defined(DARWIN_SENDFILE_API)
267 /* Darwin recycles nwritten as a value-result parameter, apart from that this
268 sendfile implementation is quite the same as the FreeBSD one */
269 ret
= sendfile(fromfd
, tofd
, offset
, &nwritten
, &sf_header
, 0);
271 ret
= sendfile(fromfd
, tofd
, offset
, count
, &sf_header
, &nwritten
, 0);
273 if (ret
== -1 && errno
!= EINTR
&& errno
!= EAGAIN
&& errno
!= EWOULDBLOCK
) {
274 /* Send failed, we are toast. */
279 /* EOF of offset is after EOF. */
283 if (sf_header
.hdr_cnt
) {
284 if (io_header
.iov_len
<= nwritten
) {
285 /* Entire header was sent. */
286 sf_header
.headers
= NULL
;
287 sf_header
.hdr_cnt
= 0;
288 nwritten
-= io_header
.iov_len
;
290 /* Partial header was sent. */
291 io_header
.iov_len
-= nwritten
;
293 ((uint8_t *)io_header
.iov_base
) + nwritten
;
305 #elif defined(AIX_SENDFILE_API)
307 /* BEGIN AIX SEND_FILE */
309 /* Contributed by William Jojo <jojowil@hvcc.edu> */
310 #include <sys/socket.h>
312 ssize_t
sys_sendfile(int tofd
, int fromfd
, const DATA_BLOB
*header
, off_t offset
, size_t count
)
314 struct sf_parms hdtrl
;
316 /* Set up the header/trailer struct params. */
318 hdtrl
.header_data
= header
->data
;
319 hdtrl
.header_length
= header
->length
;
321 hdtrl
.header_data
= NULL
;
322 hdtrl
.header_length
= 0;
324 hdtrl
.trailer_data
= NULL
;
325 hdtrl
.trailer_length
= 0;
327 hdtrl
.file_descriptor
= fromfd
;
328 hdtrl
.file_offset
= offset
;
329 hdtrl
.file_bytes
= count
;
331 while ( hdtrl
.file_bytes
+ hdtrl
.header_length
) {
337 There are three possible return values from send_file:
341 -1 an error has occurred, errno contains the error code.
343 0 the command has completed successfully.
345 1 the command was completed partially, some data has been
346 transmitted but the command has to return for some reason,
347 for example, the command was interrupted by signals.
350 ret
= send_file(&tofd
, &hdtrl
, 0);
351 } while ((ret
== 1) || (ret
== -1 && (errno
== EINTR
|| errno
== EAGAIN
|| errno
== EWOULDBLOCK
)));
356 return count
+ header
->length
;
358 /* END AIX SEND_FILE */
360 #else /* No sendfile implementation. Return error. */
362 ssize_t
sys_sendfile(int tofd
, int fromfd
, const DATA_BLOB
*header
, off_t offset
, size_t count
)
364 /* No sendfile syscall. */