Use HAVE_SENDFILE64, not SENDFILE64.
[jra/samba/.git] / source3 / lib / sendfile.c
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 2 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, write to the Free Software
18  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 /*
22  * This file handles the OS dependent sendfile implementations.
23  * The API is such that it returns -1 on error, else returns the
24  * number of bytes written.
25  */
26
27 #include "includes.h"
28
29 #if defined(LINUX_SENDFILE_API)
30
31 #include <sys/sendfile.h>
32
33 #ifndef MSG_MORE
34 #define MSG_MORE 0x8000
35 #endif
36
37 ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
38 {
39         size_t total=0;
40         ssize_t ret;
41         ssize_t hdr_len = 0;
42
43         /*
44          * Send the header first.
45          * Use MSG_MORE to cork the TCP output until sendfile is called.
46          */
47
48         if (header) {
49                 hdr_len = header->length;
50                 while (total < hd_len) {
51                         ret = sys_send(tofd, header->data + total,hdr_len - total, MSG_MORE);
52                         if (ret == -1)
53                                 return -1;
54                         total += ret;
55                 }
56         }
57
58         total = count;
59         while (total) {
60                 ssize_t nwritten;
61                 do {
62 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_SENDFILE64)
63                         nwritten = sendfile64(tofd, fromfd, &offset, total);
64 #else
65                         nwritten = sendfile(tofd, fromfd, &offset, total);
66 #endif
67                 } while (nwritten == -1 && errno == EINTR);
68                 if (nwritten == -1)
69                         return -1;
70                 if (nwritten == 0)
71                         return -1; /* I think we're at EOF here... */
72                 total -= nwritten;
73         }
74         return count + hdr_len;
75 }
76
77 #elif defined(LINUX_BROKEN_SENDFILE_API)
78
79 #include <sys/sendfile.h>
80
81 #ifndef MSG_MORE
82 #define MSG_MORE 0x8000
83 #endif
84
85 ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
86 {
87         size_t total=0;
88         ssize_t ret;
89         ssize_t hdr_len = 0;
90
91         /* 
92          * Fix for broken Linux 2.4 systems with no working sendfile64().
93          * If the offset+count > 2 GB then pretend we don't have the
94          * system call sendfile at all. The upper later catches this
95          * and uses a normal read. JRA.
96          */
97
98         if ((sizeof(SMB_OFF_T) >= 8) && (offset + count > (SMB_OFF_T)0x7FFFFFFF)) {
99                 errno = ENOSYS;
100                 return -1;
101         }
102
103         /*
104          * Send the header first.
105          * Use MSG_MORE to cork the TCP output until sendfile is called.
106          */
107
108         if (header) {
109                 hdr_len = header->length;
110                 while (total < hd_len) {
111                         ret = sys_send(tofd, header->data + total,hdr_len - total, MSG_MORE);
112                         if (ret == -1)
113                                 return -1;
114                         total += ret;
115                 }
116         }
117
118         total = count;
119         while (total) {
120                 ssize_t nwritten;
121                 do {
122                         nwritten = sendfile(tofd, fromfd, &offset, total);
123                 } while (nwritten == -1 && errno == EINTR);
124                 if (nwritten == -1)
125                         return -1;
126                 if (nwritten == 0)
127                         return -1; /* I think we're at EOF here... */
128                 total -= nwritten;
129         }
130         return count + hdr_len;
131 }
132
133
134 #elif defined(SOLARIS_SENDFILE_API)
135
136 /* Hmmm. Can't find Solaris sendfile API docs.... Where is it ? */
137 ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
138 {
139         errno = ENOSYS;
140         return -1;
141 }
142
143 #elif defined(HPUX_SENDFILE_API)
144
145 #include <sys/socket.h>
146 #include <sys/uio.h>
147
148 ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
149 {
150         size_t total=0;
151         struct iovec hdtrl[2];
152         size_t hdr_len = 0;
153
154         if (header) {
155                 /* Set up the header/trailer iovec. */
156                 hdtrl[0].iov_base = header->data;
157                 hdtrl[0].iov_len = hdr_len = header->length;
158         } else {
159                 hdtrl[0].iov_base = NULL;
160                 hdtrl[0].iov_len = hdr_len = 0;
161         }
162         hdtrl[1].iov_base = NULL;
163         hdtrl[1].iov_base = 0;
164
165         total = count;
166         while (total + hdtrl[0].iov_len) {
167                 ssize_t nwritten;
168
169                 /*
170                  * HPUX guarantees that if any data was written before
171                  * a signal interrupt then sendfile returns the number of
172                  * bytes written (which may be less than requested) not -1.
173                  * nwritten includes the header data sent.
174                  */
175
176                 do {
177 #if defined(HAVE_EXPLICIT_LARGEFILE_SUPPORT) && defined(HAVE_OFF64_T) && defined(HAVE_SENDFILE64)
178                         nwritten = sendfile64(tofd, fromfd, offset, total, &hdtrl[0], 0);
179 #else
180                         nwritten = sendfile(tofd, fromfd, offset, total, &hdtrl[0], 0);
181 #endif
182                 } while (nwritten == -1 && errno == EINTR);
183                 if (nwritten == -1)
184                         return -1;
185                 if (nwritten == 0)
186                         return -1; /* I think we're at EOF here... */
187
188                 /*
189                  * If this was a short (signal interrupted) write we may need
190                  * to subtract it from the header data, or null out the header
191                  * data altogether if we wrote more than hdtrl[0].iov_len bytes.
192                  * We change nwritten to be the number of file bytes written.
193                  */
194
195                 if (hdtrl[0].iov_base && hdtrl[0].iov_len) {
196                         if (nwritten >= hdtrl[0].iov_len) {
197                                 nwritten -= hdtrl[0].iov_len;
198                                 hdtrl[0].iov_base = NULL;
199                                 hdtrl[0].iov_len = 0;
200                         } else {
201                                 nwritten = 0;
202                                 hdtrl[0].iov_base += nwritten;
203                                 hdtrl[0].iov_len -= nwritten;
204                         }
205                 }
206                 total -= nwritten;
207                 offset += nwritten;
208         }
209         return count + hdr_len;
210 }
211
212 #elif defined(FREEBSD_SENDFILE_API)
213
214 #include <sys/types.h>
215 #include <sys/socket.h>
216 #include <sys/uio.h>
217
218 ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
219 {
220         size_t total=0;
221         struct sf_hdtr hdr;
222         struct iovec hdtrl;
223         size_t hdr_len = 0;
224
225         hdr->headers = &hdtrl;
226         hdr->hdr_cnt = 1;
227         hdr->trailers = NULL;
228         hdr->trl_cnt = 0;
229
230         /* Set up the header iovec. */
231         if (header) {
232                 hdtrl.iov_base = header->data;
233                 hdtrl.iov_len = hdr_len = header->length;
234         } else {
235                 hdtrl.iov_base = NULL;
236                 hdtrl.iov_len = 0;
237         }
238
239         total = count;
240         while (total + hdtrl.iov_len) {
241                 SMB_OFF_T nwritten;
242                 int ret;
243
244                 /*
245                  * FreeBSD sendfile returns 0 on success, -1 on error.
246                  * Remember, the tofd and fromfd are reversed..... :-).
247                  * nwritten includes the header data sent.
248                  */
249
250                 do {
251                         ret = sendfile(fromfd, tofd, offset, total, &hdr, &nwritten, 0);
252                 } while (ret == -1 && errno == EINTR);
253                 if (ret == -1)
254                         return -1;
255
256                 if (nwritten == 0)
257                         return -1; /* I think we're at EOF here... */
258
259                 /*
260                  * If this was a short (signal interrupted) write we may need
261                  * to subtract it from the header data, or null out the header
262                  * data altogether if we wrote more than hdtrl.iov_len bytes.
263                  * We change nwritten to be the number of file bytes written.
264                  */
265
266                 if (hdtrl[0].iov_base && hdtrl.iov_len) {
267                         if (nwritten >= hdtrl.iov_len) {
268                                 nwritten -= hdtrl.iov_len;
269                                 hdtrl.iov_base = NULL;
270                                 hdtrl.iov_len = 0;
271                         } else {
272                                 nwritten = 0;
273                                 hdtrl.iov_base += nwritten;
274                                 hdtrl.iov_len -= nwritten;
275                         }
276                 }
277                 total -= nwritten;
278                 offset += nwritten;
279         }
280         return count + hdr_len;
281 }
282
283 #else /* No sendfile implementation. Return error. */
284
285 ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, SMB_OFF_T offset, size_t count)
286 {
287         /* No sendfile syscall. */
288         errno = ENOSYS;
289         return -1;
290 }
291 #endif