s3:smbd: SMBtdis should return ERRSRV, ERRinvnid instead of NETWORK_NAME_DELETED
[Samba/gebeck_regimport.git] / source3 / lib / sendfile.c
bloba9607fa82594fe27de088ce758653165c37b4bf8
1 /*
2 Unix SMB/Netbios implementation.
3 Version 2.2.x / 3.0.x
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.
26 #include "includes.h"
28 #if defined(LINUX_SENDFILE_API)
30 #include <sys/sendfile.h>
32 #ifndef MSG_MORE
33 #define MSG_MORE 0x8000
34 #endif
36 ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, off_t offset, size_t count)
38 size_t total=0;
39 ssize_t ret;
40 size_t hdr_len = 0;
43 * Send the header first.
44 * Use MSG_MORE to cork the TCP output until sendfile is called.
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;
57 total = count;
58 while (total) {
59 ssize_t nwritten;
60 do {
61 nwritten = sendfile(tofd, fromfd, &offset, total);
62 #if defined(EWOULDBLOCK)
63 } while (nwritten == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
64 #else
65 } while (nwritten == -1 && (errno == EINTR || errno == EAGAIN));
66 #endif
67 if (nwritten == -1) {
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. */
79 return -1;
81 if (nwritten == 0) {
83 * EOF, return a short read
85 return hdr_len + (count - total);
87 total -= nwritten;
89 return count + hdr_len;
92 #elif defined(LINUX_BROKEN_SENDFILE_API)
95 * We must use explicit 32 bit types here. This code path means Linux
96 * won't do proper 64-bit sendfile. JRA.
99 extern int32 sendfile (int out_fd, int in_fd, int32 *offset, uint32 count);
102 #ifndef MSG_MORE
103 #define MSG_MORE 0x8000
104 #endif
106 ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, off_t offset, size_t count)
108 size_t total=0;
109 ssize_t ret;
110 ssize_t hdr_len = 0;
111 uint32 small_total = 0;
112 int32 small_offset;
115 * Fix for broken Linux 2.4 systems with no working sendfile64().
116 * If the offset+count > 2 GB then pretend we don't have the
117 * system call sendfile at all. The upper layer catches this
118 * and uses a normal read. JRA.
121 if ((sizeof(off_t) >= 8) && (offset + count > (off_t)0x7FFFFFFF)) {
122 errno = ENOSYS;
123 return -1;
127 * Send the header first.
128 * Use MSG_MORE to cork the TCP output until sendfile is called.
131 if (header) {
132 hdr_len = header->length;
133 while (total < hdr_len) {
134 ret = sys_send(tofd, header->data + total,hdr_len - total, MSG_MORE);
135 if (ret == -1)
136 return -1;
137 total += ret;
141 small_total = (uint32)count;
142 small_offset = (int32)offset;
144 while (small_total) {
145 int32 nwritten;
146 do {
147 nwritten = sendfile(tofd, fromfd, &small_offset, small_total);
148 #if defined(EWOULDBLOCK)
149 } while (nwritten == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
150 #else
151 } while (nwritten == -1 && (errno == EINTR || errno == EAGAIN));
152 #endif
153 if (nwritten == -1) {
154 if (errno == ENOSYS || errno == EINVAL) {
155 /* Ok - we're in a world of pain here. We just sent
156 * the header, but the sendfile failed. We have to
157 * emulate the sendfile at an upper layer before we
158 * disable it's use. So we do something really ugly.
159 * We set the errno to a strange value so we can detect
160 * this at the upper level and take care of it without
161 * layer violation. JRA.
163 errno = EINTR; /* Normally we can never return this. */
165 return -1;
167 if (nwritten == 0) {
169 * EOF, return a short read
171 return hdr_len + (((uint32)count) - small_total);
173 small_total -= nwritten;
175 return count + hdr_len;
179 #elif defined(SOLARIS_SENDFILE_API)
182 * Solaris sendfile code written by Pierre Belanger <belanger@pobox.com>.
185 #include <sys/sendfile.h>
187 ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, off_t offset, size_t count)
189 int sfvcnt;
190 size_t total, xferred;
191 struct sendfilevec vec[2];
192 ssize_t hdr_len = 0;
194 if (header) {
195 sfvcnt = 2;
197 vec[0].sfv_fd = SFV_FD_SELF;
198 vec[0].sfv_flag = 0;
199 vec[0].sfv_off = (off_t)header->data;
200 vec[0].sfv_len = hdr_len = header->length;
202 vec[1].sfv_fd = fromfd;
203 vec[1].sfv_flag = 0;
204 vec[1].sfv_off = offset;
205 vec[1].sfv_len = count;
207 } else {
208 sfvcnt = 1;
210 vec[0].sfv_fd = fromfd;
211 vec[0].sfv_flag = 0;
212 vec[0].sfv_off = offset;
213 vec[0].sfv_len = count;
216 total = count + hdr_len;
218 while (total) {
219 ssize_t nwritten;
222 * Although not listed in the API error returns, this is almost certainly
223 * a slow system call and will be interrupted by a signal with EINTR. JRA.
226 xferred = 0;
228 nwritten = sendfilev(tofd, vec, sfvcnt, &xferred);
229 #if defined(EWOULDBLOCK)
230 if (nwritten == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)) {
231 #else
232 if (nwritten == -1 && (errno == EINTR || errno == EAGAIN)) {
233 #endif
234 if (xferred == 0)
235 continue; /* Nothing written yet. */
236 else
237 nwritten = xferred;
240 if (nwritten == -1)
241 return -1;
242 if (nwritten == 0)
243 return -1; /* I think we're at EOF here... */
246 * If this was a short (signal interrupted) write we may need
247 * to subtract it from the header data, or null out the header
248 * data altogether if we wrote more than vec[0].sfv_len bytes.
249 * We move vec[1].* to vec[0].* and set sfvcnt to 1
252 if (sfvcnt == 2 && nwritten >= vec[0].sfv_len) {
253 vec[1].sfv_off += nwritten - vec[0].sfv_len;
254 vec[1].sfv_len -= nwritten - vec[0].sfv_len;
256 /* Move vec[1].* to vec[0].* and set sfvcnt to 1 */
257 vec[0] = vec[1];
258 sfvcnt = 1;
259 } else {
260 vec[0].sfv_off += nwritten;
261 vec[0].sfv_len -= nwritten;
263 total -= nwritten;
265 return count + hdr_len;
268 #elif defined(HPUX_SENDFILE_API)
270 #include <sys/socket.h>
271 #include <sys/uio.h>
273 ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, off_t offset, size_t count)
275 size_t total=0;
276 struct iovec hdtrl[2];
277 size_t hdr_len = 0;
279 if (header) {
280 /* Set up the header/trailer iovec. */
281 hdtrl[0].iov_base = (void *)header->data;
282 hdtrl[0].iov_len = hdr_len = header->length;
283 } else {
284 hdtrl[0].iov_base = NULL;
285 hdtrl[0].iov_len = hdr_len = 0;
287 hdtrl[1].iov_base = NULL;
288 hdtrl[1].iov_len = 0;
290 total = count;
291 while (total + hdtrl[0].iov_len) {
292 ssize_t nwritten;
295 * HPUX guarantees that if any data was written before
296 * a signal interrupt then sendfile returns the number of
297 * bytes written (which may be less than requested) not -1.
298 * nwritten includes the header data sent.
301 do {
302 nwritten = sendfile(tofd, fromfd, offset, total, &hdtrl[0], 0);
303 #if defined(EWOULDBLOCK)
304 } while (nwritten == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
305 #else
306 } while (nwritten == -1 && (errno == EINTR || errno == EAGAIN));
307 #endif
308 if (nwritten == -1)
309 return -1;
310 if (nwritten == 0)
311 return -1; /* I think we're at EOF here... */
314 * If this was a short (signal interrupted) write we may need
315 * to subtract it from the header data, or null out the header
316 * data altogether if we wrote more than hdtrl[0].iov_len bytes.
317 * We change nwritten to be the number of file bytes written.
320 if (hdtrl[0].iov_base && hdtrl[0].iov_len) {
321 if (nwritten >= hdtrl[0].iov_len) {
322 nwritten -= hdtrl[0].iov_len;
323 hdtrl[0].iov_base = NULL;
324 hdtrl[0].iov_len = 0;
325 } else {
326 /* iov_base is defined as a void *... */
327 hdtrl[0].iov_base = (void *)(((char *)hdtrl[0].iov_base) + nwritten);
328 hdtrl[0].iov_len -= nwritten;
329 nwritten = 0;
332 total -= nwritten;
333 offset += nwritten;
335 return count + hdr_len;
338 #elif defined(FREEBSD_SENDFILE_API)
340 #include <sys/types.h>
341 #include <sys/socket.h>
342 #include <sys/uio.h>
344 ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, off_t offset, size_t count)
346 size_t total=0;
347 struct sf_hdtr hdr;
348 struct iovec hdtrl;
349 size_t hdr_len = 0;
351 hdr.headers = &hdtrl;
352 hdr.hdr_cnt = 1;
353 hdr.trailers = NULL;
354 hdr.trl_cnt = 0;
356 /* Set up the header iovec. */
357 if (header) {
358 hdtrl.iov_base = (void *)header->data;
359 hdtrl.iov_len = hdr_len = header->length;
360 } else {
361 hdtrl.iov_base = NULL;
362 hdtrl.iov_len = 0;
365 total = count;
366 while (total + hdtrl.iov_len) {
367 off_t nwritten;
368 int ret;
371 * FreeBSD sendfile returns 0 on success, -1 on error.
372 * Remember, the tofd and fromfd are reversed..... :-).
373 * nwritten includes the header data sent.
376 do {
377 ret = sendfile(fromfd, tofd, offset, total, &hdr, &nwritten, 0);
378 #if defined(EWOULDBLOCK)
379 } while (ret == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
380 #else
381 } while (ret == -1 && (errno == EINTR || errno == EAGAIN));
382 #endif
383 if (ret == -1)
384 return -1;
386 if (nwritten == 0)
387 return -1; /* I think we're at EOF here... */
390 * If this was a short (signal interrupted) write we may need
391 * to subtract it from the header data, or null out the header
392 * data altogether if we wrote more than hdtrl.iov_len bytes.
393 * We change nwritten to be the number of file bytes written.
396 if (hdtrl.iov_base && hdtrl.iov_len) {
397 if (nwritten >= hdtrl.iov_len) {
398 nwritten -= hdtrl.iov_len;
399 hdtrl.iov_base = NULL;
400 hdtrl.iov_len = 0;
401 } else {
402 hdtrl.iov_base =
403 (void *)((caddr_t)hdtrl.iov_base + nwritten);
404 hdtrl.iov_len -= nwritten;
405 nwritten = 0;
408 total -= nwritten;
409 offset += nwritten;
411 return count + hdr_len;
414 #elif defined(AIX_SENDFILE_API)
416 /* BEGIN AIX SEND_FILE */
418 /* Contributed by William Jojo <jojowil@hvcc.edu> */
419 #include <sys/socket.h>
421 ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, off_t offset, size_t count)
423 struct sf_parms hdtrl;
425 /* Set up the header/trailer struct params. */
426 if (header) {
427 hdtrl.header_data = header->data;
428 hdtrl.header_length = header->length;
429 } else {
430 hdtrl.header_data = NULL;
431 hdtrl.header_length = 0;
433 hdtrl.trailer_data = NULL;
434 hdtrl.trailer_length = 0;
436 hdtrl.file_descriptor = fromfd;
437 hdtrl.file_offset = offset;
438 hdtrl.file_bytes = count;
440 while ( hdtrl.file_bytes + hdtrl.header_length ) {
441 ssize_t ret;
444 Return Value
446 There are three possible return values from send_file:
448 Value Description
450 -1 an error has occurred, errno contains the error code.
452 0 the command has completed successfully.
454 1 the command was completed partially, some data has been
455 transmitted but the command has to return for some reason,
456 for example, the command was interrupted by signals.
458 do {
459 ret = send_file(&tofd, &hdtrl, 0);
460 #if defined(EWOULDBLOCK)
461 } while ((ret == 1) || (ret == -1 && (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)));
462 #else
463 } while ((ret == 1) || (ret == -1 && (errno == EINTR || errno == EAGAIN)));
464 #endif
465 if ( ret == -1 )
466 return -1;
469 return count + header->length;
471 /* END AIX SEND_FILE */
473 #else /* No sendfile implementation. Return error. */
475 ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, off_t offset, size_t count)
477 /* No sendfile syscall. */
478 errno = ENOSYS;
479 return -1;
481 #endif