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@xxxxxxx> --- include/kvm/iovec.h | 2 ++ util/iovec.c | 31 +++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) 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. */ -- 2.36.1