1*bbecb9d1SAndroid Build Coastguard Worker /*
2*bbecb9d1SAndroid Build Coastguard Worker * this code is taken from Michael - the qemu code is GPLv2 so I don't want
3*bbecb9d1SAndroid Build Coastguard Worker * to reuse it.
4*bbecb9d1SAndroid Build Coastguard Worker * I've adapted it to handle offsets and callback
5*bbecb9d1SAndroid Build Coastguard Worker */
6*bbecb9d1SAndroid Build Coastguard Worker
7*bbecb9d1SAndroid Build Coastguard Worker //
8*bbecb9d1SAndroid Build Coastguard Worker // iovec.c
9*bbecb9d1SAndroid Build Coastguard Worker //
10*bbecb9d1SAndroid Build Coastguard Worker // Scatter/gather utility routines
11*bbecb9d1SAndroid Build Coastguard Worker //
12*bbecb9d1SAndroid Build Coastguard Worker // Copyright (C) 2002 Michael Ringgaard. All rights reserved.
13*bbecb9d1SAndroid Build Coastguard Worker //
14*bbecb9d1SAndroid Build Coastguard Worker // Redistribution and use in source and binary forms, with or without
15*bbecb9d1SAndroid Build Coastguard Worker // modification, are permitted provided that the following conditions
16*bbecb9d1SAndroid Build Coastguard Worker // are met:
17*bbecb9d1SAndroid Build Coastguard Worker //
18*bbecb9d1SAndroid Build Coastguard Worker // 1. Redistributions of source code must retain the above copyright
19*bbecb9d1SAndroid Build Coastguard Worker // notice, this list of conditions and the following disclaimer.
20*bbecb9d1SAndroid Build Coastguard Worker // 2. Redistributions in binary form must reproduce the above copyright
21*bbecb9d1SAndroid Build Coastguard Worker // notice, this list of conditions and the following disclaimer in the
22*bbecb9d1SAndroid Build Coastguard Worker // documentation and/or other materials provided with the distribution.
23*bbecb9d1SAndroid Build Coastguard Worker // 3. Neither the name of the project nor the names of its contributors
24*bbecb9d1SAndroid Build Coastguard Worker // may be used to endorse or promote products derived from this software
25*bbecb9d1SAndroid Build Coastguard Worker // without specific prior written permission.
26*bbecb9d1SAndroid Build Coastguard Worker //
27*bbecb9d1SAndroid Build Coastguard Worker // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
28*bbecb9d1SAndroid Build Coastguard Worker // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29*bbecb9d1SAndroid Build Coastguard Worker // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30*bbecb9d1SAndroid Build Coastguard Worker // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
31*bbecb9d1SAndroid Build Coastguard Worker // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32*bbecb9d1SAndroid Build Coastguard Worker // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33*bbecb9d1SAndroid Build Coastguard Worker // OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34*bbecb9d1SAndroid Build Coastguard Worker // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35*bbecb9d1SAndroid Build Coastguard Worker // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36*bbecb9d1SAndroid Build Coastguard Worker // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
37*bbecb9d1SAndroid Build Coastguard Worker // SUCH DAMAGE.
38*bbecb9d1SAndroid Build Coastguard Worker //
39*bbecb9d1SAndroid Build Coastguard Worker
40*bbecb9d1SAndroid Build Coastguard Worker #include <assert.h>
41*bbecb9d1SAndroid Build Coastguard Worker #include <string.h>
42*bbecb9d1SAndroid Build Coastguard Worker #include <stdlib.h>
43*bbecb9d1SAndroid Build Coastguard Worker #include <stdbool.h>
44*bbecb9d1SAndroid Build Coastguard Worker #include "vrend_iov.h"
45*bbecb9d1SAndroid Build Coastguard Worker
vrend_get_iovec_size(const struct iovec * iov,int iovlen)46*bbecb9d1SAndroid Build Coastguard Worker size_t vrend_get_iovec_size(const struct iovec *iov, int iovlen) {
47*bbecb9d1SAndroid Build Coastguard Worker size_t size = 0;
48*bbecb9d1SAndroid Build Coastguard Worker
49*bbecb9d1SAndroid Build Coastguard Worker while (iovlen > 0) {
50*bbecb9d1SAndroid Build Coastguard Worker size += iov->iov_len;
51*bbecb9d1SAndroid Build Coastguard Worker iov++;
52*bbecb9d1SAndroid Build Coastguard Worker iovlen--;
53*bbecb9d1SAndroid Build Coastguard Worker }
54*bbecb9d1SAndroid Build Coastguard Worker
55*bbecb9d1SAndroid Build Coastguard Worker return size;
56*bbecb9d1SAndroid Build Coastguard Worker }
57*bbecb9d1SAndroid Build Coastguard Worker
vrend_read_from_iovec(const struct iovec * iov,int iovlen,size_t offset,char * buf,size_t count)58*bbecb9d1SAndroid Build Coastguard Worker size_t vrend_read_from_iovec(const struct iovec *iov, int iovlen,
59*bbecb9d1SAndroid Build Coastguard Worker size_t offset,
60*bbecb9d1SAndroid Build Coastguard Worker char *buf, size_t count)
61*bbecb9d1SAndroid Build Coastguard Worker {
62*bbecb9d1SAndroid Build Coastguard Worker size_t read = 0;
63*bbecb9d1SAndroid Build Coastguard Worker size_t len;
64*bbecb9d1SAndroid Build Coastguard Worker
65*bbecb9d1SAndroid Build Coastguard Worker while (count > 0 && iovlen > 0) {
66*bbecb9d1SAndroid Build Coastguard Worker if (iov->iov_len > offset) {
67*bbecb9d1SAndroid Build Coastguard Worker len = iov->iov_len - offset;
68*bbecb9d1SAndroid Build Coastguard Worker
69*bbecb9d1SAndroid Build Coastguard Worker if (count < len) len = count;
70*bbecb9d1SAndroid Build Coastguard Worker
71*bbecb9d1SAndroid Build Coastguard Worker memcpy(buf, (char*)iov->iov_base + offset, len);
72*bbecb9d1SAndroid Build Coastguard Worker read += len;
73*bbecb9d1SAndroid Build Coastguard Worker
74*bbecb9d1SAndroid Build Coastguard Worker buf += len;
75*bbecb9d1SAndroid Build Coastguard Worker count -= len;
76*bbecb9d1SAndroid Build Coastguard Worker offset = 0;
77*bbecb9d1SAndroid Build Coastguard Worker } else {
78*bbecb9d1SAndroid Build Coastguard Worker offset -= iov->iov_len;
79*bbecb9d1SAndroid Build Coastguard Worker }
80*bbecb9d1SAndroid Build Coastguard Worker
81*bbecb9d1SAndroid Build Coastguard Worker iov++;
82*bbecb9d1SAndroid Build Coastguard Worker iovlen--;
83*bbecb9d1SAndroid Build Coastguard Worker }
84*bbecb9d1SAndroid Build Coastguard Worker assert(offset == 0);
85*bbecb9d1SAndroid Build Coastguard Worker return read;
86*bbecb9d1SAndroid Build Coastguard Worker }
87*bbecb9d1SAndroid Build Coastguard Worker
vrend_write_to_iovec(const struct iovec * iov,int iovlen,size_t offset,const char * buf,size_t count)88*bbecb9d1SAndroid Build Coastguard Worker size_t vrend_write_to_iovec(const struct iovec *iov, int iovlen,
89*bbecb9d1SAndroid Build Coastguard Worker size_t offset, const char *buf, size_t count)
90*bbecb9d1SAndroid Build Coastguard Worker {
91*bbecb9d1SAndroid Build Coastguard Worker size_t written = 0;
92*bbecb9d1SAndroid Build Coastguard Worker size_t len;
93*bbecb9d1SAndroid Build Coastguard Worker
94*bbecb9d1SAndroid Build Coastguard Worker while (count > 0 && iovlen > 0) {
95*bbecb9d1SAndroid Build Coastguard Worker if (iov->iov_len > offset) {
96*bbecb9d1SAndroid Build Coastguard Worker len = iov->iov_len - offset;
97*bbecb9d1SAndroid Build Coastguard Worker
98*bbecb9d1SAndroid Build Coastguard Worker if (count < len) len = count;
99*bbecb9d1SAndroid Build Coastguard Worker
100*bbecb9d1SAndroid Build Coastguard Worker memcpy((char*)iov->iov_base + offset, buf, len);
101*bbecb9d1SAndroid Build Coastguard Worker written += len;
102*bbecb9d1SAndroid Build Coastguard Worker
103*bbecb9d1SAndroid Build Coastguard Worker offset = 0;
104*bbecb9d1SAndroid Build Coastguard Worker buf += len;
105*bbecb9d1SAndroid Build Coastguard Worker count -= len;
106*bbecb9d1SAndroid Build Coastguard Worker } else {
107*bbecb9d1SAndroid Build Coastguard Worker offset -= iov->iov_len;
108*bbecb9d1SAndroid Build Coastguard Worker }
109*bbecb9d1SAndroid Build Coastguard Worker iov++;
110*bbecb9d1SAndroid Build Coastguard Worker iovlen--;
111*bbecb9d1SAndroid Build Coastguard Worker }
112*bbecb9d1SAndroid Build Coastguard Worker assert(offset == 0);
113*bbecb9d1SAndroid Build Coastguard Worker return written;
114*bbecb9d1SAndroid Build Coastguard Worker }
115*bbecb9d1SAndroid Build Coastguard Worker
vrend_read_from_iovec_cb(const struct iovec * iov,int iovlen,size_t offset,size_t count,iov_cb iocb,void * cookie)116*bbecb9d1SAndroid Build Coastguard Worker size_t vrend_read_from_iovec_cb(const struct iovec *iov, int iovlen,
117*bbecb9d1SAndroid Build Coastguard Worker size_t offset, size_t count,
118*bbecb9d1SAndroid Build Coastguard Worker iov_cb iocb, void *cookie)
119*bbecb9d1SAndroid Build Coastguard Worker {
120*bbecb9d1SAndroid Build Coastguard Worker size_t read = 0;
121*bbecb9d1SAndroid Build Coastguard Worker size_t len;
122*bbecb9d1SAndroid Build Coastguard Worker
123*bbecb9d1SAndroid Build Coastguard Worker while (count > 0 && iovlen > 0) {
124*bbecb9d1SAndroid Build Coastguard Worker if (iov->iov_len > offset) {
125*bbecb9d1SAndroid Build Coastguard Worker len = iov->iov_len - offset;
126*bbecb9d1SAndroid Build Coastguard Worker
127*bbecb9d1SAndroid Build Coastguard Worker if (count < len) len = count;
128*bbecb9d1SAndroid Build Coastguard Worker
129*bbecb9d1SAndroid Build Coastguard Worker (*iocb)(cookie, read, (char*)iov->iov_base + offset, len);
130*bbecb9d1SAndroid Build Coastguard Worker read += len;
131*bbecb9d1SAndroid Build Coastguard Worker
132*bbecb9d1SAndroid Build Coastguard Worker count -= len;
133*bbecb9d1SAndroid Build Coastguard Worker offset = 0;
134*bbecb9d1SAndroid Build Coastguard Worker } else {
135*bbecb9d1SAndroid Build Coastguard Worker offset -= iov->iov_len;
136*bbecb9d1SAndroid Build Coastguard Worker }
137*bbecb9d1SAndroid Build Coastguard Worker iov++;
138*bbecb9d1SAndroid Build Coastguard Worker iovlen--;
139*bbecb9d1SAndroid Build Coastguard Worker }
140*bbecb9d1SAndroid Build Coastguard Worker assert(offset == 0);
141*bbecb9d1SAndroid Build Coastguard Worker return read;
142*bbecb9d1SAndroid Build Coastguard Worker
143*bbecb9d1SAndroid Build Coastguard Worker
144*bbecb9d1SAndroid Build Coastguard Worker }
145*bbecb9d1SAndroid Build Coastguard Worker
146*bbecb9d1SAndroid Build Coastguard Worker /**
147*bbecb9d1SAndroid Build Coastguard Worker * Copy data from one iovec to another iovec.
148*bbecb9d1SAndroid Build Coastguard Worker *
149*bbecb9d1SAndroid Build Coastguard Worker * TODO: Implement iovec copy without copy to intermediate buffer.
150*bbecb9d1SAndroid Build Coastguard Worker *
151*bbecb9d1SAndroid Build Coastguard Worker * \param src_iov The source iov.
152*bbecb9d1SAndroid Build Coastguard Worker * \param src_iovlen The number of memory regions in the source iov.
153*bbecb9d1SAndroid Build Coastguard Worker * \param src_offset The byte offset in the source iov to start reading from.
154*bbecb9d1SAndroid Build Coastguard Worker * \param dst_iov The destination iov.
155*bbecb9d1SAndroid Build Coastguard Worker * \param dst_iovlen The number of memory regions in the destination iov.
156*bbecb9d1SAndroid Build Coastguard Worker * \param dst_offset The byte offset in the destination iov to start writing to.
157*bbecb9d1SAndroid Build Coastguard Worker * \param count The number of bytes to copy
158*bbecb9d1SAndroid Build Coastguard Worker * \param buf If not NULL, a pointer to a buffer of at least count size
159*bbecb9d1SAndroid Build Coastguard Worker * to use a temporary storage for the copy operation.
160*bbecb9d1SAndroid Build Coastguard Worker * \return -1 on failure, 0 on success
161*bbecb9d1SAndroid Build Coastguard Worker */
vrend_copy_iovec(const struct iovec * src_iov,int src_iovlen,size_t src_offset,const struct iovec * dst_iov,int dst_iovlen,size_t dst_offset,size_t count,char * buf)162*bbecb9d1SAndroid Build Coastguard Worker int vrend_copy_iovec(const struct iovec *src_iov, int src_iovlen, size_t src_offset,
163*bbecb9d1SAndroid Build Coastguard Worker const struct iovec *dst_iov, int dst_iovlen, size_t dst_offset,
164*bbecb9d1SAndroid Build Coastguard Worker size_t count, char *buf)
165*bbecb9d1SAndroid Build Coastguard Worker {
166*bbecb9d1SAndroid Build Coastguard Worker int ret = 0;
167*bbecb9d1SAndroid Build Coastguard Worker bool needs_free;
168*bbecb9d1SAndroid Build Coastguard Worker size_t nread;
169*bbecb9d1SAndroid Build Coastguard Worker size_t nwritten;
170*bbecb9d1SAndroid Build Coastguard Worker
171*bbecb9d1SAndroid Build Coastguard Worker if (src_iov == NULL || dst_iov == NULL)
172*bbecb9d1SAndroid Build Coastguard Worker return -1;
173*bbecb9d1SAndroid Build Coastguard Worker
174*bbecb9d1SAndroid Build Coastguard Worker if (src_iov == dst_iov && src_offset == dst_offset)
175*bbecb9d1SAndroid Build Coastguard Worker return 0;
176*bbecb9d1SAndroid Build Coastguard Worker
177*bbecb9d1SAndroid Build Coastguard Worker if (!buf) {
178*bbecb9d1SAndroid Build Coastguard Worker buf = malloc(count);
179*bbecb9d1SAndroid Build Coastguard Worker needs_free = true;
180*bbecb9d1SAndroid Build Coastguard Worker } else {
181*bbecb9d1SAndroid Build Coastguard Worker needs_free = false;
182*bbecb9d1SAndroid Build Coastguard Worker }
183*bbecb9d1SAndroid Build Coastguard Worker
184*bbecb9d1SAndroid Build Coastguard Worker if (!buf)
185*bbecb9d1SAndroid Build Coastguard Worker return -1;
186*bbecb9d1SAndroid Build Coastguard Worker
187*bbecb9d1SAndroid Build Coastguard Worker nread = vrend_read_from_iovec(src_iov, src_iovlen, src_offset, buf, count);
188*bbecb9d1SAndroid Build Coastguard Worker if (nread != count) {
189*bbecb9d1SAndroid Build Coastguard Worker ret = -1;
190*bbecb9d1SAndroid Build Coastguard Worker goto out;
191*bbecb9d1SAndroid Build Coastguard Worker }
192*bbecb9d1SAndroid Build Coastguard Worker
193*bbecb9d1SAndroid Build Coastguard Worker nwritten = vrend_write_to_iovec(dst_iov, dst_iovlen, dst_offset, buf, count);
194*bbecb9d1SAndroid Build Coastguard Worker if (nwritten != count) {
195*bbecb9d1SAndroid Build Coastguard Worker ret = -1;
196*bbecb9d1SAndroid Build Coastguard Worker goto out;
197*bbecb9d1SAndroid Build Coastguard Worker }
198*bbecb9d1SAndroid Build Coastguard Worker
199*bbecb9d1SAndroid Build Coastguard Worker out:
200*bbecb9d1SAndroid Build Coastguard Worker if (needs_free)
201*bbecb9d1SAndroid Build Coastguard Worker free(buf);
202*bbecb9d1SAndroid Build Coastguard Worker
203*bbecb9d1SAndroid Build Coastguard Worker return ret;
204*bbecb9d1SAndroid Build Coastguard Worker }
205