source: vendor/current/source3/lib/sendfile.c

Last change on this file was 988, checked in by Silvan Scherrer, 9 years ago

Samba Server: update vendor to version 4.4.3

File size: 9.1 KB
Line 
1/*
2 Unix SMB/Netbios implementation.
3 Version 2.2.x / 3.0.x
4 sendfile implementations.
5 Copyright (C) Jeremy Allison 2002.
6
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.
15
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/>.
18*/
19
20/*
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.
24 */
25
26#include "includes.h"
27
28#if defined(LINUX_SENDFILE_API)
29
30#include <sys/sendfile.h>
31
32#ifndef MSG_MORE
33#define MSG_MORE 0x8000
34#endif
35
36ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, off_t offset, size_t count)
37{
38 size_t total=0;
39 ssize_t ret;
40 size_t hdr_len = 0;
41
42 /*
43 * Send the header first.
44 * Use MSG_MORE to cork the TCP output until sendfile is called.
45 */
46
47 if (header) {
48 hdr_len = header->length;
49 while (total < hdr_len) {
50 ret = sys_send(tofd, header->data + total,hdr_len - total, MSG_MORE);
51 if (ret == -1)
52 return -1;
53 total += ret;
54 }
55 }
56
57 total = count;
58 while (total) {
59 ssize_t nwritten;
60 do {
61 nwritten = sendfile(tofd, fromfd, &offset, total);
62 } while (nwritten == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
63 if (nwritten == -1) {
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.
72 */
73 errno = EINTR; /* Normally we can never return this. */
74 }
75 return -1;
76 }
77 if (nwritten == 0) {
78 /*
79 * EOF, return a short read
80 */
81 return hdr_len + (count - total);
82 }
83 total -= nwritten;
84 }
85 return count + hdr_len;
86}
87
88#elif defined(SOLARIS_SENDFILE_API)
89
90/*
91 * Solaris sendfile code written by Pierre Belanger <belanger@pobox.com>.
92 */
93
94#include <sys/sendfile.h>
95
96ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, off_t offset, size_t count)
97{
98 int sfvcnt;
99 size_t total, xferred;
100 struct sendfilevec vec[2];
101 ssize_t hdr_len = 0;
102
103 if (header) {
104 sfvcnt = 2;
105
106 vec[0].sfv_fd = SFV_FD_SELF;
107 vec[0].sfv_flag = 0;
108 vec[0].sfv_off = (off_t)header->data;
109 vec[0].sfv_len = hdr_len = header->length;
110
111 vec[1].sfv_fd = fromfd;
112 vec[1].sfv_flag = 0;
113 vec[1].sfv_off = offset;
114 vec[1].sfv_len = count;
115
116 } else {
117 sfvcnt = 1;
118
119 vec[0].sfv_fd = fromfd;
120 vec[0].sfv_flag = 0;
121 vec[0].sfv_off = offset;
122 vec[0].sfv_len = count;
123 }
124
125 total = count + hdr_len;
126
127 while (total) {
128 ssize_t nwritten;
129
130 /*
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.
133 */
134
135 xferred = 0;
136
137 nwritten = sendfilev(tofd, vec, sfvcnt, &xferred);
138 if (nwritten == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)) {
139 if (xferred == 0)
140 continue; /* Nothing written yet. */
141 else
142 nwritten = xferred;
143 }
144
145 if (nwritten == -1)
146 return -1;
147 if (nwritten == 0)
148 return -1; /* I think we're at EOF here... */
149
150 /*
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
155 */
156
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;
160
161 /* Move vec[1].* to vec[0].* and set sfvcnt to 1 */
162 vec[0] = vec[1];
163 sfvcnt = 1;
164 } else {
165 vec[0].sfv_off += nwritten;
166 vec[0].sfv_len -= nwritten;
167 }
168 total -= nwritten;
169 }
170 return count + hdr_len;
171}
172
173#elif defined(HPUX_SENDFILE_API)
174
175#include <sys/socket.h>
176#include <sys/uio.h>
177
178ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, off_t offset, size_t count)
179{
180 size_t total=0;
181 struct iovec hdtrl[2];
182 size_t hdr_len = 0;
183
184 if (header) {
185 /* Set up the header/trailer iovec. */
186 hdtrl[0].iov_base = (void *)header->data;
187 hdtrl[0].iov_len = hdr_len = header->length;
188 } else {
189 hdtrl[0].iov_base = NULL;
190 hdtrl[0].iov_len = hdr_len = 0;
191 }
192 hdtrl[1].iov_base = NULL;
193 hdtrl[1].iov_len = 0;
194
195 total = count;
196 while (total + hdtrl[0].iov_len) {
197 ssize_t nwritten;
198
199 /*
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.
204 */
205
206 do {
207 nwritten = sendfile(tofd, fromfd, offset, total, &hdtrl[0], 0);
208 } while (nwritten == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
209 if (nwritten == -1)
210 return -1;
211 if (nwritten == 0)
212 return -1; /* I think we're at EOF here... */
213
214 /*
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.
219 */
220
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;
226 } else {
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;
230 nwritten = 0;
231 }
232 }
233 total -= nwritten;
234 offset += nwritten;
235 }
236 return count + hdr_len;
237}
238
239#elif defined(FREEBSD_SENDFILE_API) || defined(DARWIN_SENDFILE_API)
240
241#include <sys/types.h>
242#include <sys/socket.h>
243#include <sys/uio.h>
244
245ssize_t sys_sendfile(int tofd, int fromfd,
246 const DATA_BLOB *header, off_t offset, size_t count)
247{
248 struct sf_hdtr sf_header = {0};
249 struct iovec io_header = {0};
250
251 off_t nwritten;
252 int ret;
253
254 if (header) {
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;
261 }
262
263 while (count != 0) {
264
265 nwritten = count;
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);
270#else
271 ret = sendfile(fromfd, tofd, offset, count, &sf_header, &nwritten, 0);
272#endif
273 if (ret == -1 && errno != EINTR && errno != EAGAIN && errno != EWOULDBLOCK) {
274 /* Send failed, we are toast. */
275 return -1;
276 }
277
278 if (nwritten == 0) {
279 /* EOF of offset is after EOF. */
280 break;
281 }
282
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;
289 } else {
290 /* Partial header was sent. */
291 io_header.iov_len -= nwritten;
292 io_header.iov_base =
293 ((uint8_t *)io_header.iov_base) + nwritten;
294 nwritten = 0;
295 }
296 }
297
298 offset += nwritten;
299 count -= nwritten;
300 }
301
302 return nwritten;
303}
304
305#elif defined(AIX_SENDFILE_API)
306
307/* BEGIN AIX SEND_FILE */
308
309/* Contributed by William Jojo <jojowil@hvcc.edu> */
310#include <sys/socket.h>
311
312ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, off_t offset, size_t count)
313{
314 struct sf_parms hdtrl;
315
316 /* Set up the header/trailer struct params. */
317 if (header) {
318 hdtrl.header_data = header->data;
319 hdtrl.header_length = header->length;
320 } else {
321 hdtrl.header_data = NULL;
322 hdtrl.header_length = 0;
323 }
324 hdtrl.trailer_data = NULL;
325 hdtrl.trailer_length = 0;
326
327 hdtrl.file_descriptor = fromfd;
328 hdtrl.file_offset = offset;
329 hdtrl.file_bytes = count;
330
331 while ( hdtrl.file_bytes + hdtrl.header_length ) {
332 ssize_t ret;
333
334 /*
335 Return Value
336
337 There are three possible return values from send_file:
338
339 Value Description
340
341 -1 an error has occurred, errno contains the error code.
342
343 0 the command has completed successfully.
344
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.
348 */
349 do {
350 ret = send_file(&tofd, &hdtrl, 0);
351 } while ((ret == 1) || (ret == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)));
352 if ( ret == -1 )
353 return -1;
354 }
355
356 return count + header->length;
357}
358/* END AIX SEND_FILE */
359
360#else /* No sendfile implementation. Return error. */
361
362ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, off_t offset, size_t count)
363{
364 /* No sendfile syscall. */
365 errno = ENOSYS;
366 return -1;
367}
368#endif
Note: See TracBrowser for help on using the repository browser.