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