diff options
Diffstat (limited to 'erts/emulator/drivers/common/efile_drv.c')
-rw-r--r-- | erts/emulator/drivers/common/efile_drv.c | 68 |
1 files changed, 54 insertions, 14 deletions
diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index 1f13a65350..7eaafd5af1 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -358,15 +358,6 @@ struct t_readdir_buf { char buf[READDIR_BUFSIZE]; }; -#ifdef HAVE_SENDFILE -struct t_sendfile_hdtl { - int hdr_cnt; /* number of header iovecs */ - struct iovec *headers; /* pointer to header iovecs */ - int trl_cnt; /* number of trailer iovecs */ - struct iovec *trailers; /* pointer to trailer iovecs */ -}; -#endif /* HAVE_SENDFILE */ - struct t_data { struct t_data *next; @@ -530,6 +521,8 @@ static void *ef_safe_realloc(void *op, Uint s) !0) \ : 0) +/* int EV_GET_SYSIOVEC(ErlIoVec *ev, Uint32, int *cnt, SysIOVec **target, int *pp, int *qp) */ +#define EV_GET_SYSIOVEC ev_get_sysiovec #if 0 @@ -943,6 +936,41 @@ static int reply_eof(file_descriptor *desc) { return 0; } +static int ev_get_sysiovec(ErlIOVec *ev, Uint32 len, int *cnt, SysIOVec **target, int *pp, int *qp) { + int tmp_p = *pp, tmp_q = *qp, tmp_len = len, i; + SysIOVec *tmp_target; + while (tmp_len != 0) { + if (tmp_len + tmp_p > ev->iov[tmp_q].iov_len) { + + tmp_len -= ev->iov[tmp_q].iov_len - tmp_p; + tmp_q++; + tmp_p = 0; + if (tmp_q == ev->vsize) + return 0; + } else break; + } + *cnt = tmp_q - *qp + 1; + tmp_target = EF_SAFE_ALLOC(sizeof(SysIOVec)* (*cnt)); + *target = tmp_target; + for (i = 0; i < *cnt; i++) { + tmp_target[i].iov_base = ev->iov[*qp].iov_base+*pp; + if (len + *pp <= ev->iov[*qp].iov_len) { + tmp_target[i].iov_len = len; + if (len + *pp == ev->iov[*qp].iov_len) { + *pp = 0; + (*qp)++; + } else + *pp += len; + } else { + tmp_target[i].iov_len = ev->iov[*qp].iov_len - *pp; + len -= ev->iov[*qp].iov_len - *pp; + *pp = 0; + (*qp)++; + } + } + return 1; +} + static void invoke_name(void *data, int (*f)(Efile_error *, char *)) @@ -1753,7 +1781,7 @@ static void invoke_sendfile(void *data) int result = 0; d->again = 0; - result = efile_sendfile(&d->errInfo, fd, out_fd, &d->c.sendfile.offset, &nbytes); + result = efile_sendfile(&d->errInfo, fd, out_fd, &d->c.sendfile.offset, &nbytes, &d->c.sendfile.hdtl); d->c.sendfile.written += nbytes; @@ -3394,7 +3422,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { #ifdef HAVE_SENDFILE struct t_data *d; - Uint32 out_fd, offsetH, offsetL; + Uint32 out_fd, offsetH, offsetL, hd_len, tl_len; Uint64 nbytes; char flags; @@ -3410,7 +3438,9 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { || !EV_GET_CHAR(ev, &flags, &p, &q) || !EV_GET_UINT32(ev, &offsetH, &p, &q) || !EV_GET_UINT32(ev, &offsetL, &p, &q) - || !EV_GET_UINT64(ev, &nbytes, &p, &q)) { + || !EV_GET_UINT64(ev, &nbytes, &p, &q) + || !EV_GET_UINT32(ev, &hd_len, &p, &q) + || !EV_GET_UINT32(ev, &tl_len, &p, &q)) { /* Buffer has wrong length to contain all the needed values */ reply_posix_error(desc, EINVAL); goto done; @@ -3438,8 +3468,18 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { #endif d->c.sendfile.nbytes = nbytes; - - /* Do HEADER TRAILER stuff by calculating pointer places, not by copying data! */ + if (hd_len == 0 && tl_len == 0) + d->c.sendfile.hdtl = NULL; + else { + d->c.sendfile.hdtl = EF_SAFE_ALLOC(sizeof(struct t_sendfile_hdtl)); + if (!EV_GET_SYSIOVEC(ev, hd_len, &d->c.sendfile.hdtl->hdr_cnt, &d->c.sendfile.hdtl->headers, &p, &q) + || !EV_GET_SYSIOVEC(ev, tl_len, &d->c.sendfile.hdtl->trl_cnt, &d->c.sendfile.hdtl->trailers, &p, &q)) { + EF_FREE(d->c.sendfile.hdtl); + EF_FREE(d); + reply_posix_error(desc, EINVAL); + goto done; + } + } if (sys_info.async_threads != 0) { SET_BLOCKING(d->c.sendfile.out_fd); |