12209bd05SWei Liu /*
22209bd05SWei Liu * 9p backend
32209bd05SWei Liu *
42209bd05SWei Liu * Copyright IBM, Corp. 2010
52209bd05SWei Liu *
62209bd05SWei Liu * Authors:
72209bd05SWei Liu * Anthony Liguori <aliguori@us.ibm.com>
82209bd05SWei Liu *
92209bd05SWei Liu * This work is licensed under the terms of the GNU GPL, version 2. See
102209bd05SWei Liu * the COPYING file in the top-level directory.
112209bd05SWei Liu *
122209bd05SWei Liu */
132209bd05SWei Liu
14fbc04127SPeter Maydell #include "qemu/osdep.h"
152209bd05SWei Liu #include <glib/gprintf.h>
162209bd05SWei Liu #include <utime.h>
172209bd05SWei Liu
182209bd05SWei Liu #include "9p-iov-marshal.h"
192209bd05SWei Liu #include "qemu/bswap.h"
202209bd05SWei Liu
v9fs_packunpack(void * addr,struct iovec * sg,int sg_count,size_t offset,size_t size,int pack)212209bd05SWei Liu static ssize_t v9fs_packunpack(void *addr, struct iovec *sg, int sg_count,
222209bd05SWei Liu size_t offset, size_t size, int pack)
232209bd05SWei Liu {
242209bd05SWei Liu int i = 0;
252209bd05SWei Liu size_t copied = 0;
262209bd05SWei Liu size_t req_size = size;
272209bd05SWei Liu
282209bd05SWei Liu
292209bd05SWei Liu for (i = 0; size && i < sg_count; i++) {
302209bd05SWei Liu size_t len;
312209bd05SWei Liu if (offset >= sg[i].iov_len) {
322209bd05SWei Liu /* skip this sg */
332209bd05SWei Liu offset -= sg[i].iov_len;
342209bd05SWei Liu continue;
352209bd05SWei Liu } else {
362209bd05SWei Liu len = MIN(sg[i].iov_len - offset, size);
372209bd05SWei Liu if (pack) {
382209bd05SWei Liu memcpy(sg[i].iov_base + offset, addr, len);
392209bd05SWei Liu } else {
402209bd05SWei Liu memcpy(addr, sg[i].iov_base + offset, len);
412209bd05SWei Liu }
422209bd05SWei Liu size -= len;
432209bd05SWei Liu copied += len;
442209bd05SWei Liu addr += len;
452209bd05SWei Liu if (size) {
462209bd05SWei Liu offset = 0;
472209bd05SWei Liu continue;
482209bd05SWei Liu }
492209bd05SWei Liu }
502209bd05SWei Liu }
512209bd05SWei Liu if (copied < req_size) {
522209bd05SWei Liu /*
532209bd05SWei Liu * We copied less that requested size. error out
542209bd05SWei Liu */
552209bd05SWei Liu return -ENOBUFS;
562209bd05SWei Liu }
572209bd05SWei Liu return copied;
582209bd05SWei Liu }
592209bd05SWei Liu
v9fs_unpack(void * dst,struct iovec * out_sg,int out_num,size_t offset,size_t size)602209bd05SWei Liu static ssize_t v9fs_unpack(void *dst, struct iovec *out_sg, int out_num,
612209bd05SWei Liu size_t offset, size_t size)
622209bd05SWei Liu {
632209bd05SWei Liu return v9fs_packunpack(dst, out_sg, out_num, offset, size, 0);
642209bd05SWei Liu }
652209bd05SWei Liu
v9fs_pack(struct iovec * in_sg,int in_num,size_t offset,const void * src,size_t size)662209bd05SWei Liu ssize_t v9fs_pack(struct iovec *in_sg, int in_num, size_t offset,
672209bd05SWei Liu const void *src, size_t size)
682209bd05SWei Liu {
692209bd05SWei Liu return v9fs_packunpack((void *)src, in_sg, in_num, offset, size, 1);
702209bd05SWei Liu }
712209bd05SWei Liu
v9fs_iov_vunmarshal(struct iovec * out_sg,int out_num,size_t offset,int bswap,const char * fmt,va_list ap)720e2082d9SWei Liu ssize_t v9fs_iov_vunmarshal(struct iovec *out_sg, int out_num, size_t offset,
730e2082d9SWei Liu int bswap, const char *fmt, va_list ap)
742209bd05SWei Liu {
752209bd05SWei Liu int i;
762209bd05SWei Liu ssize_t copied = 0;
772209bd05SWei Liu size_t old_offset = offset;
782209bd05SWei Liu
792209bd05SWei Liu for (i = 0; fmt[i]; i++) {
802209bd05SWei Liu switch (fmt[i]) {
812209bd05SWei Liu case 'b': {
822209bd05SWei Liu uint8_t *valp = va_arg(ap, uint8_t *);
832209bd05SWei Liu copied = v9fs_unpack(valp, out_sg, out_num, offset, sizeof(*valp));
842209bd05SWei Liu break;
852209bd05SWei Liu }
862209bd05SWei Liu case 'w': {
872209bd05SWei Liu uint16_t val, *valp;
882209bd05SWei Liu valp = va_arg(ap, uint16_t *);
892209bd05SWei Liu copied = v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val));
902209bd05SWei Liu if (bswap) {
912209bd05SWei Liu *valp = le16_to_cpu(val);
922209bd05SWei Liu } else {
932209bd05SWei Liu *valp = val;
942209bd05SWei Liu }
952209bd05SWei Liu break;
962209bd05SWei Liu }
972209bd05SWei Liu case 'd': {
982209bd05SWei Liu uint32_t val, *valp;
992209bd05SWei Liu valp = va_arg(ap, uint32_t *);
1002209bd05SWei Liu copied = v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val));
1012209bd05SWei Liu if (bswap) {
1022209bd05SWei Liu *valp = le32_to_cpu(val);
1032209bd05SWei Liu } else {
1042209bd05SWei Liu *valp = val;
1052209bd05SWei Liu }
1062209bd05SWei Liu break;
1072209bd05SWei Liu }
1082209bd05SWei Liu case 'q': {
1092209bd05SWei Liu uint64_t val, *valp;
1102209bd05SWei Liu valp = va_arg(ap, uint64_t *);
1112209bd05SWei Liu copied = v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val));
1122209bd05SWei Liu if (bswap) {
1132209bd05SWei Liu *valp = le64_to_cpu(val);
1142209bd05SWei Liu } else {
1152209bd05SWei Liu *valp = val;
1162209bd05SWei Liu }
1172209bd05SWei Liu break;
1182209bd05SWei Liu }
1192209bd05SWei Liu case 's': {
1202209bd05SWei Liu V9fsString *str = va_arg(ap, V9fsString *);
1212209bd05SWei Liu copied = v9fs_iov_unmarshal(out_sg, out_num, offset, bswap,
1222209bd05SWei Liu "w", &str->size);
1232209bd05SWei Liu if (copied > 0) {
1242209bd05SWei Liu offset += copied;
1252209bd05SWei Liu str->data = g_malloc(str->size + 1);
1262209bd05SWei Liu copied = v9fs_unpack(str->data, out_sg, out_num, offset,
1272209bd05SWei Liu str->size);
128ba42ebb8SLi Qiang if (copied >= 0) {
1292209bd05SWei Liu str->data[str->size] = 0;
1302209bd05SWei Liu } else {
1312209bd05SWei Liu v9fs_string_free(str);
1322209bd05SWei Liu }
1332209bd05SWei Liu }
1342209bd05SWei Liu break;
1352209bd05SWei Liu }
1362209bd05SWei Liu case 'Q': {
1372209bd05SWei Liu V9fsQID *qidp = va_arg(ap, V9fsQID *);
1382209bd05SWei Liu copied = v9fs_iov_unmarshal(out_sg, out_num, offset, bswap,
1392209bd05SWei Liu "bdq", &qidp->type, &qidp->version,
1402209bd05SWei Liu &qidp->path);
1412209bd05SWei Liu break;
1422209bd05SWei Liu }
1432209bd05SWei Liu case 'S': {
1442209bd05SWei Liu V9fsStat *statp = va_arg(ap, V9fsStat *);
1452209bd05SWei Liu copied = v9fs_iov_unmarshal(out_sg, out_num, offset, bswap,
1462209bd05SWei Liu "wwdQdddqsssssddd",
1472209bd05SWei Liu &statp->size, &statp->type,
1482209bd05SWei Liu &statp->dev, &statp->qid,
1492209bd05SWei Liu &statp->mode, &statp->atime,
1502209bd05SWei Liu &statp->mtime, &statp->length,
1512209bd05SWei Liu &statp->name, &statp->uid,
1522209bd05SWei Liu &statp->gid, &statp->muid,
1532209bd05SWei Liu &statp->extension,
1542209bd05SWei Liu &statp->n_uid, &statp->n_gid,
1552209bd05SWei Liu &statp->n_muid);
1562209bd05SWei Liu break;
1572209bd05SWei Liu }
1582209bd05SWei Liu case 'I': {
1592209bd05SWei Liu V9fsIattr *iattr = va_arg(ap, V9fsIattr *);
1602209bd05SWei Liu copied = v9fs_iov_unmarshal(out_sg, out_num, offset, bswap,
1612209bd05SWei Liu "ddddqqqqq",
1622209bd05SWei Liu &iattr->valid, &iattr->mode,
1632209bd05SWei Liu &iattr->uid, &iattr->gid,
1642209bd05SWei Liu &iattr->size, &iattr->atime_sec,
1652209bd05SWei Liu &iattr->atime_nsec,
1662209bd05SWei Liu &iattr->mtime_sec,
1672209bd05SWei Liu &iattr->mtime_nsec);
1682209bd05SWei Liu break;
1692209bd05SWei Liu }
1702209bd05SWei Liu default:
171*57a0aa6bSGreg Kurz g_assert_not_reached();
1722209bd05SWei Liu }
1732209bd05SWei Liu if (copied < 0) {
1742209bd05SWei Liu return copied;
1752209bd05SWei Liu }
1762209bd05SWei Liu offset += copied;
1772209bd05SWei Liu }
1782209bd05SWei Liu
1792209bd05SWei Liu return offset - old_offset;
1802209bd05SWei Liu }
1812209bd05SWei Liu
v9fs_iov_unmarshal(struct iovec * out_sg,int out_num,size_t offset,int bswap,const char * fmt,...)1820e2082d9SWei Liu ssize_t v9fs_iov_unmarshal(struct iovec *out_sg, int out_num, size_t offset,
1832209bd05SWei Liu int bswap, const char *fmt, ...)
1842209bd05SWei Liu {
1850e2082d9SWei Liu ssize_t ret;
1862209bd05SWei Liu va_list ap;
1870e2082d9SWei Liu
1880e2082d9SWei Liu va_start(ap, fmt);
1890e2082d9SWei Liu ret = v9fs_iov_vunmarshal(out_sg, out_num, offset, bswap, fmt, ap);
1900e2082d9SWei Liu va_end(ap);
1910e2082d9SWei Liu
1920e2082d9SWei Liu return ret;
1930e2082d9SWei Liu }
1940e2082d9SWei Liu
v9fs_iov_vmarshal(struct iovec * in_sg,int in_num,size_t offset,int bswap,const char * fmt,va_list ap)1950e2082d9SWei Liu ssize_t v9fs_iov_vmarshal(struct iovec *in_sg, int in_num, size_t offset,
1960e2082d9SWei Liu int bswap, const char *fmt, va_list ap)
1970e2082d9SWei Liu {
1980e2082d9SWei Liu int i;
1992209bd05SWei Liu ssize_t copied = 0;
2002209bd05SWei Liu size_t old_offset = offset;
2012209bd05SWei Liu
2022209bd05SWei Liu for (i = 0; fmt[i]; i++) {
2032209bd05SWei Liu switch (fmt[i]) {
2042209bd05SWei Liu case 'b': {
2052209bd05SWei Liu uint8_t val = va_arg(ap, int);
2062209bd05SWei Liu copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
2072209bd05SWei Liu break;
2082209bd05SWei Liu }
2092209bd05SWei Liu case 'w': {
210b442642dSPeter Maydell uint16_t val = va_arg(ap, int);
2112209bd05SWei Liu if (bswap) {
212b442642dSPeter Maydell val = cpu_to_le16(val);
2132209bd05SWei Liu }
2142209bd05SWei Liu copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
2152209bd05SWei Liu break;
2162209bd05SWei Liu }
2172209bd05SWei Liu case 'd': {
218b442642dSPeter Maydell uint32_t val = va_arg(ap, uint32_t);
2192209bd05SWei Liu if (bswap) {
220b442642dSPeter Maydell val = cpu_to_le32(val);
2212209bd05SWei Liu }
2222209bd05SWei Liu copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
2232209bd05SWei Liu break;
2242209bd05SWei Liu }
2252209bd05SWei Liu case 'q': {
226b442642dSPeter Maydell uint64_t val = va_arg(ap, uint64_t);
2272209bd05SWei Liu if (bswap) {
228b442642dSPeter Maydell val = cpu_to_le64(val);
2292209bd05SWei Liu }
2302209bd05SWei Liu copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
2312209bd05SWei Liu break;
2322209bd05SWei Liu }
2332209bd05SWei Liu case 's': {
2342209bd05SWei Liu V9fsString *str = va_arg(ap, V9fsString *);
2352209bd05SWei Liu copied = v9fs_iov_marshal(in_sg, in_num, offset, bswap,
2362209bd05SWei Liu "w", str->size);
2372209bd05SWei Liu if (copied > 0) {
2382209bd05SWei Liu offset += copied;
2392209bd05SWei Liu copied = v9fs_pack(in_sg, in_num, offset, str->data, str->size);
2402209bd05SWei Liu }
2412209bd05SWei Liu break;
2422209bd05SWei Liu }
2432209bd05SWei Liu case 'Q': {
2442209bd05SWei Liu V9fsQID *qidp = va_arg(ap, V9fsQID *);
2452209bd05SWei Liu copied = v9fs_iov_marshal(in_sg, in_num, offset, bswap, "bdq",
2462209bd05SWei Liu qidp->type, qidp->version,
2472209bd05SWei Liu qidp->path);
2482209bd05SWei Liu break;
2492209bd05SWei Liu }
2502209bd05SWei Liu case 'S': {
2512209bd05SWei Liu V9fsStat *statp = va_arg(ap, V9fsStat *);
2522209bd05SWei Liu copied = v9fs_iov_marshal(in_sg, in_num, offset, bswap,
2532209bd05SWei Liu "wwdQdddqsssssddd",
2542209bd05SWei Liu statp->size, statp->type, statp->dev,
2552209bd05SWei Liu &statp->qid, statp->mode, statp->atime,
2562209bd05SWei Liu statp->mtime, statp->length,
2572209bd05SWei Liu &statp->name,
2582209bd05SWei Liu &statp->uid, &statp->gid, &statp->muid,
2592209bd05SWei Liu &statp->extension, statp->n_uid,
2602209bd05SWei Liu statp->n_gid, statp->n_muid);
2612209bd05SWei Liu break;
2622209bd05SWei Liu }
2632209bd05SWei Liu case 'A': {
2642209bd05SWei Liu V9fsStatDotl *statp = va_arg(ap, V9fsStatDotl *);
2652209bd05SWei Liu copied = v9fs_iov_marshal(in_sg, in_num, offset, bswap,
2662209bd05SWei Liu "qQdddqqqqqqqqqqqqqqq",
2672209bd05SWei Liu statp->st_result_mask,
2682209bd05SWei Liu &statp->qid, statp->st_mode,
2692209bd05SWei Liu statp->st_uid, statp->st_gid,
2702209bd05SWei Liu statp->st_nlink, statp->st_rdev,
2712209bd05SWei Liu statp->st_size, statp->st_blksize,
2722209bd05SWei Liu statp->st_blocks, statp->st_atime_sec,
2732209bd05SWei Liu statp->st_atime_nsec,
2742209bd05SWei Liu statp->st_mtime_sec,
2752209bd05SWei Liu statp->st_mtime_nsec,
2762209bd05SWei Liu statp->st_ctime_sec,
2772209bd05SWei Liu statp->st_ctime_nsec,
2782209bd05SWei Liu statp->st_btime_sec,
2792209bd05SWei Liu statp->st_btime_nsec, statp->st_gen,
2802209bd05SWei Liu statp->st_data_version);
2812209bd05SWei Liu break;
2822209bd05SWei Liu }
2832209bd05SWei Liu default:
284*57a0aa6bSGreg Kurz g_assert_not_reached();
2852209bd05SWei Liu }
2862209bd05SWei Liu if (copied < 0) {
2872209bd05SWei Liu return copied;
2882209bd05SWei Liu }
2892209bd05SWei Liu offset += copied;
2902209bd05SWei Liu }
2912209bd05SWei Liu
2922209bd05SWei Liu return offset - old_offset;
2932209bd05SWei Liu }
2940e2082d9SWei Liu
v9fs_iov_marshal(struct iovec * in_sg,int in_num,size_t offset,int bswap,const char * fmt,...)2950e2082d9SWei Liu ssize_t v9fs_iov_marshal(struct iovec *in_sg, int in_num, size_t offset,
2960e2082d9SWei Liu int bswap, const char *fmt, ...)
2970e2082d9SWei Liu {
2980e2082d9SWei Liu ssize_t ret;
2990e2082d9SWei Liu va_list ap;
3000e2082d9SWei Liu
3010e2082d9SWei Liu va_start(ap, fmt);
3020e2082d9SWei Liu ret = v9fs_iov_vmarshal(in_sg, in_num, offset, bswap, fmt, ap);
3030e2082d9SWei Liu va_end(ap);
3040e2082d9SWei Liu
3050e2082d9SWei Liu return ret;
3060e2082d9SWei Liu }
307