pyldb: avoid segfault when adding an element with no name
[kamenim/samba-autobuild/.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 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 #include "system/filesys.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, off_t offset, size_t count)
38 {
39         size_t total=0;
40         ssize_t ret = -1;
41         size_t hdr_len = 0;
42         int old_flags = 0;
43         bool socket_flags_changed = false;
44
45         /*
46          * Send the header first.
47          * Use MSG_MORE to cork the TCP output until sendfile is called.
48          */
49
50         if (header) {
51                 hdr_len = header->length;
52                 while (total < hdr_len) {
53                         ret = sys_send(tofd, header->data + total,hdr_len - total, MSG_MORE);
54                         if (ret == -1) {
55                                 if (errno == EAGAIN || errno == EWOULDBLOCK) {
56                                         /*
57                                          * send() must complete before we can
58                                          * send any other outgoing data on the
59                                          * socket. Ensure socket is in blocking
60                                          * mode. For SMB2 by default the socket
61                                          * is in non-blocking mode.
62                                          */
63                                         old_flags = fcntl(tofd, F_GETFL, 0);
64                                         ret = set_blocking(tofd, true);
65                                         if (ret == -1) {
66                                                 goto out;
67                                         }
68                                         socket_flags_changed = true;
69                                         continue;
70                                 }
71                                 goto out;
72                         }
73                         total += ret;
74                 }
75         }
76
77         total = count;
78         while (total) {
79                 ssize_t nwritten;
80                 do {
81                         nwritten = sendfile(tofd, fromfd, &offset, total);
82                 } while (nwritten == -1 && errno == EINTR);
83                 if (nwritten == -1) {
84                         if (errno == EAGAIN || errno == EWOULDBLOCK) {
85                                 if (socket_flags_changed) {
86                                         /*
87                                          * We're already in blocking
88                                          * mode. This is an error.
89                                          */
90                                         ret = -1;
91                                         goto out;
92                                 }
93
94                                 /*
95                                  * Sendfile must complete before we can
96                                  * send any other outgoing data on the socket.
97                                  * Ensure socket is in blocking mode.
98                                  * For SMB2 by default the socket is in
99                                  * non-blocking mode.
100                                  */
101                                 old_flags = fcntl(tofd, F_GETFL, 0);
102                                 ret = set_blocking(tofd, true);
103                                 if (ret == -1) {
104                                         goto out;
105                                 }
106                                 socket_flags_changed = true;
107                                 continue;
108                         }
109
110                         if (errno == ENOSYS || errno == EINVAL) {
111                                 /* Ok - we're in a world of pain here. We just sent
112                                  * the header, but the sendfile failed. We have to
113                                  * emulate the sendfile at an upper layer before we
114                                  * disable it's use. So we do something really ugly.
115                                  * We set the errno to a strange value so we can detect
116                                  * this at the upper level and take care of it without
117                                  * layer violation. JRA.
118                                  */
119                                 errno = EINTR; /* Normally we can never return this. */
120                         }
121                         ret = -1;
122                         goto out;
123                 }
124                 if (nwritten == 0) {
125                         /*
126                          * EOF, return a short read
127                          */
128                         ret = hdr_len + (count - total);
129                         goto out;
130                 }
131                 total -= nwritten;
132         }
133
134         ret = count + hdr_len;
135
136   out:
137
138         if (socket_flags_changed) {
139                 int saved_errno;
140                 int err;
141
142                 if (ret == -1) {
143                         saved_errno = errno;
144                 }
145                 /* Restore the old state of the socket. */
146                 err = fcntl(tofd, F_SETFL, old_flags);
147                 if (err == -1) {
148                         return -1;
149                 }
150                 if (ret == -1) {
151                         errno = saved_errno;
152                 }
153         }
154
155         return ret;
156 }
157
158 #elif defined(SOLARIS_SENDFILE_API)
159
160 /*
161  * Solaris sendfile code written by Pierre Belanger <belanger@pobox.com>.
162  */
163
164 #include <sys/sendfile.h>
165
166 ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, off_t offset, size_t count)
167 {
168         int sfvcnt;
169         size_t total, xferred;
170         struct sendfilevec vec[2];
171         ssize_t hdr_len = 0;
172         int old_flags = 0;
173         ssize_t ret = -1;
174         bool socket_flags_changed = false;
175
176         if (header) {
177                 sfvcnt = 2;
178
179                 vec[0].sfv_fd = SFV_FD_SELF;
180                 vec[0].sfv_flag = 0;
181                 vec[0].sfv_off = (off_t)header->data;
182                 vec[0].sfv_len = hdr_len = header->length;
183
184                 vec[1].sfv_fd = fromfd;
185                 vec[1].sfv_flag = 0;
186                 vec[1].sfv_off = offset;
187                 vec[1].sfv_len = count;
188
189         } else {
190                 sfvcnt = 1;
191
192                 vec[0].sfv_fd = fromfd;
193                 vec[0].sfv_flag = 0;
194                 vec[0].sfv_off = offset;
195                 vec[0].sfv_len = count;
196         }
197
198         total = count + hdr_len;
199
200         while (total) {
201                 ssize_t nwritten;
202
203                 /*
204                  * Although not listed in the API error returns, this is almost certainly
205                  * a slow system call and will be interrupted by a signal with EINTR. JRA.
206                  */
207
208                 xferred = 0;
209
210                         nwritten = sendfilev(tofd, vec, sfvcnt, &xferred);
211                 if  (nwritten == -1 && errno == EINTR) {
212                         if (xferred == 0)
213                                 continue; /* Nothing written yet. */
214                         else
215                                 nwritten = xferred;
216                 }
217
218                 if (nwritten == -1) {
219                         if (errno == EAGAIN || errno == EWOULDBLOCK) {
220                                 /*
221                                  * Sendfile must complete before we can
222                                  * send any other outgoing data on the socket.
223                                  * Ensure socket is in blocking mode.
224                                  * For SMB2 by default the socket is in
225                                  * non-blocking mode.
226                                  */
227                                 old_flags = fcntl(tofd, F_GETFL, 0);
228                                 ret = set_blocking(tofd, true);
229                                 if (ret == -1) {
230                                         goto out;
231                                 }
232                                 socket_flags_changed = true;
233                                 continue;
234                         }
235                         ret = -1;
236                         goto out;
237                 }
238                 if (nwritten == 0) {
239                         ret = -1;
240                         goto out; /* I think we're at EOF here... */
241                 }
242
243                 /*
244                  * If this was a short (signal interrupted) write we may need
245                  * to subtract it from the header data, or null out the header
246                  * data altogether if we wrote more than vec[0].sfv_len bytes.
247                  * We move vec[1].* to vec[0].* and set sfvcnt to 1
248                  */
249
250                 if (sfvcnt == 2 && nwritten >= vec[0].sfv_len) {
251                         vec[1].sfv_off += nwritten - vec[0].sfv_len;
252                         vec[1].sfv_len -= nwritten - vec[0].sfv_len;
253
254                         /* Move vec[1].* to vec[0].* and set sfvcnt to 1 */
255                         vec[0] = vec[1];
256                         sfvcnt = 1;
257                 } else {
258                         vec[0].sfv_off += nwritten;
259                         vec[0].sfv_len -= nwritten;
260                 }
261                 total -= nwritten;
262         }
263         ret = count + hdr_len;
264
265   out:
266
267         if (socket_flags_changed) {
268                 int saved_errno;
269                 int err;
270
271                 if (ret == -1) {
272                         saved_errno = errno;
273                 }
274                 /* Restore the old state of the socket. */
275                 err = fcntl(tofd, F_SETFL, old_flags);
276                 if (err == -1) {
277                         return -1;
278                 }
279                 if (ret == -1) {
280                         errno = saved_errno;
281                 }
282         }
283
284         return ret;
285 }
286
287 #elif defined(HPUX_SENDFILE_API)
288
289 #include <sys/socket.h>
290 #include <sys/uio.h>
291
292 ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, off_t offset, size_t count)
293 {
294         size_t total=0;
295         struct iovec hdtrl[2];
296         size_t hdr_len = 0;
297         int old_flags = 0;
298         ssize_t ret = -1;
299         bool socket_flags_changed = false;
300
301         if (header) {
302                 /* Set up the header/trailer iovec. */
303                 hdtrl[0].iov_base = (void *)header->data;
304                 hdtrl[0].iov_len = hdr_len = header->length;
305         } else {
306                 hdtrl[0].iov_base = NULL;
307                 hdtrl[0].iov_len = hdr_len = 0;
308         }
309         hdtrl[1].iov_base = NULL;
310         hdtrl[1].iov_len = 0;
311
312         total = count;
313         while (total + hdtrl[0].iov_len) {
314                 ssize_t nwritten;
315
316                 /*
317                  * HPUX guarantees that if any data was written before
318                  * a signal interrupt then sendfile returns the number of
319                  * bytes written (which may be less than requested) not -1.
320                  * nwritten includes the header data sent.
321                  */
322
323                 do {
324                         nwritten = sendfile(tofd, fromfd, offset, total, &hdtrl[0], 0);
325                 } while (nwritten == -1 && errno == EINTR);
326                 if (nwritten == -1) {
327                         if (errno == EAGAIN || errno == EWOULDBLOCK) {
328                                 /*
329                                  * Sendfile must complete before we can
330                                  * send any other outgoing data on the socket.
331                                  * Ensure socket is in blocking mode.
332                                  * For SMB2 by default the socket is in
333                                  * non-blocking mode.
334                                  */
335                                 old_flags = fcntl(tofd, F_GETFL, 0);
336                                 ret = set_blocking(tofd, true);
337                                 if (ret == -1) {
338                                         goto out;
339                                 }
340                                 socket_flags_changed = true;
341                                 continue;
342                         }
343                         ret = -1;
344                         goto out;
345                 }
346                 if (nwritten == 0) {
347                         ret = -1; /* I think we're at EOF here... */
348                         goto out;
349                 }
350
351                 /*
352                  * If this was a short (signal interrupted) write we may need
353                  * to subtract it from the header data, or null out the header
354                  * data altogether if we wrote more than hdtrl[0].iov_len bytes.
355                  * We change nwritten to be the number of file bytes written.
356                  */
357
358                 if (hdtrl[0].iov_base && hdtrl[0].iov_len) {
359                         if (nwritten >= hdtrl[0].iov_len) {
360                                 nwritten -= hdtrl[0].iov_len;
361                                 hdtrl[0].iov_base = NULL;
362                                 hdtrl[0].iov_len = 0;
363                         } else {
364                                 /* iov_base is defined as a void *... */
365                                 hdtrl[0].iov_base = (void *)(((char *)hdtrl[0].iov_base) + nwritten);
366                                 hdtrl[0].iov_len -= nwritten;
367                                 nwritten = 0;
368                         }
369                 }
370                 total -= nwritten;
371                 offset += nwritten;
372         }
373         ret = count + hdr_len;
374
375   out:
376
377         if (socket_flags_changed) {
378                 int saved_errno;
379                 int err;
380
381                 if (ret == -1) {
382                         saved_errno = errno;
383                 }
384                 /* Restore the old state of the socket. */
385                 err = fcntl(tofd, F_SETFL, old_flags);
386                 if (err == -1) {
387                         return -1;
388                 }
389                 if (ret == -1) {
390                         errno = saved_errno;
391                 }
392         }
393
394         return ret;
395 }
396
397 #elif defined(FREEBSD_SENDFILE_API) || defined(DARWIN_SENDFILE_API)
398
399 #include <sys/types.h>
400 #include <sys/socket.h>
401 #include <sys/uio.h>
402
403 ssize_t sys_sendfile(int tofd, int fromfd,
404             const DATA_BLOB *header, off_t offset, size_t count)
405 {
406         struct sf_hdtr  sf_header = {0};
407         struct iovec    io_header = {0};
408         int old_flags = 0;
409
410         off_t   nwritten;
411         ssize_t ret = -1;
412         bool socket_flags_changed = false;
413
414         if (header) {
415                 sf_header.headers = &io_header;
416                 sf_header.hdr_cnt = 1;
417                 io_header.iov_base = header->data;
418                 io_header.iov_len = header->length;
419                 sf_header.trailers = NULL;
420                 sf_header.trl_cnt = 0;
421         }
422
423         while (count != 0) {
424
425                 nwritten = count;
426 #if defined(DARWIN_SENDFILE_API)
427                 /* Darwin recycles nwritten as a value-result parameter, apart from that this
428                    sendfile implementation is quite the same as the FreeBSD one */
429                 ret = sendfile(fromfd, tofd, offset, &nwritten, &sf_header, 0);
430 #else
431                 ret = sendfile(fromfd, tofd, offset, count, &sf_header, &nwritten, 0);
432 #endif
433                 if (ret == -1 && errno != EINTR) {
434                         if (errno == EAGAIN || errno == EWOULDBLOCK) {
435                                 /*
436                                  * Sendfile must complete before we can
437                                  * send any other outgoing data on the socket.
438                                  * Ensure socket is in blocking mode.
439                                  * For SMB2 by default the socket is in
440                                  * non-blocking mode.
441                                  */
442                                 old_flags = fcntl(tofd, F_GETFL, 0);
443                                 ret = set_blocking(tofd, true);
444                                 if (ret == -1) {
445                                         goto out;
446                                 }
447                                 socket_flags_changed = true;
448                                 continue;
449                         }
450                         /* Send failed, we are toast. */
451                         ret = -1;
452                         goto out;
453                 }
454
455                 if (nwritten == 0) {
456                         /* EOF of offset is after EOF. */
457                         break;
458                 }
459
460                 if (sf_header.hdr_cnt) {
461                         if (io_header.iov_len <= nwritten) {
462                                 /* Entire header was sent. */
463                                 sf_header.headers = NULL;
464                                 sf_header.hdr_cnt = 0;
465                                 nwritten -= io_header.iov_len;
466                         } else {
467                                 /* Partial header was sent. */
468                                 io_header.iov_len -= nwritten;
469                                 io_header.iov_base =
470                                     ((uint8_t *)io_header.iov_base) + nwritten;
471                                 nwritten = 0;
472                         }
473                 }
474
475                 offset += nwritten;
476                 count -= nwritten;
477         }
478
479         ret = nwritten;
480
481   out:
482
483         if (socket_flags_changed) {
484                 int saved_errno;
485                 int err;
486
487                 if (ret == -1) {
488                         saved_errno = errno;
489                 }
490                 /* Restore the old state of the socket. */
491                 err = fcntl(tofd, F_SETFL, old_flags);
492                 if (err == -1) {
493                         return -1;
494                 }
495                 if (ret == -1) {
496                         errno = saved_errno;
497                 }
498         }
499
500         return ret;
501 }
502
503 #elif defined(AIX_SENDFILE_API)
504
505 /* BEGIN AIX SEND_FILE */
506
507 /* Contributed by William Jojo <jojowil@hvcc.edu> */
508 #include <sys/socket.h>
509
510 ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, off_t offset, size_t count)
511 {
512         struct sf_parms hdtrl;
513         int old_flags = 0;
514         ssize_t ret = -1;
515         bool socket_flags_changed = false;
516
517         /* Set up the header/trailer struct params. */
518         if (header) {
519                 hdtrl.header_data = header->data;
520                 hdtrl.header_length = header->length;
521         } else {
522                 hdtrl.header_data = NULL;
523                 hdtrl.header_length = 0;
524         }
525         hdtrl.trailer_data = NULL;
526         hdtrl.trailer_length = 0;
527
528         hdtrl.file_descriptor = fromfd;
529         hdtrl.file_offset = offset;
530         hdtrl.file_bytes = count;
531
532         while ( hdtrl.file_bytes + hdtrl.header_length ) {
533                 /*
534                  Return Value
535
536                  There are three possible return values from send_file:
537
538                  Value Description
539
540                  -1 an error has occurred, errno contains the error code.
541
542                  0 the command has completed successfully.
543
544                  1 the command was completed partially, some data has been
545                  transmitted but the command has to return for some reason,
546                  for example, the command was interrupted by signals.
547                 */
548                 do {
549                         ret = send_file(&tofd, &hdtrl, 0);
550                 } while ((ret == 1) || (ret == -1 && errno == EINTR));
551                 if ( ret == -1 ) {
552                         if (errno == EAGAIN || errno == EWOULDBLOCK) {
553                                 /*
554                                  * Sendfile must complete before we can
555                                  * send any other outgoing data on the socket.
556                                  * Ensure socket is in blocking mode.
557                                  * For SMB2 by default the socket is in
558                                  * non-blocking mode.
559                                  */
560                                 old_flags = fcntl(tofd, F_GETFL, 0);
561                                 ret = set_blocking(tofd, true);
562                                 if (ret == -1) {
563                                         goto out;
564                                 }
565                                 socket_flags_changed = true;
566                                 continue;
567                         }
568                         goto out;
569                 }
570         }
571
572         ret = count + header->length;
573
574   out:
575
576         if (socket_flags_changed) {
577                 int saved_errno;
578                 int err;
579
580                 if (ret == -1) {
581                         saved_errno = errno;
582                 }
583                 /* Restore the old state of the socket. */
584                 err = fcntl(tofd, F_SETFL, old_flags);
585                 if (err == -1) {
586                         return -1;
587                 }
588                 if (ret == -1) {
589                         errno = saved_errno;
590                 }
591         }
592
593         return ret;
594 }
595 /* END AIX SEND_FILE */
596
597 #else /* No sendfile implementation. Return error. */
598
599 ssize_t sys_sendfile(int tofd, int fromfd, const DATA_BLOB *header, off_t offset, size_t count)
600 {
601         /* No sendfile syscall. */
602         errno = ENOSYS;
603         return -1;
604 }
605 #endif