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