diff options
author | phk <phk@FreeBSD.org> | 2004-07-10 15:42:16 +0000 |
---|---|---|
committer | phk <phk@FreeBSD.org> | 2004-07-10 15:42:16 +0000 |
commit | b9f13e4266e1a358f8e0f5ee3542e657eabb8a19 (patch) | |
tree | de46976e3a829fc81580355aafed8ed3f3fcdb8e /sys/kern/kern_subr.c | |
parent | afe21b6175db45f3406c5cd8c0d1516078e4e32c (diff) | |
download | FreeBSD-src-b9f13e4266e1a358f8e0f5ee3542e657eabb8a19.zip FreeBSD-src-b9f13e4266e1a358f8e0f5ee3542e657eabb8a19.tar.gz |
Clean up and wash struct iovec and struct uio handling.
Add copyiniov() which copies a struct iovec array in from userland into
a malloc'ed struct iovec. Caller frees.
Change uiofromiov() to malloc the uio (caller frees) and name it
copyinuio() which is more appropriate.
Add cloneuio() which returns a malloc'ed copy. Caller frees.
Use them throughout.
Diffstat (limited to 'sys/kern/kern_subr.c')
-rw-r--r-- | sys/kern/kern_subr.c | 63 |
1 files changed, 46 insertions, 17 deletions
diff --git a/sys/kern/kern_subr.c b/sys/kern/kern_subr.c index 7ccccdd..8d5c6f0 100644 --- a/sys/kern/kern_subr.c +++ b/sys/kern/kern_subr.c @@ -474,40 +474,69 @@ copyinstrfrom(const void * __restrict src, void * __restrict dst, size_t len, } int -uiofromiov(struct iovec *iovp, u_int iovcnt, struct uio *uio) +copyiniov(struct iovec *iovp, u_int iovcnt, struct iovec **iov, int error) +{ + u_int iovlen; + + *iov = NULL; + if (iovcnt > UIO_MAXIOV) + return (error); + iovlen = iovcnt * sizeof (struct iovec); + *iov = malloc(iovlen, M_IOV, M_WAITOK); + error = copyin(iovp, *iov, iovlen); + if (error) { + free(*iov, M_IOV); + *iov = NULL; + } + return (error); +} + +int +copyinuio(struct iovec *iovp, u_int iovcnt, struct uio **uiop) { struct iovec *iov; + struct uio *uio; u_int iovlen; int error, i; - /* note: can't use iovlen until iovcnt is validated */ + *uiop = NULL; + if (iovcnt > UIO_MAXIOV) + return (EINVAL); iovlen = iovcnt * sizeof (struct iovec); - if (iovcnt > UIO_MAXIOV) { - error = EINVAL; - goto done; + uio = malloc(iovlen + sizeof *uio, M_IOV, M_WAITOK); + iov = (struct iovec *)(uio + 1); + error = copyin(iovp, iov, iovlen); + if (error) { + free(uio, M_IOV); + return (error); } - MALLOC(iov, struct iovec *, iovlen, M_IOV, M_WAITOK); uio->uio_iov = iov; uio->uio_iovcnt = iovcnt; uio->uio_segflg = UIO_USERSPACE; uio->uio_offset = -1; - if ((error = copyin(iovp, iov, iovlen))) - goto done; uio->uio_resid = 0; for (i = 0; i < iovcnt; i++) { if (iov->iov_len > INT_MAX - uio->uio_resid) { - error = EINVAL; - goto done; + free(uio, M_IOV); + return (EINVAL); } uio->uio_resid += iov->iov_len; iov++; } + *uiop = uio; + return (0); +} -done: - if (error && uio->uio_iov) { - FREE(uio->uio_iov, M_IOV); - uio->uio_iov = NULL; - } - return (error); - +struct uio * +cloneuio(struct uio *uiop) +{ + struct uio *uio; + int iovlen; + + iovlen = uiop->uio_iovcnt * sizeof (struct iovec); + uio = malloc(iovlen + sizeof *uio, M_IOV, M_WAITOK); + *uio = *uiop; + uio->uio_iov = (struct iovec *)(uio + 1); + bcopy(uiop->uio_iov, uio->uio_iov, iovlen); + return (uio); } |