qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

9p-iov-marshal.c (10334B)


      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, *valp;
     88             valp = va_arg(ap, uint16_t *);
     89             copied = v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val));
     90             if (bswap) {
     91                 *valp = le16_to_cpu(val);
     92             } else {
     93                 *valp = val;
     94             }
     95             break;
     96         }
     97         case 'd': {
     98             uint32_t val, *valp;
     99             valp = va_arg(ap, uint32_t *);
    100             copied = v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val));
    101             if (bswap) {
    102                 *valp = le32_to_cpu(val);
    103             } else {
    104                 *valp = val;
    105             }
    106             break;
    107         }
    108         case 'q': {
    109             uint64_t val, *valp;
    110             valp = va_arg(ap, uint64_t *);
    111             copied = v9fs_unpack(&val, out_sg, out_num, offset, sizeof(val));
    112             if (bswap) {
    113                 *valp = le64_to_cpu(val);
    114             } else {
    115                 *valp = val;
    116             }
    117             break;
    118         }
    119         case 's': {
    120             V9fsString *str = va_arg(ap, V9fsString *);
    121             copied = v9fs_iov_unmarshal(out_sg, out_num, offset, bswap,
    122                                         "w", &str->size);
    123             if (copied > 0) {
    124                 offset += copied;
    125                 str->data = g_malloc(str->size + 1);
    126                 copied = v9fs_unpack(str->data, out_sg, out_num, offset,
    127                                      str->size);
    128                 if (copied >= 0) {
    129                     str->data[str->size] = 0;
    130                 } else {
    131                     v9fs_string_free(str);
    132                 }
    133             }
    134             break;
    135         }
    136         case 'Q': {
    137             V9fsQID *qidp = va_arg(ap, V9fsQID *);
    138             copied = v9fs_iov_unmarshal(out_sg, out_num, offset, bswap,
    139                                         "bdq", &qidp->type, &qidp->version,
    140                                         &qidp->path);
    141             break;
    142         }
    143         case 'S': {
    144             V9fsStat *statp = va_arg(ap, V9fsStat *);
    145             copied = v9fs_iov_unmarshal(out_sg, out_num, offset, bswap,
    146                                         "wwdQdddqsssssddd",
    147                                         &statp->size, &statp->type,
    148                                         &statp->dev, &statp->qid,
    149                                         &statp->mode, &statp->atime,
    150                                         &statp->mtime, &statp->length,
    151                                         &statp->name, &statp->uid,
    152                                         &statp->gid, &statp->muid,
    153                                         &statp->extension,
    154                                         &statp->n_uid, &statp->n_gid,
    155                                         &statp->n_muid);
    156             break;
    157         }
    158         case 'I': {
    159             V9fsIattr *iattr = va_arg(ap, V9fsIattr *);
    160             copied = v9fs_iov_unmarshal(out_sg, out_num, offset, bswap,
    161                                         "ddddqqqqq",
    162                                         &iattr->valid, &iattr->mode,
    163                                         &iattr->uid, &iattr->gid,
    164                                         &iattr->size, &iattr->atime_sec,
    165                                         &iattr->atime_nsec,
    166                                         &iattr->mtime_sec,
    167                                         &iattr->mtime_nsec);
    168             break;
    169         }
    170         default:
    171             g_assert_not_reached();
    172         }
    173         if (copied < 0) {
    174             return copied;
    175         }
    176         offset += copied;
    177     }
    178 
    179     return offset - old_offset;
    180 }
    181 
    182 ssize_t v9fs_iov_unmarshal(struct iovec *out_sg, int out_num, size_t offset,
    183                            int bswap, const char *fmt, ...)
    184 {
    185     ssize_t ret;
    186     va_list ap;
    187 
    188     va_start(ap, fmt);
    189     ret = v9fs_iov_vunmarshal(out_sg, out_num, offset, bswap, fmt, ap);
    190     va_end(ap);
    191 
    192     return ret;
    193 }
    194 
    195 ssize_t v9fs_iov_vmarshal(struct iovec *in_sg, int in_num, size_t offset,
    196                           int bswap, const char *fmt, va_list ap)
    197 {
    198     int i;
    199     ssize_t copied = 0;
    200     size_t old_offset = offset;
    201 
    202     for (i = 0; fmt[i]; i++) {
    203         switch (fmt[i]) {
    204         case 'b': {
    205             uint8_t val = va_arg(ap, int);
    206             copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
    207             break;
    208         }
    209         case 'w': {
    210             uint16_t val = va_arg(ap, int);
    211             if (bswap) {
    212                 val = cpu_to_le16(val);
    213             }
    214             copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
    215             break;
    216         }
    217         case 'd': {
    218             uint32_t val = va_arg(ap, uint32_t);
    219             if (bswap) {
    220                 val = cpu_to_le32(val);
    221             }
    222             copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
    223             break;
    224         }
    225         case 'q': {
    226             uint64_t val = va_arg(ap, uint64_t);
    227             if (bswap) {
    228                 val = cpu_to_le64(val);
    229             }
    230             copied = v9fs_pack(in_sg, in_num, offset, &val, sizeof(val));
    231             break;
    232         }
    233         case 's': {
    234             V9fsString *str = va_arg(ap, V9fsString *);
    235             copied = v9fs_iov_marshal(in_sg, in_num, offset, bswap,
    236                                       "w", str->size);
    237             if (copied > 0) {
    238                 offset += copied;
    239                 copied = v9fs_pack(in_sg, in_num, offset, str->data, str->size);
    240             }
    241             break;
    242         }
    243         case 'Q': {
    244             V9fsQID *qidp = va_arg(ap, V9fsQID *);
    245             copied = v9fs_iov_marshal(in_sg, in_num, offset, bswap, "bdq",
    246                                       qidp->type, qidp->version,
    247                                       qidp->path);
    248             break;
    249         }
    250         case 'S': {
    251             V9fsStat *statp = va_arg(ap, V9fsStat *);
    252             copied = v9fs_iov_marshal(in_sg, in_num, offset, bswap,
    253                                       "wwdQdddqsssssddd",
    254                                       statp->size, statp->type, statp->dev,
    255                                       &statp->qid, statp->mode, statp->atime,
    256                                       statp->mtime, statp->length,
    257                                       &statp->name,
    258                                       &statp->uid, &statp->gid, &statp->muid,
    259                                       &statp->extension, statp->n_uid,
    260                                       statp->n_gid, statp->n_muid);
    261             break;
    262         }
    263         case 'A': {
    264             V9fsStatDotl *statp = va_arg(ap, V9fsStatDotl *);
    265             copied = v9fs_iov_marshal(in_sg, in_num, offset, bswap,
    266                                       "qQdddqqqqqqqqqqqqqqq",
    267                                       statp->st_result_mask,
    268                                       &statp->qid, statp->st_mode,
    269                                       statp->st_uid, statp->st_gid,
    270                                       statp->st_nlink, statp->st_rdev,
    271                                       statp->st_size, statp->st_blksize,
    272                                       statp->st_blocks, statp->st_atime_sec,
    273                                       statp->st_atime_nsec,
    274                                       statp->st_mtime_sec,
    275                                       statp->st_mtime_nsec,
    276                                       statp->st_ctime_sec,
    277                                       statp->st_ctime_nsec,
    278                                       statp->st_btime_sec,
    279                                       statp->st_btime_nsec, statp->st_gen,
    280                                       statp->st_data_version);
    281             break;
    282         }
    283         default:
    284             g_assert_not_reached();
    285         }
    286         if (copied < 0) {
    287             return copied;
    288         }
    289         offset += copied;
    290     }
    291 
    292     return offset - old_offset;
    293 }
    294 
    295 ssize_t v9fs_iov_marshal(struct iovec *in_sg, int in_num, size_t offset,
    296                          int bswap, const char *fmt, ...)
    297 {
    298     ssize_t ret;
    299     va_list ap;
    300 
    301     va_start(ap, fmt);
    302     ret = v9fs_iov_vmarshal(in_sg, in_num, offset, bswap, fmt, ap);
    303     va_end(ap);
    304 
    305     return ret;
    306 }