summaryrefslogtreecommitdiffstats
path: root/sys/kern/kern_subr.c
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>2004-07-10 15:42:16 +0000
committerphk <phk@FreeBSD.org>2004-07-10 15:42:16 +0000
commitb9f13e4266e1a358f8e0f5ee3542e657eabb8a19 (patch)
treede46976e3a829fc81580355aafed8ed3f3fcdb8e /sys/kern/kern_subr.c
parentafe21b6175db45f3406c5cd8c0d1516078e4e32c (diff)
downloadFreeBSD-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.c63
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);
}
OpenPOWER on IntegriCloud