Beispiel #1
0
ssize_t vfswrap_sendfile(vfs_handle_struct *handle, int tofd, files_struct *fsp, int fromfd, const DATA_BLOB *hdr,
			SMB_OFF_T offset, size_t n)
{
	ssize_t result;

	START_PROFILE_BYTES(syscall_sendfile, n);
	result = sys_sendfile(tofd, fromfd, hdr, offset, n);
	END_PROFILE(syscall_sendfile);
	return result;
}
Beispiel #2
0
/*
 * Transmit the body of a file using sendfile().
 *
 * Linux at the moment requires the input be page-based -- ie a disk file, and
 * only on particular filesystems.  If the sendfile() call fails in a way that
 * makes us think that regular IO might work, then we try that instead.  For
 * example, the /tmp filesystem may not support sendfile().
 */
int
dcc_pump_sendfile(int ofd, int ifd, size_t size)
{
    ssize_t sent;
    off_t offset = 0;
    int ret;

    while (size) {
        /* Handle possibility of partial transmission, e.g. if
         * sendfile() is interrupted by a signal.  size is decremented
         * as we go. */

        sent = sys_sendfile(ofd, ifd, &offset, size);
        if (sent == -1) {
            if ((errno == ENOSYS || errno == EINVAL) && offset == 0) {
                /* The offset==0 tests is because we may be part way through
                 * the file.  We can't just naively go back to read/write
                 * because sendfile() does not update the file pointer: we
                 * would need to lseek() first.  That case is not handled at
                 * the moment because it's unlikely that sendfile() would
                 * suddenly be unsupported while we're using it.  A failure
                 * halfway through probably indicates a genuine error.*/

                rs_log_info("decided to use read/write rather than sendfile");
                return dcc_pump_readwrite(ofd, ifd, size);
            } else if (errno == EAGAIN) {
                /* Sleep until we're able to write out more data. */
                if ((ret = dcc_select_for_write(ofd, dcc_io_timeout)) != 0)
                    return ret;
                rs_trace("select() returned, continuing to write");
            } else if (errno == EINTR) {
                rs_trace("sendfile() interrupted, continuing");
            } else {
                rs_log_error("sendfile failed: %s", strerror(errno));
                return EXIT_IO_ERROR;
            }
        } else if (sent == 0) {
            rs_log_error("sendfile returned 0? can't cope");
            return EXIT_IO_ERROR;
        } else if (sent != (ssize_t) size) {
            /* offset is automatically updated by sendfile. */
            size -= sent;
            rs_log_notice("sendfile: partial transmission of %ld bytes; retrying %ld @%ld",
                          (long) sent, (long) size, (long) offset);
        } else {
            /* normal case, everything was sent. */
            break;
        }
    }
    return 0;
}
Beispiel #3
0
ssize_t dsi_stream_read_file(DSI *dsi, int fromfd, off_t offset, const size_t length)
{
  size_t written;
  ssize_t len;

  LOG(log_maxdebug, logtype_dsi, "dsi_stream_read_file: sending %u bytes", length);

  if (dsi->flags & DSI_DISCONNECTED)
      return -1;

  dsi->in_write++;
  written = 0;

  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 
        written += len;
  }

  dsi->write_count += written;
  dsi->in_write--;
  return written;
}
Beispiel #4
0
/* read from a socket and write to an adouble file */
ssize_t ad_writefile(struct adouble *ad, const int eid, 
		     const int sock, off_t off, const int end,
		     const size_t len)
{
#ifdef __linux__
  ssize_t cc;
  int fd;

  fd = ad_sendfile_init(ad, eid, &off, end);
  if ((cc = sys_sendfile(fd, sock, &off, len)) < 0)
    return -1;

  if ((eid != ADEID_DFORK) && (off > ad_getentrylen(ad, eid))) 
    ad_setentrylen(ad, eid, off);

  return cc;
#endif /* __linux__ */
}
Beispiel #5
0
asmlinkage int sys32_sendfile(int out_fd, int in_fd, compat_off_t __user *offset, s32 count)
{
        mm_segment_t old_fs = get_fs();
        int ret;
        off_t of;

        if (offset && get_user(of, offset))
                return -EFAULT;

        set_fs(KERNEL_DS);
        ret = sys_sendfile(out_fd, in_fd, offset ? (off_t __user *)&of : NULL, count);
        set_fs(old_fs);

        if (offset && put_user(of, offset))
                return -EFAULT;

        return ret;
}
/* Note: it is necessary to treat out_fd and in_fd as unsigned ints, 
 * with the corresponding cast to a signed int to insure that the 
 * proper conversion (sign extension) between the register representation of a signed int (msr in 32-bit mode)
 * and the register representation of a signed int (msr in 64-bit mode) is performed.
 */
asmlinkage long compat_sys_sendfile(u32 out_fd, u32 in_fd, compat_off_t __user * offset, u32 count)
{
	mm_segment_t old_fs = get_fs();
	int ret;
	off_t of;
	off_t __user *up;

	if (offset && get_user(of, offset))
		return -EFAULT;

	/* The __user pointer cast is valid because of the set_fs() */		
	set_fs(KERNEL_DS);
	up = offset ? (off_t __user *) &of : NULL;
	ret = sys_sendfile((int)out_fd, (int)in_fd, up, count);
	set_fs(old_fs);
	
	if (offset && put_user(of, offset))
		return -EFAULT;
		
	return ret;
}
Beispiel #7
0
ssize_t dsi_stream_read_file(DSI *dsi, const int fromfd, off_t offset, const size_t length, const int err)
{
    int ret = 0;
    size_t written = 0;
    size_t total = length;
    ssize_t len;
    off_t pos = offset;
    char block[DSI_BLOCKSIZ];
#ifdef HAVE_SENDFILEV
    int sfvcnt;
    struct sendfilevec vec[2];
    ssize_t nwritten;
#elif defined(FREEBSD)
    ssize_t nwritten;
    void *hdrp;
    struct sf_hdtr hdr;
    struct iovec iovec;
    hdr.headers = &iovec;
    hdr.hdr_cnt = 1;
    hdr.trailers = NULL;
    hdr.trl_cnt = 0;
    hdrp = &hdr;
#endif

    LOG(log_maxdebug, logtype_dsi, "dsi_stream_read_file(off: %jd, len: %zu)", (intmax_t)offset, length);

    if (dsi->flags & DSI_DISCONNECTED)
        return -1;

    dsi->in_write++;

    dsi->flags |= DSI_NOREPLY;
    dsi->header.dsi_flags = DSIFL_REPLY;
    dsi->header.dsi_len = htonl(length);
    dsi->header.dsi_code = htonl(err);
    dsi_header_pack_reply(dsi, block);

#ifdef HAVE_SENDFILEV
    total += DSI_BLOCKSIZ;
    sfvcnt = 2;
    vec[0].sfv_fd = SFV_FD_SELF;
    vec[0].sfv_flag = 0;
    /* Cast to unsigned long to prevent sign extension of the
     * pointer value for the LFS case; see Apache PR 39463. */
    vec[0].sfv_off = (unsigned long)block;
    vec[0].sfv_len = DSI_BLOCKSIZ;
    vec[1].sfv_fd = fromfd;
    vec[1].sfv_flag = 0;
    vec[1].sfv_off = offset;
    vec[1].sfv_len = length;
#elif defined(FREEBSD)
    iovec.iov_base = block;
    iovec.iov_len = DSI_BLOCKSIZ;
#else
    dsi_stream_write(dsi, block, sizeof(block), DSI_MSG_MORE);
#endif

    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);
        written += len;
    }
#ifdef HAVE_SENDFILEV
    written -= DSI_BLOCKSIZ;
#endif
    dsi->write_count += written;

exit:
    dsi->in_write--;
    LOG(log_maxdebug, logtype_dsi, "dsi_stream_read_file: written: %zd", written);
    if (ret != 0)
        return -1;
    return written;
}