root / fsdev / virtio-9p-marshal.c @ cb9c377f
History | View | Annotate | Download (9.9 kB)
1 |
/*
|
---|---|
2 |
* Virtio 9p backend
|
3 |
*
|
4 |
* Copyright IBM, Corp. 2010
|
5 |
*
|
6 |
* Authors:
|
7 |
* Anthony Liguori <aliguori@us.ibm.com>
|
8 |
*
|
9 |
* This work is licensed under the terms of the GNU GPL, version 2. See
|
10 |
* the COPYING file in the top-level directory.
|
11 |
*
|
12 |
*/
|
13 |
|
14 |
#include <glib.h> |
15 |
#include <glib/gprintf.h> |
16 |
#include <sys/types.h> |
17 |
#include <dirent.h> |
18 |
#include <sys/time.h> |
19 |
#include <utime.h> |
20 |
#include <sys/uio.h> |
21 |
#include <string.h> |
22 |
#include <stdint.h> |
23 |
#include <errno.h> |
24 |
|
25 |
#include "compiler.h" |
26 |
#include "virtio-9p-marshal.h" |
27 |
#include "bswap.h" |
28 |
|
29 |
void v9fs_string_free(V9fsString *str)
|
30 |
{ |
31 |
g_free(str->data); |
32 |
str->data = NULL;
|
33 |
str->size = 0;
|
34 |
} |
35 |
|
36 |
void v9fs_string_null(V9fsString *str)
|
37 |
{ |
38 |
v9fs_string_free(str); |
39 |
} |
40 |
|
41 |
void GCC_FMT_ATTR(2, 3) |
42 |
v9fs_string_sprintf(V9fsString *str, const char *fmt, ...) |
43 |
{ |
44 |
va_list ap; |
45 |
|
46 |
v9fs_string_free(str); |
47 |
|
48 |
va_start(ap, fmt); |
49 |
str->size = g_vasprintf(&str->data, fmt, ap); |
50 |
va_end(ap); |
51 |
} |
52 |
|
53 |
void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs)
|
54 |
{ |
55 |
v9fs_string_free(lhs); |
56 |
v9fs_string_sprintf(lhs, "%s", rhs->data);
|
57 |
} |
58 |
|
59 |
|
60 |
static ssize_t v9fs_packunpack(void *addr, struct iovec *sg, int sg_count, |
61 |
size_t offset, size_t size, int pack)
|
62 |
{ |
63 |
int i = 0; |
64 |
size_t copied = 0;
|
65 |
size_t req_size = size; |
66 |
|
67 |
|
68 |
for (i = 0; size && i < sg_count; i++) { |
69 |
size_t len; |
70 |
if (offset >= sg[i].iov_len) {
|
71 |
/* skip this sg */
|
72 |
offset -= sg[i].iov_len; |
73 |
continue;
|
74 |
} else {
|
75 |
len = MIN(sg[i].iov_len - offset, size); |
76 |
if (pack) {
|
77 |
memcpy(sg[i].iov_base + offset, addr, len); |
78 |
} else {
|
79 |
memcpy(addr, sg[i].iov_base + offset, len); |
80 |
} |
81 |
size -= len; |
82 |
copied += len; |
83 |
addr += len; |
84 |
if (size) {
|
85 |
offset = 0;
|
86 |
continue;
|
87 |
} |
88 |
} |
89 |
} |
90 |
if (copied < req_size) {
|
91 |
/*
|
92 |
* We copied less that requested size. error out
|
93 |
*/
|
94 |
return -ENOBUFS;
|
95 |
} |
96 |
return copied;
|
97 |
} |
98 |
|
99 |
static ssize_t v9fs_unpack(void *dst, struct iovec *out_sg, int out_num, |
100 |
size_t offset, size_t size) |
101 |
{ |
102 |
return v9fs_packunpack(dst, out_sg, out_num, offset, size, 0); |
103 |
} |
104 |
|
105 |
ssize_t v9fs_pack(struct iovec *in_sg, int in_num, size_t offset, |
106 |
const void *src, size_t size) |
107 |
{ |
108 |
return v9fs_packunpack((void *)src, in_sg, in_num, offset, size, 1); |
109 |
} |
110 |
|
111 |
ssize_t v9fs_unmarshal(struct iovec *out_sg, int out_num, size_t offset, |
112 |
int bswap, const char *fmt, ...) |
113 |
{ |
114 |
int i;
|
115 |
va_list ap; |
116 |
ssize_t copied = 0;
|
117 |
size_t old_offset = offset; |
118 |
|
119 |
va_start(ap, fmt); |
120 |
for (i = 0; fmt[i]; i++) { |
121 |
switch (fmt[i]) {
|
122 |
case 'b': { |
123 |
uint8_t *valp = va_arg(ap, uint8_t *); |
124 |
copied = v9fs_unpack(valp, out_sg, out_num, offset, sizeof(*valp));
|
125 |
break;
|
126 |
} |
127 |
case 'w': { |
128 |
uint16_t val, *valp; |
129 |
valp = va_arg(ap, uint16_t *); |
130 |
copied = v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val));
|
131 |
if (bswap) {
|
132 |
*valp = le16_to_cpu(val); |
133 |
} else {
|
134 |
*valp = val; |
135 |
} |
136 |
break;
|
137 |
} |
138 |
case 'd': { |
139 |
uint32_t val, *valp; |
140 |
valp = va_arg(ap, uint32_t *); |
141 |
copied = v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val));
|
142 |
if (bswap) {
|
143 |
*valp = le32_to_cpu(val); |
144 |
} else {
|
145 |
*valp = val; |
146 |
} |
147 |
break;
|
148 |
} |
149 |
case 'q': { |
150 |
uint64_t val, *valp; |
151 |
valp = va_arg(ap, uint64_t *); |
152 |
copied = v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val));
|
153 |
if (bswap) {
|
154 |
*valp = le64_to_cpu(val); |
155 |
} else {
|
156 |
*valp = val; |
157 |
} |
158 |
break;
|
159 |
} |
160 |
case 's': { |
161 |
V9fsString *str = va_arg(ap, V9fsString *); |
162 |
copied = v9fs_unmarshal(out_sg, out_num, offset, bswap, |
163 |
"w", &str->size);
|
164 |
if (copied > 0) { |
165 |
offset += copied; |
166 |
str->data = g_malloc(str->size + 1);
|
167 |
copied = v9fs_unpack(str->data, out_sg, out_num, offset, |
168 |
str->size); |
169 |
if (copied > 0) { |
170 |
str->data[str->size] = 0;
|
171 |
} else {
|
172 |
v9fs_string_free(str); |
173 |
} |
174 |
} |
175 |
break;
|
176 |
} |
177 |
case 'Q': { |
178 |
V9fsQID *qidp = va_arg(ap, V9fsQID *); |
179 |
copied = v9fs_unmarshal(out_sg, out_num, offset, bswap, "bdq",
|
180 |
&qidp->type, &qidp->version, &qidp->path); |
181 |
break;
|
182 |
} |
183 |
case 'S': { |
184 |
V9fsStat *statp = va_arg(ap, V9fsStat *); |
185 |
copied = v9fs_unmarshal(out_sg, out_num, offset, bswap, |
186 |
"wwdQdddqsssssddd",
|
187 |
&statp->size, &statp->type, &statp->dev, |
188 |
&statp->qid, &statp->mode, &statp->atime, |
189 |
&statp->mtime, &statp->length, |
190 |
&statp->name, &statp->uid, &statp->gid, |
191 |
&statp->muid, &statp->extension, |
192 |
&statp->n_uid, &statp->n_gid, |
193 |
&statp->n_muid); |
194 |
break;
|
195 |
} |
196 |
case 'I': { |
197 |
V9fsIattr *iattr = va_arg(ap, V9fsIattr *); |
198 |
copied = v9fs_unmarshal(out_sg, out_num, offset, bswap, |
199 |
"ddddqqqqq",
|
200 |
&iattr->valid, &iattr->mode, |
201 |
&iattr->uid, &iattr->gid, &iattr->size, |
202 |
&iattr->atime_sec, &iattr->atime_nsec, |
203 |
&iattr->mtime_sec, &iattr->mtime_nsec); |
204 |
break;
|
205 |
} |
206 |
default:
|
207 |
break;
|
208 |
} |
209 |
if (copied < 0) { |
210 |
va_end(ap); |
211 |
return copied;
|
212 |
} |
213 |
offset += copied; |
214 |
} |
215 |
va_end(ap); |
216 |
|
217 |
return offset - old_offset;
|
218 |
} |
219 |
|
220 |
ssize_t v9fs_marshal(struct iovec *in_sg, int in_num, size_t offset, |
221 |
int bswap, const char *fmt, ...) |
222 |
{ |
223 |
int i;
|
224 |
va_list ap; |
225 |
ssize_t copied = 0;
|
226 |
size_t old_offset = offset; |
227 |
|
228 |
va_start(ap, fmt); |
229 |
for (i = 0; fmt[i]; i++) { |
230 |
switch (fmt[i]) {
|
231 |
case 'b': { |
232 |
uint8_t val = va_arg(ap, int);
|
233 |
copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
|
234 |
break;
|
235 |
} |
236 |
case 'w': { |
237 |
uint16_t val; |
238 |
if (bswap) {
|
239 |
cpu_to_le16w(&val, va_arg(ap, int));
|
240 |
} else {
|
241 |
val = va_arg(ap, int);
|
242 |
} |
243 |
copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
|
244 |
break;
|
245 |
} |
246 |
case 'd': { |
247 |
uint32_t val; |
248 |
if (bswap) {
|
249 |
cpu_to_le32w(&val, va_arg(ap, uint32_t)); |
250 |
} else {
|
251 |
val = va_arg(ap, uint32_t); |
252 |
} |
253 |
copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
|
254 |
break;
|
255 |
} |
256 |
case 'q': { |
257 |
uint64_t val; |
258 |
if (bswap) {
|
259 |
cpu_to_le64w(&val, va_arg(ap, uint64_t)); |
260 |
} else {
|
261 |
val = va_arg(ap, uint64_t); |
262 |
} |
263 |
copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
|
264 |
break;
|
265 |
} |
266 |
case 's': { |
267 |
V9fsString *str = va_arg(ap, V9fsString *); |
268 |
copied = v9fs_marshal(in_sg, in_num, offset, bswap, |
269 |
"w", str->size);
|
270 |
if (copied > 0) { |
271 |
offset += copied; |
272 |
copied = v9fs_pack(in_sg, in_num, offset, str->data, str->size); |
273 |
} |
274 |
break;
|
275 |
} |
276 |
case 'Q': { |
277 |
V9fsQID *qidp = va_arg(ap, V9fsQID *); |
278 |
copied = v9fs_marshal(in_sg, in_num, offset, bswap, "bdq",
|
279 |
qidp->type, qidp->version, qidp->path); |
280 |
break;
|
281 |
} |
282 |
case 'S': { |
283 |
V9fsStat *statp = va_arg(ap, V9fsStat *); |
284 |
copied = v9fs_marshal(in_sg, in_num, offset, bswap, |
285 |
"wwdQdddqsssssddd",
|
286 |
statp->size, statp->type, statp->dev, |
287 |
&statp->qid, statp->mode, statp->atime, |
288 |
statp->mtime, statp->length, &statp->name, |
289 |
&statp->uid, &statp->gid, &statp->muid, |
290 |
&statp->extension, statp->n_uid, |
291 |
statp->n_gid, statp->n_muid); |
292 |
break;
|
293 |
} |
294 |
case 'A': { |
295 |
V9fsStatDotl *statp = va_arg(ap, V9fsStatDotl *); |
296 |
copied = v9fs_marshal(in_sg, in_num, offset, bswap, |
297 |
"qQdddqqqqqqqqqqqqqqq",
|
298 |
statp->st_result_mask, |
299 |
&statp->qid, statp->st_mode, |
300 |
statp->st_uid, statp->st_gid, |
301 |
statp->st_nlink, statp->st_rdev, |
302 |
statp->st_size, statp->st_blksize, |
303 |
statp->st_blocks, statp->st_atime_sec, |
304 |
statp->st_atime_nsec, statp->st_mtime_sec, |
305 |
statp->st_mtime_nsec, statp->st_ctime_sec, |
306 |
statp->st_ctime_nsec, statp->st_btime_sec, |
307 |
statp->st_btime_nsec, statp->st_gen, |
308 |
statp->st_data_version); |
309 |
break;
|
310 |
} |
311 |
default:
|
312 |
break;
|
313 |
} |
314 |
if (copied < 0) { |
315 |
va_end(ap); |
316 |
return copied;
|
317 |
} |
318 |
offset += copied; |
319 |
} |
320 |
va_end(ap); |
321 |
|
322 |
return offset - old_offset;
|
323 |
} |