]>
Commit | Line | Data |
---|---|---|
10925bf0 MK |
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> | |
ddca7f86 | 23 | #include <errno.h> |
10925bf0 | 24 | |
1de7afc9 | 25 | #include "qemu/compiler.h" |
10925bf0 | 26 | #include "virtio-9p-marshal.h" |
1de7afc9 | 27 | #include "qemu/bswap.h" |
10925bf0 | 28 | |
10925bf0 MK |
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 | ||
ddca7f86 MK |
60 | static ssize_t v9fs_packunpack(void *addr, struct iovec *sg, int sg_count, |
61 | size_t offset, size_t size, int pack) | |
10925bf0 MK |
62 | { |
63 | int i = 0; | |
64 | size_t copied = 0; | |
ddca7f86 MK |
65 | size_t req_size = size; |
66 | ||
10925bf0 MK |
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 | } | |
ddca7f86 MK |
90 | if (copied < req_size) { |
91 | /* | |
92 | * We copied less that requested size. error out | |
93 | */ | |
94 | return -ENOBUFS; | |
95 | } | |
10925bf0 MK |
96 | return copied; |
97 | } | |
98 | ||
ddca7f86 MK |
99 | static ssize_t v9fs_unpack(void *dst, struct iovec *out_sg, int out_num, |
100 | size_t offset, size_t size) | |
10925bf0 MK |
101 | { |
102 | return v9fs_packunpack(dst, out_sg, out_num, offset, size, 0); | |
103 | } | |
104 | ||
ddca7f86 MK |
105 | ssize_t v9fs_pack(struct iovec *in_sg, int in_num, size_t offset, |
106 | const void *src, size_t size) | |
10925bf0 MK |
107 | { |
108 | return v9fs_packunpack((void *)src, in_sg, in_num, offset, size, 1); | |
109 | } | |
110 | ||
ddca7f86 MK |
111 | ssize_t v9fs_unmarshal(struct iovec *out_sg, int out_num, size_t offset, |
112 | int bswap, const char *fmt, ...) | |
10925bf0 MK |
113 | { |
114 | int i; | |
115 | va_list ap; | |
ddca7f86 | 116 | ssize_t copied = 0; |
10925bf0 MK |
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 *); | |
ddca7f86 | 124 | copied = v9fs_unpack(valp, out_sg, out_num, offset, sizeof(*valp)); |
10925bf0 MK |
125 | break; |
126 | } | |
127 | case 'w': { | |
128 | uint16_t val, *valp; | |
129 | valp = va_arg(ap, uint16_t *); | |
ddca7f86 | 130 | copied = v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val)); |
10925bf0 MK |
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 *); | |
ddca7f86 | 141 | copied = v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val)); |
10925bf0 MK |
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 *); | |
ddca7f86 | 152 | copied = v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val)); |
10925bf0 MK |
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 *); | |
ddca7f86 MK |
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 | } | |
10925bf0 MK |
175 | break; |
176 | } | |
177 | case 'Q': { | |
178 | V9fsQID *qidp = va_arg(ap, V9fsQID *); | |
ddca7f86 MK |
179 | copied = v9fs_unmarshal(out_sg, out_num, offset, bswap, "bdq", |
180 | &qidp->type, &qidp->version, &qidp->path); | |
10925bf0 MK |
181 | break; |
182 | } | |
183 | case 'S': { | |
184 | V9fsStat *statp = va_arg(ap, V9fsStat *); | |
ddca7f86 | 185 | copied = v9fs_unmarshal(out_sg, out_num, offset, bswap, |
10925bf0 | 186 | "wwdQdddqsssssddd", |
ddca7f86 MK |
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); | |
10925bf0 MK |
194 | break; |
195 | } | |
196 | case 'I': { | |
197 | V9fsIattr *iattr = va_arg(ap, V9fsIattr *); | |
ddca7f86 MK |
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); | |
10925bf0 MK |
204 | break; |
205 | } | |
206 | default: | |
207 | break; | |
208 | } | |
ddca7f86 MK |
209 | if (copied < 0) { |
210 | va_end(ap); | |
211 | return copied; | |
212 | } | |
213 | offset += copied; | |
10925bf0 | 214 | } |
10925bf0 MK |
215 | va_end(ap); |
216 | ||
217 | return offset - old_offset; | |
218 | } | |
219 | ||
ddca7f86 MK |
220 | ssize_t v9fs_marshal(struct iovec *in_sg, int in_num, size_t offset, |
221 | int bswap, const char *fmt, ...) | |
10925bf0 MK |
222 | { |
223 | int i; | |
224 | va_list ap; | |
ddca7f86 | 225 | ssize_t copied = 0; |
10925bf0 MK |
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); | |
ddca7f86 | 233 | copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val)); |
10925bf0 MK |
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 | } | |
ddca7f86 | 243 | copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val)); |
10925bf0 MK |
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 | } | |
ddca7f86 | 253 | copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val)); |
10925bf0 MK |
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 | } | |
ddca7f86 | 263 | copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val)); |
10925bf0 MK |
264 | break; |
265 | } | |
266 | case 's': { | |
267 | V9fsString *str = va_arg(ap, V9fsString *); | |
ddca7f86 MK |
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 | } | |
10925bf0 MK |
274 | break; |
275 | } | |
276 | case 'Q': { | |
277 | V9fsQID *qidp = va_arg(ap, V9fsQID *); | |
ddca7f86 MK |
278 | copied = v9fs_marshal(in_sg, in_num, offset, bswap, "bdq", |
279 | qidp->type, qidp->version, qidp->path); | |
10925bf0 MK |
280 | break; |
281 | } | |
282 | case 'S': { | |
283 | V9fsStat *statp = va_arg(ap, V9fsStat *); | |
ddca7f86 MK |
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); | |
10925bf0 MK |
292 | break; |
293 | } | |
294 | case 'A': { | |
295 | V9fsStatDotl *statp = va_arg(ap, V9fsStatDotl *); | |
ddca7f86 | 296 | copied = v9fs_marshal(in_sg, in_num, offset, bswap, |
10925bf0 MK |
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 | } | |
ddca7f86 MK |
314 | if (copied < 0) { |
315 | va_end(ap); | |
316 | return copied; | |
317 | } | |
318 | offset += copied; | |
10925bf0 MK |
319 | } |
320 | va_end(ap); | |
321 | ||
322 | return offset - old_offset; | |
323 | } |