]> git.proxmox.com Git - mirror_qemu.git/blame - fsdev/virtio-9p-marshal.c
hw/9pfs: Move pdu_marshal/unmarshal code to a seperate file
[mirror_qemu.git] / fsdev / virtio-9p-marshal.c
CommitLineData
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>
23
24#include "compiler.h"
25#include "virtio-9p-marshal.h"
26#include "bswap.h"
27
28void v9fs_string_init(V9fsString *str)
29{
30 str->data = NULL;
31 str->size = 0;
32}
33
34void v9fs_string_free(V9fsString *str)
35{
36 g_free(str->data);
37 str->data = NULL;
38 str->size = 0;
39}
40
41void v9fs_string_null(V9fsString *str)
42{
43 v9fs_string_free(str);
44}
45
46void GCC_FMT_ATTR(2, 3)
47v9fs_string_sprintf(V9fsString *str, const char *fmt, ...)
48{
49 va_list ap;
50
51 v9fs_string_free(str);
52
53 va_start(ap, fmt);
54 str->size = g_vasprintf(&str->data, fmt, ap);
55 va_end(ap);
56}
57
58void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs)
59{
60 v9fs_string_free(lhs);
61 v9fs_string_sprintf(lhs, "%s", rhs->data);
62}
63
64
65static size_t v9fs_packunpack(void *addr, struct iovec *sg, int sg_count,
66 size_t offset, size_t size, int pack)
67{
68 int i = 0;
69 size_t copied = 0;
70
71 for (i = 0; size && i < sg_count; i++) {
72 size_t len;
73 if (offset >= sg[i].iov_len) {
74 /* skip this sg */
75 offset -= sg[i].iov_len;
76 continue;
77 } else {
78 len = MIN(sg[i].iov_len - offset, size);
79 if (pack) {
80 memcpy(sg[i].iov_base + offset, addr, len);
81 } else {
82 memcpy(addr, sg[i].iov_base + offset, len);
83 }
84 size -= len;
85 copied += len;
86 addr += len;
87 if (size) {
88 offset = 0;
89 continue;
90 }
91 }
92 }
93
94 return copied;
95}
96
97static size_t v9fs_unpack(void *dst, struct iovec *out_sg, int out_num,
98 size_t offset, size_t size)
99{
100 return v9fs_packunpack(dst, out_sg, out_num, offset, size, 0);
101}
102
103size_t v9fs_pack(struct iovec *in_sg, int in_num, size_t offset,
104 const void *src, size_t size)
105{
106 return v9fs_packunpack((void *)src, in_sg, in_num, offset, size, 1);
107}
108
109size_t v9fs_unmarshal(struct iovec *out_sg, int out_num, size_t offset,
110 int bswap, const char *fmt, ...)
111{
112 int i;
113 va_list ap;
114 size_t old_offset = offset;
115
116 va_start(ap, fmt);
117 for (i = 0; fmt[i]; i++) {
118 switch (fmt[i]) {
119 case 'b': {
120 uint8_t *valp = va_arg(ap, uint8_t *);
121 offset += v9fs_unpack(valp, out_sg, out_num, offset, sizeof(*valp));
122 break;
123 }
124 case 'w': {
125 uint16_t val, *valp;
126 valp = va_arg(ap, uint16_t *);
127 offset += v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val));
128 if (bswap) {
129 *valp = le16_to_cpu(val);
130 } else {
131 *valp = val;
132 }
133 break;
134 }
135 case 'd': {
136 uint32_t val, *valp;
137 valp = va_arg(ap, uint32_t *);
138 offset += v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val));
139 if (bswap) {
140 *valp = le32_to_cpu(val);
141 } else {
142 *valp = val;
143 }
144 break;
145 }
146 case 'q': {
147 uint64_t val, *valp;
148 valp = va_arg(ap, uint64_t *);
149 offset += v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val));
150 if (bswap) {
151 *valp = le64_to_cpu(val);
152 } else {
153 *valp = val;
154 }
155 break;
156 }
157 case 's': {
158 V9fsString *str = va_arg(ap, V9fsString *);
159 offset += v9fs_unmarshal(out_sg, out_num, offset, bswap,
160 "w", &str->size);
161 /* FIXME: sanity check str->size */
162 str->data = g_malloc(str->size + 1);
163 offset += v9fs_unpack(str->data, out_sg, out_num, offset,
164 str->size);
165 str->data[str->size] = 0;
166 break;
167 }
168 case 'Q': {
169 V9fsQID *qidp = va_arg(ap, V9fsQID *);
170 offset += v9fs_unmarshal(out_sg, out_num, offset, bswap, "bdq",
171 &qidp->type, &qidp->version, &qidp->path);
172 break;
173 }
174 case 'S': {
175 V9fsStat *statp = va_arg(ap, V9fsStat *);
176 offset += v9fs_unmarshal(out_sg, out_num, offset, bswap,
177 "wwdQdddqsssssddd",
178 &statp->size, &statp->type, &statp->dev,
179 &statp->qid, &statp->mode, &statp->atime,
180 &statp->mtime, &statp->length,
181 &statp->name, &statp->uid, &statp->gid,
182 &statp->muid, &statp->extension,
183 &statp->n_uid, &statp->n_gid,
184 &statp->n_muid);
185 break;
186 }
187 case 'I': {
188 V9fsIattr *iattr = va_arg(ap, V9fsIattr *);
189 offset += v9fs_unmarshal(out_sg, out_num, offset, bswap,
190 "ddddqqqqq",
191 &iattr->valid, &iattr->mode,
192 &iattr->uid, &iattr->gid, &iattr->size,
193 &iattr->atime_sec, &iattr->atime_nsec,
194 &iattr->mtime_sec, &iattr->mtime_nsec);
195 break;
196 }
197 default:
198 break;
199 }
200 }
201
202 va_end(ap);
203
204 return offset - old_offset;
205}
206
207size_t v9fs_marshal(struct iovec *in_sg, int in_num, size_t offset,
208 int bswap, const char *fmt, ...)
209{
210 int i;
211 va_list ap;
212 size_t old_offset = offset;
213
214 va_start(ap, fmt);
215 for (i = 0; fmt[i]; i++) {
216 switch (fmt[i]) {
217 case 'b': {
218 uint8_t val = va_arg(ap, int);
219 offset += v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
220 break;
221 }
222 case 'w': {
223 uint16_t val;
224 if (bswap) {
225 cpu_to_le16w(&val, va_arg(ap, int));
226 } else {
227 val = va_arg(ap, int);
228 }
229 offset += v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
230 break;
231 }
232 case 'd': {
233 uint32_t val;
234 if (bswap) {
235 cpu_to_le32w(&val, va_arg(ap, uint32_t));
236 } else {
237 val = va_arg(ap, uint32_t);
238 }
239 offset += v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
240 break;
241 }
242 case 'q': {
243 uint64_t val;
244 if (bswap) {
245 cpu_to_le64w(&val, va_arg(ap, uint64_t));
246 } else {
247 val = va_arg(ap, uint64_t);
248 }
249 offset += v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
250 break;
251 }
252 case 's': {
253 V9fsString *str = va_arg(ap, V9fsString *);
254 offset += v9fs_marshal(in_sg, in_num, offset, bswap,
255 "w", str->size);
256 offset += v9fs_pack(in_sg, in_num, offset, str->data, str->size);
257 break;
258 }
259 case 'Q': {
260 V9fsQID *qidp = va_arg(ap, V9fsQID *);
261 offset += v9fs_marshal(in_sg, in_num, offset, bswap, "bdq",
262 qidp->type, qidp->version, qidp->path);
263 break;
264 }
265 case 'S': {
266 V9fsStat *statp = va_arg(ap, V9fsStat *);
267 offset += v9fs_marshal(in_sg, in_num, offset, bswap,
268 "wwdQdddqsssssddd",
269 statp->size, statp->type, statp->dev,
270 &statp->qid, statp->mode, statp->atime,
271 statp->mtime, statp->length, &statp->name,
272 &statp->uid, &statp->gid, &statp->muid,
273 &statp->extension, statp->n_uid,
274 statp->n_gid, statp->n_muid);
275 break;
276 }
277 case 'A': {
278 V9fsStatDotl *statp = va_arg(ap, V9fsStatDotl *);
279 offset += v9fs_marshal(in_sg, in_num, offset, bswap,
280 "qQdddqqqqqqqqqqqqqqq",
281 statp->st_result_mask,
282 &statp->qid, statp->st_mode,
283 statp->st_uid, statp->st_gid,
284 statp->st_nlink, statp->st_rdev,
285 statp->st_size, statp->st_blksize,
286 statp->st_blocks, statp->st_atime_sec,
287 statp->st_atime_nsec, statp->st_mtime_sec,
288 statp->st_mtime_nsec, statp->st_ctime_sec,
289 statp->st_ctime_nsec, statp->st_btime_sec,
290 statp->st_btime_nsec, statp->st_gen,
291 statp->st_data_version);
292 break;
293 }
294 default:
295 break;
296 }
297 }
298 va_end(ap);
299
300 return offset - old_offset;
301}