1 /* 2 * 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 "qemu/osdep.h" 15 #include <glib/gprintf.h> 16 #include <utime.h> 17 18 #include "9p-iov-marshal.h" 19 #include "qemu/bswap.h" 20 21 static ssize_t v9fs_packunpack(void *addr, struct iovec *sg, int sg_count, 22 size_t offset, size_t size, int pack) 23 { 24 int i = 0; 25 size_t copied = 0; 26 size_t req_size = size; 27 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 } 51 if (copied < req_size) { 52 /* 53 * We copied less that requested size. error out 54 */ 55 return -ENOBUFS; 56 } 57 return copied; 58 } 59 60 static ssize_t v9fs_unpack(void *dst, struct iovec *out_sg, int out_num, 61 size_t offset, size_t size) 62 { 63 return v9fs_packunpack(dst, out_sg, out_num, offset, size, 0); 64 } 65 66 ssize_t v9fs_pack(struct iovec *in_sg, int in_num, size_t offset, 67 const void *src, size_t size) 68 { 69 return v9fs_packunpack((void *)src, in_sg, in_num, offset, size, 1); 70 } 71 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) 74 { 75 int i; 76 ssize_t copied = 0; 77 size_t old_offset = offset; 78 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; 85 } 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; 92 } 93 if (bswap) { 94 *valp = le16_to_cpu(val); 95 } else { 96 *valp = val; 97 } 98 break; 99 } 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; 106 } 107 if (bswap) { 108 *valp = le32_to_cpu(val); 109 } else { 110 *valp = val; 111 } 112 break; 113 } 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; 120 } 121 if (bswap) { 122 *valp = le64_to_cpu(val); 123 } else { 124 *valp = val; 125 } 126 break; 127 } 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); 141 } 142 } 143 break; 144 } 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; 151 } 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; 166 } 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; 178 } 179 default: 180 g_assert_not_reached(); 181 } 182 if (copied < 0) { 183 return copied; 184 } 185 offset += copied; 186 } 187 188 return offset - old_offset; 189 } 190 191 ssize_t v9fs_iov_unmarshal(struct iovec *out_sg, int out_num, size_t offset, 192 int bswap, const char *fmt, ...) 193 { 194 ssize_t ret; 195 va_list ap; 196 197 va_start(ap, fmt); 198 ret = v9fs_iov_vunmarshal(out_sg, out_num, offset, bswap, fmt, ap); 199 va_end(ap); 200 201 return ret; 202 } 203 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) 206 { 207 int i; 208 ssize_t copied = 0; 209 size_t old_offset = offset; 210 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; 217 } 218 case 'w': { 219 uint16_t val = va_arg(ap, int); 220 if (bswap) { 221 val = cpu_to_le16(val); 222 } 223 copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val)); 224 break; 225 } 226 case 'd': { 227 uint32_t val = va_arg(ap, uint32_t); 228 if (bswap) { 229 val = cpu_to_le32(val); 230 } 231 copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val)); 232 break; 233 } 234 case 'q': { 235 uint64_t val = va_arg(ap, uint64_t); 236 if (bswap) { 237 val = cpu_to_le64(val); 238 } 239 copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val)); 240 break; 241 } 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); 249 } 250 break; 251 } 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; 258 } 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; 271 } 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; 291 } 292 default: 293 g_assert_not_reached(); 294 } 295 if (copied < 0) { 296 return copied; 297 } 298 offset += copied; 299 } 300 301 return offset - old_offset; 302 } 303 304 ssize_t v9fs_iov_marshal(struct iovec *in_sg, int in_num, size_t offset, 305 int bswap, const char *fmt, ...) 306 { 307 ssize_t ret; 308 va_list ap; 309 310 va_start(ap, fmt); 311 ret = v9fs_iov_vmarshal(in_sg, in_num, offset, bswap, fmt, ap); 312 va_end(ap); 313 314 return ret; 315 } 316