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)
253 #include <sys/types.h>
254 #include <sys/socket.h>
257 ssize_t
sys_sendfile(int tofd
, int fromfd
, const DATA_BLOB
*header
, off_t offset
, size_t count
)
264 hdr
.headers
= &hdtrl
;
269 /* Set up the header iovec. */
271 hdtrl
.iov_base
= (void *)header
->data
;
272 hdtrl
.iov_len
= hdr_len
= header
->length
;
274 hdtrl
.iov_base
= NULL
;
279 while (total
+ hdtrl
.iov_len
) {
284 * FreeBSD sendfile returns 0 on success, -1 on error.
285 * Remember, the tofd and fromfd are reversed..... :-).
286 * nwritten includes the header data sent.
290 ret
= sendfile(fromfd
, tofd
, offset
, total
, &hdr
, &nwritten
, 0);
291 #if defined(EWOULDBLOCK)
292 } while (ret
== -1 && (errno
== EINTR
|| errno
== EAGAIN
|| errno
== EWOULDBLOCK
));
294 } while (ret
== -1 && (errno
== EINTR
|| errno
== EAGAIN
));
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.iov_len bytes.
306 * We change nwritten to be the number of file bytes written.
309 if (hdtrl
.iov_base
&& hdtrl
.iov_len
) {
310 if (nwritten
>= hdtrl
.iov_len
) {
311 nwritten
-= hdtrl
.iov_len
;
312 hdtrl
.iov_base
= NULL
;
316 (void *)((caddr_t
)hdtrl
.iov_base
+ nwritten
);
317 hdtrl
.iov_len
-= nwritten
;
324 return count
+ hdr_len
;
327 #elif defined(AIX_SENDFILE_API)
329 /* BEGIN AIX SEND_FILE */
331 /* Contributed by William Jojo <jojowil@hvcc.edu> */
332 #include <sys/socket.h>
334 ssize_t
sys_sendfile(int tofd
, int fromfd
, const DATA_BLOB
*header
, off_t offset
, size_t count
)
336 struct sf_parms hdtrl
;
338 /* Set up the header/trailer struct params. */
340 hdtrl
.header_data
= header
->data
;
341 hdtrl
.header_length
= header
->length
;
343 hdtrl
.header_data
= NULL
;
344 hdtrl
.header_length
= 0;
346 hdtrl
.trailer_data
= NULL
;
347 hdtrl
.trailer_length
= 0;
349 hdtrl
.file_descriptor
= fromfd
;
350 hdtrl
.file_offset
= offset
;
351 hdtrl
.file_bytes
= count
;
353 while ( hdtrl
.file_bytes
+ hdtrl
.header_length
) {
359 There are three possible return values from send_file:
363 -1 an error has occurred, errno contains the error code.
365 0 the command has completed successfully.
367 1 the command was completed partially, some data has been
368 transmitted but the command has to return for some reason,
369 for example, the command was interrupted by signals.
372 ret
= send_file(&tofd
, &hdtrl
, 0);
373 #if defined(EWOULDBLOCK)
374 } while ((ret
== 1) || (ret
== -1 && (errno
== EINTR
|| errno
== EAGAIN
|| errno
== EWOULDBLOCK
)));
376 } while ((ret
== 1) || (ret
== -1 && (errno
== EINTR
|| errno
== EAGAIN
)));
382 return count
+ header
->length
;
384 /* END AIX SEND_FILE */
386 #else /* No sendfile implementation. Return error. */
388 ssize_t
sys_sendfile(int tofd
, int fromfd
, const DATA_BLOB
*header
, off_t offset
, size_t count
)
390 /* No sendfile syscall. */