- while (written < length) {
- len = sys_sendfile(dsi->socket, fromfd, &offset, length - written);
-
- if (len < 0) {
- if (errno == EINTR)
- continue;
- if (errno == EINVAL || errno == ENOSYS)
- return -1;
-
- if (errno == EAGAIN || errno == EWOULDBLOCK) {
- if (dsi_peek(dsi)) {
- /* can't go back to blocking mode, exit, the next read
- will return with an error and afpd will die.
- */
- break;
- }
- continue;
- }
- LOG(log_error, logtype_dsi, "dsi_stream_read_file: %s", strerror(errno));
- break;
- }
- else if (!len) {
- /* afpd is going to exit */
- errno = EIO;
- return -1; /* I think we're at EOF here... */
- }
- else
+ while (written < total) {
+#ifdef HAVE_SENDFILEV
+ nwritten = 0;
+ len = sendfilev(dsi->socket, vec, sfvcnt, &nwritten);
+#elif defined(FREEBSD)
+ len = sendfile(fromfd, dsi->socket, pos, total - written, hdrp, &nwritten, 0);
+ if (len == 0)
+ len = nwritten;
+#else
+ len = sys_sendfile(dsi->socket, fromfd, &pos, total - written);
+#endif
+ if (len < 0) {
+ switch (errno) {
+ case EINTR:
+ case EAGAIN:
+ len = 0;
+#if defined(HAVE_SENDFILEV) || defined(FREEBSD)
+ len = (size_t)nwritten;
+#elif defined(SOLARIS)
+ if (pos > offset) {
+ /* we actually have sent sth., adjust counters and keep trying */
+ len = pos - offset;
+ offset = pos;
+ }
+#endif /* HAVE_SENDFILEV */
+
+ if (dsi_peek(dsi) != 0) {
+ ret = -1;
+ goto exit;
+ }
+ break;
+ default:
+ LOG(log_error, logtype_dsi, "dsi_stream_read_file: %s", strerror(errno));
+ ret = -1;
+ goto exit;
+ }
+ } else if (len == 0) {
+ /* afpd is going to exit */
+ ret = -1;
+ goto exit;
+ }
+#ifdef HAVE_SENDFILEV
+ if (sfvcnt == 2 && len >= vec[0].sfv_len) {
+ vec[1].sfv_off += len - vec[0].sfv_len;
+ vec[1].sfv_len -= len - vec[0].sfv_len;
+
+ vec[0] = vec[1];
+ sfvcnt = 1;
+ } else {
+ vec[0].sfv_off += len;
+ vec[0].sfv_len -= len;
+ }
+#elif defined(FREEBSD)
+ if (hdrp) {
+ if (len >= iovec.iov_len) {
+ hdrp = NULL;
+ len -= iovec.iov_len; /* len now contains how much sendfile() actually sent from the file */
+ } else {
+ iovec.iov_len -= len;
+ iovec.iov_base += len;
+ len = 0;
+ }
+ }
+ pos += len;
+#endif /* HAVE_SENDFILEV */
+ LOG(log_maxdebug, logtype_dsi, "dsi_stream_read_file: wrote: %zd", len);