1 // Copyright 2016 The Fuchsia Authors
2 // Copyright (c) 2014 Travis Geiselbrecht
3 //
4 // Use of this source code is governed by a MIT-style
5 // license that can be found in the LICENSE file or at
6 // https://opensource.org/licenses/MIT
7 
8 #include <iovec.h>
9 
10 #include <assert.h>
11 #include <debug.h>
12 #include <err.h>
13 #include <string.h>
14 #include <sys/types.h>
15 
16 #define LOCAL_TRACE 0
17 
18 /*
19  *  Calc total size of iovec buffers
20  */
iovec_size(const iovec_t * iov,uint iov_cnt)21 ssize_t iovec_size(const iovec_t* iov, uint iov_cnt) {
22     if (!iov) {
23         return (ssize_t)ZX_ERR_INVALID_ARGS;
24     }
25 
26     size_t c = 0;
27     for (uint i = 0; i < iov_cnt; i++, iov++) {
28         c += iov->iov_len;
29     }
30     return (ssize_t)c;
31 }
32 
33 /*
34  *  Copy out portion of iovec started from given position
35  *  into single buffer
36  */
iovec_to_membuf(uint8_t * buf,uint buf_len,const iovec_t * iov,uint iov_cnt,uint iov_pos)37 ssize_t iovec_to_membuf(uint8_t* buf, uint buf_len, const iovec_t* iov, uint iov_cnt, uint iov_pos) {
38     uint buf_pos = 0;
39 
40     if (!buf || !iov) {
41         return (ssize_t)ZX_ERR_INVALID_ARGS;
42     }
43 
44     /* for all iovec */
45     for (uint i = 0; i < iov_cnt; i++, iov++) {
46 
47         if (iov_pos >= iov->iov_len) {
48             iov_pos -= iov->iov_len; /* skip whole chunks */
49             continue;
50         }
51 
52         /* calc number of bytes left in current iov */
53         size_t to_copy = (size_t)(iov->iov_len - iov_pos);
54 
55         /* limit it to number of bytes left in buffer */
56         if (to_copy > buf_len) {
57             to_copy = buf_len;
58         }
59 
60         /* copy data out */
61         memcpy(buf + buf_pos, (uint8_t*)iov->iov_base + iov_pos, to_copy);
62 
63         /* advance in buffer position */
64         buf_pos += to_copy;
65         buf_len -= to_copy;
66 
67         /* check if we need to copy more data */
68         if (buf_len == 0) {
69             break;
70         }
71 
72         iov_pos = 0; /* it is only possible to have fully copied iovec here */
73     }
74 
75     return (ssize_t)buf_pos;
76 }
77