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