Merge tag 'pull-loongarch-20241016' of https://gitlab.com/gaosong/qemu into staging
[qemu/armbru.git] / fsdev / 9p-iov-marshal.c
blob0c5a1a0fa216ecbb83dd890b1edec14f702c0715
1 /*
2 * 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 "qemu/osdep.h"
15 #include <glib/gprintf.h>
16 #include <utime.h>
18 #include "9p-iov-marshal.h"
19 #include "qemu/bswap.h"
21 static ssize_t v9fs_packunpack(void *addr, struct iovec *sg, int sg_count,
22 size_t offset, size_t size, int pack)
24 int i = 0;
25 size_t copied = 0;
26 size_t req_size = size;
29 for (i = 0; size && i < sg_count; i++) {
30 size_t len;
31 if (offset >= sg[i].iov_len) {
32 /* skip this sg */
33 offset -= sg[i].iov_len;
34 continue;
35 } else {
36 len = MIN(sg[i].iov_len - offset, size);
37 if (pack) {
38 memcpy(sg[i].iov_base + offset, addr, len);
39 } else {
40 memcpy(addr, sg[i].iov_base + offset, len);
42 size -= len;
43 copied += len;
44 addr += len;
45 if (size) {
46 offset = 0;
47 continue;
51 if (copied < req_size) {
53 * We copied less that requested size. error out
55 return -ENOBUFS;
57 return copied;
60 static ssize_t v9fs_unpack(void *dst, struct iovec *out_sg, int out_num,
61 size_t offset, size_t size)
63 return v9fs_packunpack(dst, out_sg, out_num, offset, size, 0);
66 ssize_t v9fs_pack(struct iovec *in_sg, int in_num, size_t offset,
67 const void *src, size_t size)
69 return v9fs_packunpack((void *)src, in_sg, in_num, offset, size, 1);
72 ssize_t v9fs_iov_vunmarshal(struct iovec *out_sg, int out_num, size_t offset,
73 int bswap, const char *fmt, va_list ap)
75 int i;
76 ssize_t copied = 0;
77 size_t old_offset = offset;
79 for (i = 0; fmt[i]; i++) {
80 switch (fmt[i]) {
81 case 'b': {
82 uint8_t *valp = va_arg(ap, uint8_t *);
83 copied = v9fs_unpack(valp, out_sg, out_num, offset, sizeof(*valp));
84 break;
86 case 'w': {
87 uint16_t val = 0, *valp;
88 valp = va_arg(ap, uint16_t *);
89 copied = v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val));
90 if (copied <= 0) {
91 break;
93 if (bswap) {
94 *valp = le16_to_cpu(val);
95 } else {
96 *valp = val;
98 break;
100 case 'd': {
101 uint32_t val = 0, *valp;
102 valp = va_arg(ap, uint32_t *);
103 copied = v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val));
104 if (copied <= 0) {
105 break;
107 if (bswap) {
108 *valp = le32_to_cpu(val);
109 } else {
110 *valp = val;
112 break;
114 case 'q': {
115 uint64_t val = 0, *valp;
116 valp = va_arg(ap, uint64_t *);
117 copied = v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val));
118 if (copied <= 0) {
119 break;
121 if (bswap) {
122 *valp = le64_to_cpu(val);
123 } else {
124 *valp = val;
126 break;
128 case 's': {
129 V9fsString *str = va_arg(ap, V9fsString *);
130 copied = v9fs_iov_unmarshal(out_sg, out_num, offset, bswap,
131 "w", &str->size);
132 if (copied > 0) {
133 offset += copied;
134 str->data = g_malloc(str->size + 1);
135 copied = v9fs_unpack(str->data, out_sg, out_num, offset,
136 str->size);
137 if (copied >= 0) {
138 str->data[str->size] = 0;
139 } else {
140 v9fs_string_free(str);
143 break;
145 case 'Q': {
146 V9fsQID *qidp = va_arg(ap, V9fsQID *);
147 copied = v9fs_iov_unmarshal(out_sg, out_num, offset, bswap,
148 "bdq", &qidp->type, &qidp->version,
149 &qidp->path);
150 break;
152 case 'S': {
153 V9fsStat *statp = va_arg(ap, V9fsStat *);
154 copied = v9fs_iov_unmarshal(out_sg, out_num, offset, bswap,
155 "wwdQdddqsssssddd",
156 &statp->size, &statp->type,
157 &statp->dev, &statp->qid,
158 &statp->mode, &statp->atime,
159 &statp->mtime, &statp->length,
160 &statp->name, &statp->uid,
161 &statp->gid, &statp->muid,
162 &statp->extension,
163 &statp->n_uid, &statp->n_gid,
164 &statp->n_muid);
165 break;
167 case 'I': {
168 V9fsIattr *iattr = va_arg(ap, V9fsIattr *);
169 copied = v9fs_iov_unmarshal(out_sg, out_num, offset, bswap,
170 "ddddqqqqq",
171 &iattr->valid, &iattr->mode,
172 &iattr->uid, &iattr->gid,
173 &iattr->size, &iattr->atime_sec,
174 &iattr->atime_nsec,
175 &iattr->mtime_sec,
176 &iattr->mtime_nsec);
177 break;
179 default:
180 g_assert_not_reached();
182 if (copied < 0) {
183 return copied;
185 offset += copied;
188 return offset - old_offset;
191 ssize_t v9fs_iov_unmarshal(struct iovec *out_sg, int out_num, size_t offset,
192 int bswap, const char *fmt, ...)
194 ssize_t ret;
195 va_list ap;
197 va_start(ap, fmt);
198 ret = v9fs_iov_vunmarshal(out_sg, out_num, offset, bswap, fmt, ap);
199 va_end(ap);
201 return ret;
204 ssize_t v9fs_iov_vmarshal(struct iovec *in_sg, int in_num, size_t offset,
205 int bswap, const char *fmt, va_list ap)
207 int i;
208 ssize_t copied = 0;
209 size_t old_offset = offset;
211 for (i = 0; fmt[i]; i++) {
212 switch (fmt[i]) {
213 case 'b': {
214 uint8_t val = va_arg(ap, int);
215 copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
216 break;
218 case 'w': {
219 uint16_t val = va_arg(ap, int);
220 if (bswap) {
221 val = cpu_to_le16(val);
223 copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
224 break;
226 case 'd': {
227 uint32_t val = va_arg(ap, uint32_t);
228 if (bswap) {
229 val = cpu_to_le32(val);
231 copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
232 break;
234 case 'q': {
235 uint64_t val = va_arg(ap, uint64_t);
236 if (bswap) {
237 val = cpu_to_le64(val);
239 copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
240 break;
242 case 's': {
243 V9fsString *str = va_arg(ap, V9fsString *);
244 copied = v9fs_iov_marshal(in_sg, in_num, offset, bswap,
245 "w", str->size);
246 if (copied > 0) {
247 offset += copied;
248 copied = v9fs_pack(in_sg, in_num, offset, str->data, str->size);
250 break;
252 case 'Q': {
253 V9fsQID *qidp = va_arg(ap, V9fsQID *);
254 copied = v9fs_iov_marshal(in_sg, in_num, offset, bswap, "bdq",
255 qidp->type, qidp->version,
256 qidp->path);
257 break;
259 case 'S': {
260 V9fsStat *statp = va_arg(ap, V9fsStat *);
261 copied = v9fs_iov_marshal(in_sg, in_num, offset, bswap,
262 "wwdQdddqsssssddd",
263 statp->size, statp->type, statp->dev,
264 &statp->qid, statp->mode, statp->atime,
265 statp->mtime, statp->length,
266 &statp->name,
267 &statp->uid, &statp->gid, &statp->muid,
268 &statp->extension, statp->n_uid,
269 statp->n_gid, statp->n_muid);
270 break;
272 case 'A': {
273 V9fsStatDotl *statp = va_arg(ap, V9fsStatDotl *);
274 copied = v9fs_iov_marshal(in_sg, in_num, offset, bswap,
275 "qQdddqqqqqqqqqqqqqqq",
276 statp->st_result_mask,
277 &statp->qid, statp->st_mode,
278 statp->st_uid, statp->st_gid,
279 statp->st_nlink, statp->st_rdev,
280 statp->st_size, statp->st_blksize,
281 statp->st_blocks, statp->st_atime_sec,
282 statp->st_atime_nsec,
283 statp->st_mtime_sec,
284 statp->st_mtime_nsec,
285 statp->st_ctime_sec,
286 statp->st_ctime_nsec,
287 statp->st_btime_sec,
288 statp->st_btime_nsec, statp->st_gen,
289 statp->st_data_version);
290 break;
292 default:
293 g_assert_not_reached();
295 if (copied < 0) {
296 return copied;
298 offset += copied;
301 return offset - old_offset;
304 ssize_t v9fs_iov_marshal(struct iovec *in_sg, int in_num, size_t offset,
305 int bswap, const char *fmt, ...)
307 ssize_t ret;
308 va_list ap;
310 va_start(ap, fmt);
311 ret = v9fs_iov_vmarshal(in_sg, in_num, offset, bswap, fmt, ap);
312 va_end(ap);
314 return ret;