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': {
87*79660687SMarc-André Lureau uint16_t val = 0, *valp;
882209bd05SWei Liu valp = va_arg(ap, uint16_t *);
892209bd05SWei Liu copied = v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val));
90*79660687SMarc-André Lureau if (copied <= 0) {
91*79660687SMarc-André Lureau break;
92*79660687SMarc-André Lureau }
932209bd05SWei Liu if (bswap) {
942209bd05SWei Liu *valp = le16_to_cpu(val);
952209bd05SWei Liu } else {
962209bd05SWei Liu *valp = val;
972209bd05SWei Liu }
982209bd05SWei Liu break;
992209bd05SWei Liu }
1002209bd05SWei Liu case 'd': {
101*79660687SMarc-André Lureau uint32_t val = 0, *valp;
1022209bd05SWei Liu valp = va_arg(ap, uint32_t *);
1032209bd05SWei Liu copied = v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val));
104*79660687SMarc-André Lureau if (copied <= 0) {
105*79660687SMarc-André Lureau break;
106*79660687SMarc-André Lureau }
1072209bd05SWei Liu if (bswap) {
1082209bd05SWei Liu *valp = le32_to_cpu(val);
1092209bd05SWei Liu } else {
1102209bd05SWei Liu *valp = val;
1112209bd05SWei Liu }
1122209bd05SWei Liu break;
1132209bd05SWei Liu }
1142209bd05SWei Liu case 'q': {
115*79660687SMarc-André Lureau uint64_t val = 0, *valp;
1162209bd05SWei Liu valp = va_arg(ap, uint64_t *);
1172209bd05SWei Liu copied = v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val));
118*79660687SMarc-André Lureau if (copied <= 0) {
119*79660687SMarc-André Lureau break;
120*79660687SMarc-André Lureau }
1212209bd05SWei Liu if (bswap) {
1222209bd05SWei Liu *valp = le64_to_cpu(val);
1232209bd05SWei Liu } else {
1242209bd05SWei Liu *valp = val;
1252209bd05SWei Liu }
1262209bd05SWei Liu break;
1272209bd05SWei Liu }
1282209bd05SWei Liu case 's': {
1292209bd05SWei Liu V9fsString *str = va_arg(ap, V9fsString *);
1302209bd05SWei Liu copied = v9fs_iov_unmarshal(out_sg, out_num, offset, bswap,
1312209bd05SWei Liu "w", &str->size);
1322209bd05SWei Liu if (copied > 0) {
1332209bd05SWei Liu offset += copied;
1342209bd05SWei Liu str->data = g_malloc(str->size + 1);
1352209bd05SWei Liu copied = v9fs_unpack(str->data, out_sg, out_num, offset,
1362209bd05SWei Liu str->size);
137ba42ebb8SLi Qiang if (copied >= 0) {
1382209bd05SWei Liu str->data[str->size] = 0;
1392209bd05SWei Liu } else {
1402209bd05SWei Liu v9fs_string_free(str);
1412209bd05SWei Liu }
1422209bd05SWei Liu }
1432209bd05SWei Liu break;
1442209bd05SWei Liu }
1452209bd05SWei Liu case 'Q': {
1462209bd05SWei Liu V9fsQID *qidp = va_arg(ap, V9fsQID *);
1472209bd05SWei Liu copied = v9fs_iov_unmarshal(out_sg, out_num, offset, bswap,
1482209bd05SWei Liu "bdq", &qidp->type, &qidp->version,
1492209bd05SWei Liu &qidp->path);
1502209bd05SWei Liu break;
1512209bd05SWei Liu }
1522209bd05SWei Liu case 'S': {
1532209bd05SWei Liu V9fsStat *statp = va_arg(ap, V9fsStat *);
1542209bd05SWei Liu copied = v9fs_iov_unmarshal(out_sg, out_num, offset, bswap,
1552209bd05SWei Liu "wwdQdddqsssssddd",
1562209bd05SWei Liu &statp->size, &statp->type,
1572209bd05SWei Liu &statp->dev, &statp->qid,
1582209bd05SWei Liu &statp->mode, &statp->atime,
1592209bd05SWei Liu &statp->mtime, &statp->length,
1602209bd05SWei Liu &statp->name, &statp->uid,
1612209bd05SWei Liu &statp->gid, &statp->muid,
1622209bd05SWei Liu &statp->extension,
1632209bd05SWei Liu &statp->n_uid, &statp->n_gid,
1642209bd05SWei Liu &statp->n_muid);
1652209bd05SWei Liu break;
1662209bd05SWei Liu }
1672209bd05SWei Liu case 'I': {
1682209bd05SWei Liu V9fsIattr *iattr = va_arg(ap, V9fsIattr *);
1692209bd05SWei Liu copied = v9fs_iov_unmarshal(out_sg, out_num, offset, bswap,
1702209bd05SWei Liu "ddddqqqqq",
1712209bd05SWei Liu &iattr->valid, &iattr->mode,
1722209bd05SWei Liu &iattr->uid, &iattr->gid,
1732209bd05SWei Liu &iattr->size, &iattr->atime_sec,
1742209bd05SWei Liu &iattr->atime_nsec,
1752209bd05SWei Liu &iattr->mtime_sec,
1762209bd05SWei Liu &iattr->mtime_nsec);
1772209bd05SWei Liu break;
1782209bd05SWei Liu }
1792209bd05SWei Liu default:
18057a0aa6bSGreg Kurz g_assert_not_reached();
1812209bd05SWei Liu }
1822209bd05SWei Liu if (copied < 0) {
1832209bd05SWei Liu return copied;
1842209bd05SWei Liu }
1852209bd05SWei Liu offset += copied;
1862209bd05SWei Liu }
1872209bd05SWei Liu
1882209bd05SWei Liu return offset - old_offset;
1892209bd05SWei Liu }
1902209bd05SWei Liu
v9fs_iov_unmarshal(struct iovec * out_sg,int out_num,size_t offset,int bswap,const char * fmt,...)1910e2082d9SWei Liu ssize_t v9fs_iov_unmarshal(struct iovec *out_sg, int out_num, size_t offset,
1922209bd05SWei Liu int bswap, const char *fmt, ...)
1932209bd05SWei Liu {
1940e2082d9SWei Liu ssize_t ret;
1952209bd05SWei Liu va_list ap;
1960e2082d9SWei Liu
1970e2082d9SWei Liu va_start(ap, fmt);
1980e2082d9SWei Liu ret = v9fs_iov_vunmarshal(out_sg, out_num, offset, bswap, fmt, ap);
1990e2082d9SWei Liu va_end(ap);
2000e2082d9SWei Liu
2010e2082d9SWei Liu return ret;
2020e2082d9SWei Liu }
2030e2082d9SWei Liu
v9fs_iov_vmarshal(struct iovec * in_sg,int in_num,size_t offset,int bswap,const char * fmt,va_list ap)2040e2082d9SWei Liu ssize_t v9fs_iov_vmarshal(struct iovec *in_sg, int in_num, size_t offset,
2050e2082d9SWei Liu int bswap, const char *fmt, va_list ap)
2060e2082d9SWei Liu {
2070e2082d9SWei Liu int i;
2082209bd05SWei Liu ssize_t copied = 0;
2092209bd05SWei Liu size_t old_offset = offset;
2102209bd05SWei Liu
2112209bd05SWei Liu for (i = 0; fmt[i]; i++) {
2122209bd05SWei Liu switch (fmt[i]) {
2132209bd05SWei Liu case 'b': {
2142209bd05SWei Liu uint8_t val = va_arg(ap, int);
2152209bd05SWei Liu copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
2162209bd05SWei Liu break;
2172209bd05SWei Liu }
2182209bd05SWei Liu case 'w': {
219b442642dSPeter Maydell uint16_t val = va_arg(ap, int);
2202209bd05SWei Liu if (bswap) {
221b442642dSPeter Maydell val = cpu_to_le16(val);
2222209bd05SWei Liu }
2232209bd05SWei Liu copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
2242209bd05SWei Liu break;
2252209bd05SWei Liu }
2262209bd05SWei Liu case 'd': {
227b442642dSPeter Maydell uint32_t val = va_arg(ap, uint32_t);
2282209bd05SWei Liu if (bswap) {
229b442642dSPeter Maydell val = cpu_to_le32(val);
2302209bd05SWei Liu }
2312209bd05SWei Liu copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
2322209bd05SWei Liu break;
2332209bd05SWei Liu }
2342209bd05SWei Liu case 'q': {
235b442642dSPeter Maydell uint64_t val = va_arg(ap, uint64_t);
2362209bd05SWei Liu if (bswap) {
237b442642dSPeter Maydell val = cpu_to_le64(val);
2382209bd05SWei Liu }
2392209bd05SWei Liu copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
2402209bd05SWei Liu break;
2412209bd05SWei Liu }
2422209bd05SWei Liu case 's': {
2432209bd05SWei Liu V9fsString *str = va_arg(ap, V9fsString *);
2442209bd05SWei Liu copied = v9fs_iov_marshal(in_sg, in_num, offset, bswap,
2452209bd05SWei Liu "w", str->size);
2462209bd05SWei Liu if (copied > 0) {
2472209bd05SWei Liu offset += copied;
2482209bd05SWei Liu copied = v9fs_pack(in_sg, in_num, offset, str->data, str->size);
2492209bd05SWei Liu }
2502209bd05SWei Liu break;
2512209bd05SWei Liu }
2522209bd05SWei Liu case 'Q': {
2532209bd05SWei Liu V9fsQID *qidp = va_arg(ap, V9fsQID *);
2542209bd05SWei Liu copied = v9fs_iov_marshal(in_sg, in_num, offset, bswap, "bdq",
2552209bd05SWei Liu qidp->type, qidp->version,
2562209bd05SWei Liu qidp->path);
2572209bd05SWei Liu break;
2582209bd05SWei Liu }
2592209bd05SWei Liu case 'S': {
2602209bd05SWei Liu V9fsStat *statp = va_arg(ap, V9fsStat *);
2612209bd05SWei Liu copied = v9fs_iov_marshal(in_sg, in_num, offset, bswap,
2622209bd05SWei Liu "wwdQdddqsssssddd",
2632209bd05SWei Liu statp->size, statp->type, statp->dev,
2642209bd05SWei Liu &statp->qid, statp->mode, statp->atime,
2652209bd05SWei Liu statp->mtime, statp->length,
2662209bd05SWei Liu &statp->name,
2672209bd05SWei Liu &statp->uid, &statp->gid, &statp->muid,
2682209bd05SWei Liu &statp->extension, statp->n_uid,
2692209bd05SWei Liu statp->n_gid, statp->n_muid);
2702209bd05SWei Liu break;
2712209bd05SWei Liu }
2722209bd05SWei Liu case 'A': {
2732209bd05SWei Liu V9fsStatDotl *statp = va_arg(ap, V9fsStatDotl *);
2742209bd05SWei Liu copied = v9fs_iov_marshal(in_sg, in_num, offset, bswap,
2752209bd05SWei Liu "qQdddqqqqqqqqqqqqqqq",
2762209bd05SWei Liu statp->st_result_mask,
2772209bd05SWei Liu &statp->qid, statp->st_mode,
2782209bd05SWei Liu statp->st_uid, statp->st_gid,
2792209bd05SWei Liu statp->st_nlink, statp->st_rdev,
2802209bd05SWei Liu statp->st_size, statp->st_blksize,
2812209bd05SWei Liu statp->st_blocks, statp->st_atime_sec,
2822209bd05SWei Liu statp->st_atime_nsec,
2832209bd05SWei Liu statp->st_mtime_sec,
2842209bd05SWei Liu statp->st_mtime_nsec,
2852209bd05SWei Liu statp->st_ctime_sec,
2862209bd05SWei Liu statp->st_ctime_nsec,
2872209bd05SWei Liu statp->st_btime_sec,
2882209bd05SWei Liu statp->st_btime_nsec, statp->st_gen,
2892209bd05SWei Liu statp->st_data_version);
2902209bd05SWei Liu break;
2912209bd05SWei Liu }
2922209bd05SWei Liu default:
29357a0aa6bSGreg Kurz g_assert_not_reached();
2942209bd05SWei Liu }
2952209bd05SWei Liu if (copied < 0) {
2962209bd05SWei Liu return copied;
2972209bd05SWei Liu }
2982209bd05SWei Liu offset += copied;
2992209bd05SWei Liu }
3002209bd05SWei Liu
3012209bd05SWei Liu return offset - old_offset;
3022209bd05SWei Liu }
3030e2082d9SWei Liu
v9fs_iov_marshal(struct iovec * in_sg,int in_num,size_t offset,int bswap,const char * fmt,...)3040e2082d9SWei Liu ssize_t v9fs_iov_marshal(struct iovec *in_sg, int in_num, size_t offset,
3050e2082d9SWei Liu int bswap, const char *fmt, ...)
3060e2082d9SWei Liu {
3070e2082d9SWei Liu ssize_t ret;
3080e2082d9SWei Liu va_list ap;
3090e2082d9SWei Liu
3100e2082d9SWei Liu va_start(ap, fmt);
3110e2082d9SWei Liu ret = v9fs_iov_vmarshal(in_sg, in_num, offset, bswap, fmt, ap);
3120e2082d9SWei Liu va_end(ap);
3130e2082d9SWei Liu
3140e2082d9SWei Liu return ret;
3150e2082d9SWei Liu }
316