diff mbox series

[kvmtool,10/24] Add memcpy_fromiovec_safe

Message ID 20220607170239.120084-11-jean-philippe.brucker@arm.com (mailing list archive)
State New, archived
Headers show
Series Virtio v1 support | expand

Commit Message

Jean-Philippe Brucker June 7, 2022, 5:02 p.m. UTC
Existing IOV functions don't take the iovec size as parameter. This is
unfortunate because when parsing buffers split into header and body,
callers may want to know where the body starts in the iovec, after copying
the header. Add a function that does the same as memcpy_fromiovec, but
also allows to iterate over the iovec.

Signed-off-by: Jean-Philippe Brucker <jean-philippe.brucker@arm.com>
---
 include/kvm/iovec.h |  2 ++
 util/iovec.c        | 31 +++++++++++++++++++++++++++++++
 2 files changed, 33 insertions(+)
diff mbox series

Patch

diff --git a/include/kvm/iovec.h b/include/kvm/iovec.h
index fe79dd48..55a03913 100644
--- a/include/kvm/iovec.h
+++ b/include/kvm/iovec.h
@@ -7,6 +7,8 @@  extern int memcpy_fromiovecend(unsigned char *kdata, const struct iovec *iov,
 extern int memcpy_toiovec(struct iovec *v, unsigned char *kdata, int len);
 extern int memcpy_toiovecend(const struct iovec *v, unsigned char *kdata,
 				size_t offset, int len);
+ssize_t memcpy_fromiovec_safe(void *buf, struct iovec **iov, size_t len,
+			      size_t *iovcount);
 
 static inline size_t iov_size(const struct iovec *iovec, size_t len)
 {
diff --git a/util/iovec.c b/util/iovec.c
index 089f1051..c0159011 100644
--- a/util/iovec.c
+++ b/util/iovec.c
@@ -93,6 +93,37 @@  int memcpy_fromiovec(unsigned char *kdata, struct iovec *iov, int len)
 	return 0;
 }
 
+/*
+ *	Copy at most @len bytes from iovec to buffer.
+ *	Returns the remaining len.
+ *
+ *	Note: this modifies the original iovec, the iov pointer, and the
+ *	iovcount to describe the remaining buffer.
+ */
+ssize_t memcpy_fromiovec_safe(void *buf, struct iovec **iov, size_t len,
+			      size_t *iovcount)
+{
+	size_t copy;
+
+	while (len && *iovcount) {
+		copy = min(len, (*iov)->iov_len);
+		memcpy(buf, (*iov)->iov_base, copy);
+		buf += copy;
+		len -= copy;
+
+		/* Move iov cursor */
+		(*iov)->iov_base += copy;
+		(*iov)->iov_len -= copy;
+
+		if (!(*iov)->iov_len) {
+			(*iov)++;
+			(*iovcount)--;
+		}
+	}
+
+	return len;
+}
+
 /*
  *	Copy iovec from kernel. Returns -EFAULT on error.
  */