]>
Commit | Line | Data |
---|---|---|
10925bf0 | 1 | /* |
2209bd05 | 2 | * 9p backend |
10925bf0 MK |
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 | ||
fbc04127 | 14 | #include "qemu/osdep.h" |
10925bf0 | 15 | #include <glib/gprintf.h> |
10925bf0 | 16 | #include <utime.h> |
10925bf0 | 17 | |
2209bd05 | 18 | #include "9p-iov-marshal.h" |
1de7afc9 | 19 | #include "qemu/bswap.h" |
10925bf0 | 20 | |
ddca7f86 MK |
21 | static ssize_t v9fs_packunpack(void *addr, struct iovec *sg, int sg_count, |
22 | size_t offset, size_t size, int pack) | |
10925bf0 MK |
23 | { |
24 | int i = 0; | |
25 | size_t copied = 0; | |
ddca7f86 MK |
26 | size_t req_size = size; |
27 | ||
10925bf0 MK |
28 | |
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); | |
41 | } | |
42 | size -= len; | |
43 | copied += len; | |
44 | addr += len; | |
45 | if (size) { | |
46 | offset = 0; | |
47 | continue; | |
48 | } | |
49 | } | |
50 | } | |
ddca7f86 MK |
51 | if (copied < req_size) { |
52 | /* | |
53 | * We copied less that requested size. error out | |
54 | */ | |
55 | return -ENOBUFS; | |
56 | } | |
10925bf0 MK |
57 | return copied; |
58 | } | |
59 | ||
ddca7f86 MK |
60 | static ssize_t v9fs_unpack(void *dst, struct iovec *out_sg, int out_num, |
61 | size_t offset, size_t size) | |
10925bf0 MK |
62 | { |
63 | return v9fs_packunpack(dst, out_sg, out_num, offset, size, 0); | |
64 | } | |
65 | ||
ddca7f86 MK |
66 | ssize_t v9fs_pack(struct iovec *in_sg, int in_num, size_t offset, |
67 | const void *src, size_t size) | |
10925bf0 MK |
68 | { |
69 | return v9fs_packunpack((void *)src, in_sg, in_num, offset, size, 1); | |
70 | } | |
71 | ||
0e2082d9 WL |
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) | |
10925bf0 MK |
74 | { |
75 | int i; | |
ddca7f86 | 76 | ssize_t copied = 0; |
10925bf0 MK |
77 | size_t old_offset = offset; |
78 | ||
10925bf0 MK |
79 | for (i = 0; fmt[i]; i++) { |
80 | switch (fmt[i]) { | |
81 | case 'b': { | |
82 | uint8_t *valp = va_arg(ap, uint8_t *); | |
ddca7f86 | 83 | copied = v9fs_unpack(valp, out_sg, out_num, offset, sizeof(*valp)); |
10925bf0 MK |
84 | break; |
85 | } | |
86 | case 'w': { | |
87 | uint16_t val, *valp; | |
88 | valp = va_arg(ap, uint16_t *); | |
ddca7f86 | 89 | copied = v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val)); |
10925bf0 MK |
90 | if (bswap) { |
91 | *valp = le16_to_cpu(val); | |
92 | } else { | |
93 | *valp = val; | |
94 | } | |
95 | break; | |
96 | } | |
97 | case 'd': { | |
98 | uint32_t val, *valp; | |
99 | valp = va_arg(ap, uint32_t *); | |
ddca7f86 | 100 | copied = v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val)); |
10925bf0 MK |
101 | if (bswap) { |
102 | *valp = le32_to_cpu(val); | |
103 | } else { | |
104 | *valp = val; | |
105 | } | |
106 | break; | |
107 | } | |
108 | case 'q': { | |
109 | uint64_t val, *valp; | |
110 | valp = va_arg(ap, uint64_t *); | |
ddca7f86 | 111 | copied = v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val)); |
10925bf0 MK |
112 | if (bswap) { |
113 | *valp = le64_to_cpu(val); | |
114 | } else { | |
115 | *valp = val; | |
116 | } | |
117 | break; | |
118 | } | |
119 | case 's': { | |
120 | V9fsString *str = va_arg(ap, V9fsString *); | |
2209bd05 WL |
121 | copied = v9fs_iov_unmarshal(out_sg, out_num, offset, bswap, |
122 | "w", &str->size); | |
ddca7f86 MK |
123 | if (copied > 0) { |
124 | offset += copied; | |
125 | str->data = g_malloc(str->size + 1); | |
126 | copied = v9fs_unpack(str->data, out_sg, out_num, offset, | |
127 | str->size); | |
ba42ebb8 | 128 | if (copied >= 0) { |
ddca7f86 MK |
129 | str->data[str->size] = 0; |
130 | } else { | |
131 | v9fs_string_free(str); | |
132 | } | |
133 | } | |
10925bf0 MK |
134 | break; |
135 | } | |
136 | case 'Q': { | |
137 | V9fsQID *qidp = va_arg(ap, V9fsQID *); | |
2209bd05 WL |
138 | copied = v9fs_iov_unmarshal(out_sg, out_num, offset, bswap, |
139 | "bdq", &qidp->type, &qidp->version, | |
140 | &qidp->path); | |
10925bf0 MK |
141 | break; |
142 | } | |
143 | case 'S': { | |
144 | V9fsStat *statp = va_arg(ap, V9fsStat *); | |
2209bd05 WL |
145 | copied = v9fs_iov_unmarshal(out_sg, out_num, offset, bswap, |
146 | "wwdQdddqsssssddd", | |
147 | &statp->size, &statp->type, | |
148 | &statp->dev, &statp->qid, | |
149 | &statp->mode, &statp->atime, | |
150 | &statp->mtime, &statp->length, | |
151 | &statp->name, &statp->uid, | |
152 | &statp->gid, &statp->muid, | |
153 | &statp->extension, | |
154 | &statp->n_uid, &statp->n_gid, | |
155 | &statp->n_muid); | |
10925bf0 MK |
156 | break; |
157 | } | |
158 | case 'I': { | |
159 | V9fsIattr *iattr = va_arg(ap, V9fsIattr *); | |
2209bd05 WL |
160 | copied = v9fs_iov_unmarshal(out_sg, out_num, offset, bswap, |
161 | "ddddqqqqq", | |
162 | &iattr->valid, &iattr->mode, | |
163 | &iattr->uid, &iattr->gid, | |
164 | &iattr->size, &iattr->atime_sec, | |
165 | &iattr->atime_nsec, | |
166 | &iattr->mtime_sec, | |
167 | &iattr->mtime_nsec); | |
10925bf0 MK |
168 | break; |
169 | } | |
170 | default: | |
57a0aa6b | 171 | g_assert_not_reached(); |
10925bf0 | 172 | } |
ddca7f86 | 173 | if (copied < 0) { |
ddca7f86 MK |
174 | return copied; |
175 | } | |
176 | offset += copied; | |
10925bf0 | 177 | } |
10925bf0 MK |
178 | |
179 | return offset - old_offset; | |
180 | } | |
181 | ||
0e2082d9 WL |
182 | ssize_t v9fs_iov_unmarshal(struct iovec *out_sg, int out_num, size_t offset, |
183 | int bswap, const char *fmt, ...) | |
10925bf0 | 184 | { |
0e2082d9 | 185 | ssize_t ret; |
10925bf0 | 186 | va_list ap; |
0e2082d9 WL |
187 | |
188 | va_start(ap, fmt); | |
189 | ret = v9fs_iov_vunmarshal(out_sg, out_num, offset, bswap, fmt, ap); | |
190 | va_end(ap); | |
191 | ||
192 | return ret; | |
193 | } | |
194 | ||
195 | ssize_t v9fs_iov_vmarshal(struct iovec *in_sg, int in_num, size_t offset, | |
196 | int bswap, const char *fmt, va_list ap) | |
197 | { | |
198 | int i; | |
ddca7f86 | 199 | ssize_t copied = 0; |
10925bf0 MK |
200 | size_t old_offset = offset; |
201 | ||
10925bf0 MK |
202 | for (i = 0; fmt[i]; i++) { |
203 | switch (fmt[i]) { | |
204 | case 'b': { | |
205 | uint8_t val = va_arg(ap, int); | |
ddca7f86 | 206 | copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val)); |
10925bf0 MK |
207 | break; |
208 | } | |
209 | case 'w': { | |
b442642d | 210 | uint16_t val = va_arg(ap, int); |
10925bf0 | 211 | if (bswap) { |
b442642d | 212 | val = cpu_to_le16(val); |
10925bf0 | 213 | } |
ddca7f86 | 214 | copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val)); |
10925bf0 MK |
215 | break; |
216 | } | |
217 | case 'd': { | |
b442642d | 218 | uint32_t val = va_arg(ap, uint32_t); |
10925bf0 | 219 | if (bswap) { |
b442642d | 220 | val = cpu_to_le32(val); |
10925bf0 | 221 | } |
ddca7f86 | 222 | copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val)); |
10925bf0 MK |
223 | break; |
224 | } | |
225 | case 'q': { | |
b442642d | 226 | uint64_t val = va_arg(ap, uint64_t); |
10925bf0 | 227 | if (bswap) { |
b442642d | 228 | val = cpu_to_le64(val); |
10925bf0 | 229 | } |
ddca7f86 | 230 | copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val)); |
10925bf0 MK |
231 | break; |
232 | } | |
233 | case 's': { | |
234 | V9fsString *str = va_arg(ap, V9fsString *); | |
2209bd05 WL |
235 | copied = v9fs_iov_marshal(in_sg, in_num, offset, bswap, |
236 | "w", str->size); | |
ddca7f86 MK |
237 | if (copied > 0) { |
238 | offset += copied; | |
239 | copied = v9fs_pack(in_sg, in_num, offset, str->data, str->size); | |
240 | } | |
10925bf0 MK |
241 | break; |
242 | } | |
243 | case 'Q': { | |
244 | V9fsQID *qidp = va_arg(ap, V9fsQID *); | |
2209bd05 WL |
245 | copied = v9fs_iov_marshal(in_sg, in_num, offset, bswap, "bdq", |
246 | qidp->type, qidp->version, | |
247 | qidp->path); | |
10925bf0 MK |
248 | break; |
249 | } | |
250 | case 'S': { | |
251 | V9fsStat *statp = va_arg(ap, V9fsStat *); | |
2209bd05 WL |
252 | copied = v9fs_iov_marshal(in_sg, in_num, offset, bswap, |
253 | "wwdQdddqsssssddd", | |
254 | statp->size, statp->type, statp->dev, | |
255 | &statp->qid, statp->mode, statp->atime, | |
256 | statp->mtime, statp->length, | |
257 | &statp->name, | |
258 | &statp->uid, &statp->gid, &statp->muid, | |
259 | &statp->extension, statp->n_uid, | |
260 | statp->n_gid, statp->n_muid); | |
10925bf0 MK |
261 | break; |
262 | } | |
263 | case 'A': { | |
264 | V9fsStatDotl *statp = va_arg(ap, V9fsStatDotl *); | |
2209bd05 WL |
265 | copied = v9fs_iov_marshal(in_sg, in_num, offset, bswap, |
266 | "qQdddqqqqqqqqqqqqqqq", | |
267 | statp->st_result_mask, | |
268 | &statp->qid, statp->st_mode, | |
269 | statp->st_uid, statp->st_gid, | |
270 | statp->st_nlink, statp->st_rdev, | |
271 | statp->st_size, statp->st_blksize, | |
272 | statp->st_blocks, statp->st_atime_sec, | |
273 | statp->st_atime_nsec, | |
274 | statp->st_mtime_sec, | |
275 | statp->st_mtime_nsec, | |
276 | statp->st_ctime_sec, | |
277 | statp->st_ctime_nsec, | |
278 | statp->st_btime_sec, | |
279 | statp->st_btime_nsec, statp->st_gen, | |
280 | statp->st_data_version); | |
10925bf0 MK |
281 | break; |
282 | } | |
283 | default: | |
57a0aa6b | 284 | g_assert_not_reached(); |
10925bf0 | 285 | } |
ddca7f86 | 286 | if (copied < 0) { |
ddca7f86 MK |
287 | return copied; |
288 | } | |
289 | offset += copied; | |
10925bf0 | 290 | } |
10925bf0 MK |
291 | |
292 | return offset - old_offset; | |
293 | } | |
0e2082d9 WL |
294 | |
295 | ssize_t v9fs_iov_marshal(struct iovec *in_sg, int in_num, size_t offset, | |
296 | int bswap, const char *fmt, ...) | |
297 | { | |
298 | ssize_t ret; | |
299 | va_list ap; | |
300 | ||
301 | va_start(ap, fmt); | |
302 | ret = v9fs_iov_vmarshal(in_sg, in_num, offset, bswap, fmt, ap); | |
303 | va_end(ap); | |
304 | ||
305 | return ret; | |
306 | } |