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 #if defined(EWOULDBLOCK)
63 } while (nwritten
== -1 && (errno
== EINTR
|| errno
== EAGAIN
|| errno
== EWOULDBLOCK
));
65 } while (nwritten
== -1 && (errno
== EINTR
|| errno
== EAGAIN
));
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(SOLARIS_SENDFILE_API)
95 * Solaris sendfile code written by Pierre Belanger <belanger@pobox.com>.
98 #include <sys/sendfile.h>
100 ssize_t
sys_sendfile(int tofd
, int fromfd
, const DATA_BLOB
*header
, off_t offset
, size_t count
)
103 size_t total
, xferred
;
104 struct sendfilevec vec
[2];
110 vec
[0].sfv_fd
= SFV_FD_SELF
;
112 vec
[0].sfv_off
= (off_t
)header
->data
;
113 vec
[0].sfv_len
= hdr_len
= header
->length
;
115 vec
[1].sfv_fd
= fromfd
;
117 vec
[1].sfv_off
= offset
;
118 vec
[1].sfv_len
= count
;
123 vec
[0].sfv_fd
= fromfd
;
125 vec
[0].sfv_off
= offset
;
126 vec
[0].sfv_len
= count
;
129 total
= count
+ hdr_len
;
135 * Although not listed in the API error returns, this is almost certainly
136 * a slow system call and will be interrupted by a signal with EINTR. JRA.
141 nwritten
= sendfilev(tofd
, vec
, sfvcnt
, &xferred
);
142 #if defined(EWOULDBLOCK)
143 if (nwritten
== -1 && (errno
== EINTR
|| errno
== EAGAIN
|| errno
== EWOULDBLOCK
)) {
145 if (nwritten
== -1 && (errno
== EINTR
|| errno
== EAGAIN
)) {
148 continue; /* Nothing written yet. */
156 return -1; /* I think we're at EOF here... */
159 * If this was a short (signal interrupted) write we may need
160 * to subtract it from the header data, or null out the header
161 * data altogether if we wrote more than vec[0].sfv_len bytes.
162 * We move vec[1].* to vec[0].* and set sfvcnt to 1
165 if (sfvcnt
== 2 && nwritten
>= vec
[0].sfv_len
) {
166 vec
[1].sfv_off
+= nwritten
- vec
[0].sfv_len
;
167 vec
[1].sfv_len
-= nwritten
- vec
[0].sfv_len
;
169 /* Move vec[1].* to vec[0].* and set sfvcnt to 1 */
173 vec
[0].sfv_off
+= nwritten
;
174 vec
[0].sfv_len
-= nwritten
;
178 return count
+ hdr_len
;
181 #elif defined(HPUX_SENDFILE_API)
183 #include <sys/socket.h>
186 ssize_t
sys_sendfile(int tofd
, int fromfd
, const DATA_BLOB
*header
, off_t offset
, size_t count
)
189 struct iovec hdtrl
[2];
193 /* Set up the header/trailer iovec. */
194 hdtrl
[0].iov_base
= (void *)header
->data
;
195 hdtrl
[0].iov_len
= hdr_len
= header
->length
;
197 hdtrl
[0].iov_base
= NULL
;
198 hdtrl
[0].iov_len
= hdr_len
= 0;
200 hdtrl
[1].iov_base
= NULL
;
201 hdtrl
[1].iov_len
= 0;
204 while (total
+ hdtrl
[0].iov_len
) {
208 * HPUX guarantees that if any data was written before
209 * a signal interrupt then sendfile returns the number of
210 * bytes written (which may be less than requested) not -1.
211 * nwritten includes the header data sent.
215 nwritten
= sendfile(tofd
, fromfd
, offset
, total
, &hdtrl
[0], 0);
216 #if defined(EWOULDBLOCK)
217 } while (nwritten
== -1 && (errno
== EINTR
|| errno
== EAGAIN
|| errno
== EWOULDBLOCK
));
219 } while (nwritten
== -1 && (errno
== EINTR
|| errno
== EAGAIN
));
224 return -1; /* I think we're at EOF here... */
227 * If this was a short (signal interrupted) write we may need
228 * to subtract it from the header data, or null out the header
229 * data altogether if we wrote more than hdtrl[0].iov_len bytes.
230 * We change nwritten to be the number of file bytes written.
233 if (hdtrl
[0].iov_base
&& hdtrl
[0].iov_len
) {
234 if (nwritten
>= hdtrl
[0].iov_len
) {
235 nwritten
-= hdtrl
[0].iov_len
;
236 hdtrl
[0].iov_base
= NULL
;
237 hdtrl
[0].iov_len
= 0;
239 /* iov_base is defined as a void *... */
240 hdtrl
[0].iov_base
= (void *)(((char *)hdtrl
[0].iov_base
) + nwritten
);
241 hdtrl
[0].iov_len
-= nwritten
;
248 return count
+ hdr_len
;
251 #elif defined(FREEBSD_SENDFILE_API) || defined(DARWIN_SENDFILE_API)
253 #include <sys/types.h>
254 #include <sys/socket.h>
257 ssize_t
sys_sendfile(int tofd
, int fromfd
,
258 const DATA_BLOB
*header
, off_t offset
, size_t count
)
260 struct sf_hdtr sf_header
= {0};
261 struct iovec io_header
= {0};
267 sf_header
.headers
= &io_header
;
268 sf_header
.hdr_cnt
= 1;
269 io_header
.iov_base
= header
->data
;
270 io_header
.iov_len
= header
->length
;
271 sf_header
.trailers
= NULL
;
272 sf_header
.trl_cnt
= 0;
278 #if defined(DARWIN_SENDFILE_API)
279 /* Darwin recycles nwritten as a value-result parameter, apart from that this
280 sendfile implementation is quite the same as the FreeBSD one */
281 ret
= sendfile(fromfd
, tofd
, offset
, &nwritten
, &sf_header
, 0);
283 ret
= sendfile(fromfd
, tofd
, offset
, count
, &sf_header
, &nwritten
, 0);
285 #if defined(EWOULDBLOCK)
286 if (ret
== -1 && errno
!= EINTR
&& errno
!= EAGAIN
&& errno
!= EWOULDBLOCK
) {
288 if (ret
== -1 && errno
!= EINTR
&& errno
!= EAGAIN
) {
290 /* Send failed, we are toast. */
295 /* EOF of offset is after EOF. */
299 if (sf_header
.hdr_cnt
) {
300 if (io_header
.iov_len
<= nwritten
) {
301 /* Entire header was sent. */
302 sf_header
.headers
= NULL
;
303 sf_header
.hdr_cnt
= 0;
304 nwritten
-= io_header
.iov_len
;
306 /* Partial header was sent. */
307 io_header
.iov_len
-= nwritten
;
309 ((uint8_t *)io_header
.iov_base
) + nwritten
;
321 #elif defined(AIX_SENDFILE_API)
323 /* BEGIN AIX SEND_FILE */
325 /* Contributed by William Jojo <jojowil@hvcc.edu> */
326 #include <sys/socket.h>
328 ssize_t
sys_sendfile(int tofd
, int fromfd
, const DATA_BLOB
*header
, off_t offset
, size_t count
)
330 struct sf_parms hdtrl
;
332 /* Set up the header/trailer struct params. */
334 hdtrl
.header_data
= header
->data
;
335 hdtrl
.header_length
= header
->length
;
337 hdtrl
.header_data
= NULL
;
338 hdtrl
.header_length
= 0;
340 hdtrl
.trailer_data
= NULL
;
341 hdtrl
.trailer_length
= 0;
343 hdtrl
.file_descriptor
= fromfd
;
344 hdtrl
.file_offset
= offset
;
345 hdtrl
.file_bytes
= count
;
347 while ( hdtrl
.file_bytes
+ hdtrl
.header_length
) {
353 There are three possible return values from send_file:
357 -1 an error has occurred, errno contains the error code.
359 0 the command has completed successfully.
361 1 the command was completed partially, some data has been
362 transmitted but the command has to return for some reason,
363 for example, the command was interrupted by signals.
366 ret
= send_file(&tofd
, &hdtrl
, 0);
367 #if defined(EWOULDBLOCK)
368 } while ((ret
== 1) || (ret
== -1 && (errno
== EINTR
|| errno
== EAGAIN
|| errno
== EWOULDBLOCK
)));
370 } while ((ret
== 1) || (ret
== -1 && (errno
== EINTR
|| errno
== EAGAIN
)));
376 return count
+ header
->length
;
378 /* END AIX SEND_FILE */
380 #else /* No sendfile implementation. Return error. */
382 ssize_t
sys_sendfile(int tofd
, int fromfd
, const DATA_BLOB
*header
, off_t offset
, size_t count
)
384 /* No sendfile syscall. */