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