Annotation of qemu/hw/virtio-9p.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Virtio 9p backend
                      3:  *
                      4:  * Copyright IBM, Corp. 2010
                      5:  *
                      6:  * Authors:
                      7:  *  Anthony Liguori   <[email protected]>
                      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 "virtio.h"
                     15: #include "pc.h"
                     16: #include "qemu_socket.h"
                     17: #include "virtio-9p.h"
                     18: #include "fsdev/qemu-fsdev.h"
                     19: #include "virtio-9p-debug.h"
                     20: 
                     21: int dotu = 1;
                     22: int debug_9p_pdu;
                     23: 
                     24: enum {
                     25:     Oread   = 0x00,
                     26:     Owrite  = 0x01,
                     27:     Ordwr   = 0x02,
                     28:     Oexec   = 0x03,
                     29:     Oexcl   = 0x04,
                     30:     Otrunc  = 0x10,
                     31:     Orexec  = 0x20,
                     32:     Orclose = 0x40,
                     33:     Oappend = 0x80,
                     34: };
                     35: 
                     36: static int omode_to_uflags(int8_t mode)
                     37: {
                     38:     int ret = 0;
                     39: 
                     40:     switch (mode & 3) {
                     41:     case Oread:
                     42:         ret = O_RDONLY;
                     43:         break;
                     44:     case Ordwr:
                     45:         ret = O_RDWR;
                     46:         break;
                     47:     case Owrite:
                     48:         ret = O_WRONLY;
                     49:         break;
                     50:     case Oexec:
                     51:         ret = O_RDONLY;
                     52:         break;
                     53:     }
                     54: 
                     55:     if (mode & Otrunc) {
                     56:         ret |= O_TRUNC;
                     57:     }
                     58: 
                     59:     if (mode & Oappend) {
                     60:         ret |= O_APPEND;
                     61:     }
                     62: 
                     63:     if (mode & Oexcl) {
                     64:         ret |= O_EXCL;
                     65:     }
                     66: 
                     67:     return ret;
                     68: }
                     69: 
                     70: void cred_init(FsCred *credp)
                     71: {
                     72:     credp->fc_uid = -1;
                     73:     credp->fc_gid = -1;
                     74:     credp->fc_mode = -1;
                     75:     credp->fc_rdev = -1;
                     76: }
                     77: 
                     78: static int v9fs_do_lstat(V9fsState *s, V9fsString *path, struct stat *stbuf)
                     79: {
                     80:     return s->ops->lstat(&s->ctx, path->data, stbuf);
                     81: }
                     82: 
                     83: static ssize_t v9fs_do_readlink(V9fsState *s, V9fsString *path, V9fsString *buf)
                     84: {
                     85:     ssize_t len;
                     86: 
                     87:     buf->data = qemu_malloc(1024);
                     88: 
                     89:     len = s->ops->readlink(&s->ctx, path->data, buf->data, 1024 - 1);
                     90:     if (len > -1) {
                     91:         buf->size = len;
                     92:         buf->data[len] = 0;
                     93:     }
                     94: 
                     95:     return len;
                     96: }
                     97: 
                     98: static int v9fs_do_close(V9fsState *s, int fd)
                     99: {
                    100:     return s->ops->close(&s->ctx, fd);
                    101: }
                    102: 
                    103: static int v9fs_do_closedir(V9fsState *s, DIR *dir)
                    104: {
                    105:     return s->ops->closedir(&s->ctx, dir);
                    106: }
                    107: 
                    108: static int v9fs_do_open(V9fsState *s, V9fsString *path, int flags)
                    109: {
                    110:     return s->ops->open(&s->ctx, path->data, flags);
                    111: }
                    112: 
                    113: static DIR *v9fs_do_opendir(V9fsState *s, V9fsString *path)
                    114: {
                    115:     return s->ops->opendir(&s->ctx, path->data);
                    116: }
                    117: 
                    118: static void v9fs_do_rewinddir(V9fsState *s, DIR *dir)
                    119: {
                    120:     return s->ops->rewinddir(&s->ctx, dir);
                    121: }
                    122: 
                    123: static off_t v9fs_do_telldir(V9fsState *s, DIR *dir)
                    124: {
                    125:     return s->ops->telldir(&s->ctx, dir);
                    126: }
                    127: 
                    128: static struct dirent *v9fs_do_readdir(V9fsState *s, DIR *dir)
                    129: {
                    130:     return s->ops->readdir(&s->ctx, dir);
                    131: }
                    132: 
                    133: static void v9fs_do_seekdir(V9fsState *s, DIR *dir, off_t off)
                    134: {
                    135:     return s->ops->seekdir(&s->ctx, dir, off);
                    136: }
                    137: 
                    138: static int v9fs_do_readv(V9fsState *s, int fd, const struct iovec *iov,
                    139:                             int iovcnt)
                    140: {
                    141:     return s->ops->readv(&s->ctx, fd, iov, iovcnt);
                    142: }
                    143: 
                    144: static off_t v9fs_do_lseek(V9fsState *s, int fd, off_t offset, int whence)
                    145: {
                    146:     return s->ops->lseek(&s->ctx, fd, offset, whence);
                    147: }
                    148: 
                    149: static int v9fs_do_writev(V9fsState *s, int fd, const struct iovec *iov,
                    150:                        int iovcnt)
                    151: {
                    152:     return s->ops->writev(&s->ctx, fd, iov, iovcnt);
                    153: }
                    154: 
                    155: static int v9fs_do_chmod(V9fsState *s, V9fsString *path, mode_t mode)
                    156: {
                    157:     FsCred cred;
                    158:     cred_init(&cred);
                    159:     cred.fc_mode = mode;
                    160:     return s->ops->chmod(&s->ctx, path->data, &cred);
                    161: }
                    162: 
                    163: static int v9fs_do_mknod(V9fsState *s, V9fsCreateState *vs, mode_t mode,
                    164:         dev_t dev)
                    165: {
                    166:     FsCred cred;
                    167:     cred_init(&cred);
                    168:     cred.fc_uid = vs->fidp->uid;
                    169:     cred.fc_mode = mode;
                    170:     cred.fc_rdev = dev;
                    171:     return s->ops->mknod(&s->ctx, vs->fullname.data, &cred);
                    172: }
                    173: 
                    174: static int v9fs_do_mkdir(V9fsState *s, V9fsCreateState *vs)
                    175: {
                    176:     FsCred cred;
                    177: 
                    178:     cred_init(&cred);
                    179:     cred.fc_uid = vs->fidp->uid;
                    180:     cred.fc_mode = vs->perm & 0777;
                    181: 
                    182:     return s->ops->mkdir(&s->ctx, vs->fullname.data, &cred);
                    183: }
                    184: 
                    185: static int v9fs_do_fstat(V9fsState *s, int fd, struct stat *stbuf)
                    186: {
                    187:     return s->ops->fstat(&s->ctx, fd, stbuf);
                    188: }
                    189: 
                    190: static int v9fs_do_open2(V9fsState *s, V9fsCreateState *vs)
                    191: {
                    192:     FsCred cred;
                    193:     int flags;
                    194: 
                    195:     cred_init(&cred);
                    196:     cred.fc_uid = vs->fidp->uid;
                    197:     cred.fc_mode = vs->perm & 0777;
                    198:     flags = omode_to_uflags(vs->mode) | O_CREAT;
                    199: 
                    200:     return s->ops->open2(&s->ctx, vs->fullname.data, flags, &cred);
                    201: }
                    202: 
                    203: static int v9fs_do_symlink(V9fsState *s, V9fsCreateState *vs)
                    204: {
                    205:     FsCred cred;
                    206:     cred_init(&cred);
                    207:     cred.fc_uid = vs->fidp->uid;
                    208:     cred.fc_mode = vs->perm | 0777;
                    209: 
                    210:     return s->ops->symlink(&s->ctx, vs->extension.data, vs->fullname.data,
                    211:             &cred);
                    212: }
                    213: 
                    214: static int v9fs_do_link(V9fsState *s, V9fsString *oldpath, V9fsString *newpath)
                    215: {
                    216:     return s->ops->link(&s->ctx, oldpath->data, newpath->data);
                    217: }
                    218: 
                    219: static int v9fs_do_truncate(V9fsState *s, V9fsString *path, off_t size)
                    220: {
                    221:     return s->ops->truncate(&s->ctx, path->data, size);
                    222: }
                    223: 
                    224: static int v9fs_do_rename(V9fsState *s, V9fsString *oldpath,
                    225:                             V9fsString *newpath)
                    226: {
                    227:     return s->ops->rename(&s->ctx, oldpath->data, newpath->data);
                    228: }
                    229: 
                    230: static int v9fs_do_chown(V9fsState *s, V9fsString *path, uid_t uid, gid_t gid)
                    231: {
                    232:     FsCred cred;
                    233:     cred_init(&cred);
                    234:     cred.fc_uid = uid;
                    235:     cred.fc_gid = gid;
                    236: 
                    237:     return s->ops->chown(&s->ctx, path->data, &cred);
                    238: }
                    239: 
                    240: static int v9fs_do_utime(V9fsState *s, V9fsString *path,
                    241:                             const struct utimbuf *buf)
                    242: {
                    243:     return s->ops->utime(&s->ctx, path->data, buf);
                    244: }
                    245: 
                    246: static int v9fs_do_remove(V9fsState *s, V9fsString *path)
                    247: {
                    248:     return s->ops->remove(&s->ctx, path->data);
                    249: }
                    250: 
                    251: static int v9fs_do_fsync(V9fsState *s, int fd)
                    252: {
                    253:     return s->ops->fsync(&s->ctx, fd);
                    254: }
                    255: 
                    256: static void v9fs_string_init(V9fsString *str)
                    257: {
                    258:     str->data = NULL;
                    259:     str->size = 0;
                    260: }
                    261: 
                    262: static void v9fs_string_free(V9fsString *str)
                    263: {
                    264:     qemu_free(str->data);
                    265:     str->data = NULL;
                    266:     str->size = 0;
                    267: }
                    268: 
                    269: static void v9fs_string_null(V9fsString *str)
                    270: {
                    271:     v9fs_string_free(str);
                    272: }
                    273: 
                    274: static int number_to_string(void *arg, char type)
                    275: {
                    276:     unsigned int ret = 0;
                    277: 
                    278:     switch (type) {
                    279:     case 'u': {
                    280:         unsigned int num = *(unsigned int *)arg;
                    281: 
                    282:         do {
                    283:             ret++;
                    284:             num = num/10;
                    285:         } while (num);
                    286:         break;
                    287:     }
                    288:     default:
                    289:         printf("Number_to_string: Unknown number format\n");
                    290:         return -1;
                    291:     }
                    292: 
                    293:     return ret;
                    294: }
                    295: 
                    296: static int v9fs_string_alloc_printf(char **strp, const char *fmt, va_list ap)
                    297: {
                    298:     va_list ap2;
                    299:     char *iter = (char *)fmt;
                    300:     int len = 0;
                    301:     int nr_args = 0;
                    302:     char *arg_char_ptr;
                    303:     unsigned int arg_uint;
                    304: 
                    305:     /* Find the number of %'s that denotes an argument */
                    306:     for (iter = strstr(iter, "%"); iter; iter = strstr(iter, "%")) {
                    307:         nr_args++;
                    308:         iter++;
                    309:     }
                    310: 
                    311:     len = strlen(fmt) - 2*nr_args;
                    312: 
                    313:     if (!nr_args) {
                    314:         goto alloc_print;
                    315:     }
                    316: 
                    317:     va_copy(ap2, ap);
                    318: 
                    319:     iter = (char *)fmt;
                    320: 
                    321:     /* Now parse the format string */
                    322:     for (iter = strstr(iter, "%"); iter; iter = strstr(iter, "%")) {
                    323:         iter++;
                    324:         switch (*iter) {
                    325:         case 'u':
                    326:             arg_uint = va_arg(ap2, unsigned int);
                    327:             len += number_to_string((void *)&arg_uint, 'u');
                    328:             break;
                    329:         case 's':
                    330:             arg_char_ptr = va_arg(ap2, char *);
                    331:             len += strlen(arg_char_ptr);
                    332:             break;
                    333:         case 'c':
                    334:             len += 1;
                    335:             break;
                    336:         default:
                    337:             fprintf(stderr,
                    338:                    "v9fs_string_alloc_printf:Incorrect format %c", *iter);
                    339:             return -1;
                    340:         }
                    341:         iter++;
                    342:     }
                    343: 
                    344: alloc_print:
                    345:     *strp = qemu_malloc((len + 1) * sizeof(**strp));
                    346: 
                    347:     return vsprintf(*strp, fmt, ap);
                    348: }
                    349: 
                    350: static void v9fs_string_sprintf(V9fsString *str, const char *fmt, ...)
                    351: {
                    352:     va_list ap;
                    353:     int err;
                    354: 
                    355:     v9fs_string_free(str);
                    356: 
                    357:     va_start(ap, fmt);
                    358:     err = v9fs_string_alloc_printf(&str->data, fmt, ap);
                    359:     BUG_ON(err == -1);
                    360:     va_end(ap);
                    361: 
                    362:     str->size = err;
                    363: }
                    364: 
                    365: static void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs)
                    366: {
                    367:     v9fs_string_free(lhs);
                    368:     v9fs_string_sprintf(lhs, "%s", rhs->data);
                    369: }
                    370: 
                    371: static size_t v9fs_string_size(V9fsString *str)
                    372: {
                    373:     return str->size;
                    374: }
                    375: 
                    376: static V9fsFidState *lookup_fid(V9fsState *s, int32_t fid)
                    377: {
                    378:     V9fsFidState *f;
                    379: 
                    380:     for (f = s->fid_list; f; f = f->next) {
                    381:         if (f->fid == fid) {
                    382:             return f;
                    383:         }
                    384:     }
                    385: 
                    386:     return NULL;
                    387: }
                    388: 
                    389: static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid)
                    390: {
                    391:     V9fsFidState *f;
                    392: 
                    393:     f = lookup_fid(s, fid);
                    394:     if (f) {
                    395:         return NULL;
                    396:     }
                    397: 
                    398:     f = qemu_mallocz(sizeof(V9fsFidState));
                    399: 
                    400:     f->fid = fid;
                    401:     f->fd = -1;
                    402:     f->dir = NULL;
                    403: 
                    404:     f->next = s->fid_list;
                    405:     s->fid_list = f;
                    406: 
                    407:     return f;
                    408: }
                    409: 
                    410: static int free_fid(V9fsState *s, int32_t fid)
                    411: {
                    412:     V9fsFidState **fidpp, *fidp;
                    413: 
                    414:     for (fidpp = &s->fid_list; *fidpp; fidpp = &(*fidpp)->next) {
                    415:         if ((*fidpp)->fid == fid) {
                    416:             break;
                    417:         }
                    418:     }
                    419: 
                    420:     if (*fidpp == NULL) {
                    421:         return -ENOENT;
                    422:     }
                    423: 
                    424:     fidp = *fidpp;
                    425:     *fidpp = fidp->next;
                    426: 
                    427:     if (fidp->fd != -1) {
                    428:         v9fs_do_close(s, fidp->fd);
                    429:     }
                    430:     if (fidp->dir) {
                    431:         v9fs_do_closedir(s, fidp->dir);
                    432:     }
                    433:     v9fs_string_free(&fidp->path);
                    434:     qemu_free(fidp);
                    435: 
                    436:     return 0;
                    437: }
                    438: 
                    439: #define P9_QID_TYPE_DIR         0x80
                    440: #define P9_QID_TYPE_SYMLINK     0x02
                    441: 
                    442: #define P9_STAT_MODE_DIR        0x80000000
                    443: #define P9_STAT_MODE_APPEND     0x40000000
                    444: #define P9_STAT_MODE_EXCL       0x20000000
                    445: #define P9_STAT_MODE_MOUNT      0x10000000
                    446: #define P9_STAT_MODE_AUTH       0x08000000
                    447: #define P9_STAT_MODE_TMP        0x04000000
                    448: #define P9_STAT_MODE_SYMLINK    0x02000000
                    449: #define P9_STAT_MODE_LINK       0x01000000
                    450: #define P9_STAT_MODE_DEVICE     0x00800000
                    451: #define P9_STAT_MODE_NAMED_PIPE 0x00200000
                    452: #define P9_STAT_MODE_SOCKET     0x00100000
                    453: #define P9_STAT_MODE_SETUID     0x00080000
                    454: #define P9_STAT_MODE_SETGID     0x00040000
                    455: #define P9_STAT_MODE_SETVTX     0x00010000
                    456: 
                    457: #define P9_STAT_MODE_TYPE_BITS (P9_STAT_MODE_DIR |          \
                    458:                                 P9_STAT_MODE_SYMLINK |      \
                    459:                                 P9_STAT_MODE_LINK |         \
                    460:                                 P9_STAT_MODE_DEVICE |       \
                    461:                                 P9_STAT_MODE_NAMED_PIPE |   \
                    462:                                 P9_STAT_MODE_SOCKET)
                    463: 
                    464: /* This is the algorithm from ufs in spfs */
                    465: static void stat_to_qid(const struct stat *stbuf, V9fsQID *qidp)
                    466: {
                    467:     size_t size;
                    468: 
                    469:     size = MIN(sizeof(stbuf->st_ino), sizeof(qidp->path));
                    470:     memcpy(&qidp->path, &stbuf->st_ino, size);
                    471:     qidp->version = stbuf->st_mtime ^ (stbuf->st_size << 8);
                    472:     qidp->type = 0;
                    473:     if (S_ISDIR(stbuf->st_mode)) {
                    474:         qidp->type |= P9_QID_TYPE_DIR;
                    475:     }
                    476:     if (S_ISLNK(stbuf->st_mode)) {
                    477:         qidp->type |= P9_QID_TYPE_SYMLINK;
                    478:     }
                    479: }
                    480: 
                    481: static int fid_to_qid(V9fsState *s, V9fsFidState *fidp, V9fsQID *qidp)
                    482: {
                    483:     struct stat stbuf;
                    484:     int err;
                    485: 
                    486:     err = v9fs_do_lstat(s, &fidp->path, &stbuf);
                    487:     if (err) {
                    488:         return err;
                    489:     }
                    490: 
                    491:     stat_to_qid(&stbuf, qidp);
                    492:     return 0;
                    493: }
                    494: 
                    495: static V9fsPDU *alloc_pdu(V9fsState *s)
                    496: {
                    497:     V9fsPDU *pdu = NULL;
                    498: 
                    499:     if (!QLIST_EMPTY(&s->free_list)) {
                    500:        pdu = QLIST_FIRST(&s->free_list);
                    501:        QLIST_REMOVE(pdu, next);
                    502:     }
                    503:     return pdu;
                    504: }
                    505: 
                    506: static void free_pdu(V9fsState *s, V9fsPDU *pdu)
                    507: {
                    508:     if (pdu) {
                    509:        QLIST_INSERT_HEAD(&s->free_list, pdu, next);
                    510:     }
                    511: }
                    512: 
                    513: size_t pdu_packunpack(void *addr, struct iovec *sg, int sg_count,
                    514:                         size_t offset, size_t size, int pack)
                    515: {
                    516:     int i = 0;
                    517:     size_t copied = 0;
                    518: 
                    519:     for (i = 0; size && i < sg_count; i++) {
                    520:         size_t len;
                    521:         if (offset >= sg[i].iov_len) {
                    522:             /* skip this sg */
                    523:             offset -= sg[i].iov_len;
                    524:             continue;
                    525:         } else {
                    526:             len = MIN(sg[i].iov_len - offset, size);
                    527:             if (pack) {
                    528:                 memcpy(sg[i].iov_base + offset, addr, len);
                    529:             } else {
                    530:                 memcpy(addr, sg[i].iov_base + offset, len);
                    531:             }
                    532:             size -= len;
                    533:             copied += len;
                    534:             addr += len;
                    535:             if (size) {
                    536:                 offset = 0;
                    537:                 continue;
                    538:             }
                    539:         }
                    540:     }
                    541: 
                    542:     return copied;
                    543: }
                    544: 
                    545: static size_t pdu_unpack(void *dst, V9fsPDU *pdu, size_t offset, size_t size)
                    546: {
                    547:     return pdu_packunpack(dst, pdu->elem.out_sg, pdu->elem.out_num,
                    548:                          offset, size, 0);
                    549: }
                    550: 
                    551: static size_t pdu_pack(V9fsPDU *pdu, size_t offset, const void *src,
                    552:                         size_t size)
                    553: {
                    554:     return pdu_packunpack((void *)src, pdu->elem.in_sg, pdu->elem.in_num,
                    555:                              offset, size, 1);
                    556: }
                    557: 
                    558: static int pdu_copy_sg(V9fsPDU *pdu, size_t offset, int rx, struct iovec *sg)
                    559: {
                    560:     size_t pos = 0;
                    561:     int i, j;
                    562:     struct iovec *src_sg;
                    563:     unsigned int num;
                    564: 
                    565:     if (rx) {
                    566:         src_sg = pdu->elem.in_sg;
                    567:         num = pdu->elem.in_num;
                    568:     } else {
                    569:         src_sg = pdu->elem.out_sg;
                    570:         num = pdu->elem.out_num;
                    571:     }
                    572: 
                    573:     j = 0;
                    574:     for (i = 0; i < num; i++) {
                    575:         if (offset <= pos) {
                    576:             sg[j].iov_base = src_sg[i].iov_base;
                    577:             sg[j].iov_len = src_sg[i].iov_len;
                    578:             j++;
                    579:         } else if (offset < (src_sg[i].iov_len + pos)) {
                    580:             sg[j].iov_base = src_sg[i].iov_base;
                    581:             sg[j].iov_len = src_sg[i].iov_len;
                    582:             sg[j].iov_base += (offset - pos);
                    583:             sg[j].iov_len -= (offset - pos);
                    584:             j++;
                    585:         }
                    586:         pos += src_sg[i].iov_len;
                    587:     }
                    588: 
                    589:     return j;
                    590: }
                    591: 
                    592: static size_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
                    593: {
                    594:     size_t old_offset = offset;
                    595:     va_list ap;
                    596:     int i;
                    597: 
                    598:     va_start(ap, fmt);
                    599:     for (i = 0; fmt[i]; i++) {
                    600:         switch (fmt[i]) {
                    601:         case 'b': {
                    602:             uint8_t *valp = va_arg(ap, uint8_t *);
                    603:             offset += pdu_unpack(valp, pdu, offset, sizeof(*valp));
                    604:             break;
                    605:         }
                    606:         case 'w': {
                    607:             uint16_t val, *valp;
                    608:             valp = va_arg(ap, uint16_t *);
                    609:             val = le16_to_cpupu(valp);
                    610:             offset += pdu_unpack(&val, pdu, offset, sizeof(val));
                    611:             *valp = val;
                    612:             break;
                    613:         }
                    614:         case 'd': {
                    615:             uint32_t val, *valp;
                    616:             valp = va_arg(ap, uint32_t *);
                    617:             val = le32_to_cpupu(valp);
                    618:             offset += pdu_unpack(&val, pdu, offset, sizeof(val));
                    619:             *valp = val;
                    620:             break;
                    621:         }
                    622:         case 'q': {
                    623:             uint64_t val, *valp;
                    624:             valp = va_arg(ap, uint64_t *);
                    625:             val = le64_to_cpup(valp);
                    626:             offset += pdu_unpack(&val, pdu, offset, sizeof(val));
                    627:             *valp = val;
                    628:             break;
                    629:         }
                    630:         case 'v': {
                    631:             struct iovec *iov = va_arg(ap, struct iovec *);
                    632:             int *iovcnt = va_arg(ap, int *);
                    633:             *iovcnt = pdu_copy_sg(pdu, offset, 0, iov);
                    634:             break;
                    635:         }
                    636:         case 's': {
                    637:             V9fsString *str = va_arg(ap, V9fsString *);
                    638:             offset += pdu_unmarshal(pdu, offset, "w", &str->size);
                    639:             /* FIXME: sanity check str->size */
                    640:             str->data = qemu_malloc(str->size + 1);
                    641:             offset += pdu_unpack(str->data, pdu, offset, str->size);
                    642:             str->data[str->size] = 0;
                    643:             break;
                    644:         }
                    645:         case 'Q': {
                    646:             V9fsQID *qidp = va_arg(ap, V9fsQID *);
                    647:             offset += pdu_unmarshal(pdu, offset, "bdq",
                    648:                         &qidp->type, &qidp->version, &qidp->path);
                    649:             break;
                    650:         }
                    651:         case 'S': {
                    652:             V9fsStat *statp = va_arg(ap, V9fsStat *);
                    653:             offset += pdu_unmarshal(pdu, offset, "wwdQdddqsssssddd",
                    654:                         &statp->size, &statp->type, &statp->dev,
                    655:                         &statp->qid, &statp->mode, &statp->atime,
                    656:                         &statp->mtime, &statp->length,
                    657:                         &statp->name, &statp->uid, &statp->gid,
                    658:                         &statp->muid, &statp->extension,
                    659:                         &statp->n_uid, &statp->n_gid,
                    660:                         &statp->n_muid);
                    661:             break;
                    662:         }
                    663:         default:
                    664:             break;
                    665:         }
                    666:     }
                    667: 
                    668:     va_end(ap);
                    669: 
                    670:     return offset - old_offset;
                    671: }
                    672: 
                    673: static size_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
                    674: {
                    675:     size_t old_offset = offset;
                    676:     va_list ap;
                    677:     int i;
                    678: 
                    679:     va_start(ap, fmt);
                    680:     for (i = 0; fmt[i]; i++) {
                    681:         switch (fmt[i]) {
                    682:         case 'b': {
                    683:             uint8_t val = va_arg(ap, int);
                    684:             offset += pdu_pack(pdu, offset, &val, sizeof(val));
                    685:             break;
                    686:         }
                    687:         case 'w': {
                    688:             uint16_t val;
                    689:             cpu_to_le16w(&val, va_arg(ap, int));
                    690:             offset += pdu_pack(pdu, offset, &val, sizeof(val));
                    691:             break;
                    692:         }
                    693:         case 'd': {
                    694:             uint32_t val;
                    695:             cpu_to_le32w(&val, va_arg(ap, uint32_t));
                    696:             offset += pdu_pack(pdu, offset, &val, sizeof(val));
                    697:             break;
                    698:         }
                    699:         case 'q': {
                    700:             uint64_t val;
                    701:             cpu_to_le64w(&val, va_arg(ap, uint64_t));
                    702:             offset += pdu_pack(pdu, offset, &val, sizeof(val));
                    703:             break;
                    704:         }
                    705:         case 'v': {
                    706:             struct iovec *iov = va_arg(ap, struct iovec *);
                    707:             int *iovcnt = va_arg(ap, int *);
                    708:             *iovcnt = pdu_copy_sg(pdu, offset, 1, iov);
                    709:             break;
                    710:         }
                    711:         case 's': {
                    712:             V9fsString *str = va_arg(ap, V9fsString *);
                    713:             offset += pdu_marshal(pdu, offset, "w", str->size);
                    714:             offset += pdu_pack(pdu, offset, str->data, str->size);
                    715:             break;
                    716:         }
                    717:         case 'Q': {
                    718:             V9fsQID *qidp = va_arg(ap, V9fsQID *);
                    719:             offset += pdu_marshal(pdu, offset, "bdq",
                    720:                         qidp->type, qidp->version, qidp->path);
                    721:             break;
                    722:         }
                    723:         case 'S': {
                    724:             V9fsStat *statp = va_arg(ap, V9fsStat *);
                    725:             offset += pdu_marshal(pdu, offset, "wwdQdddqsssssddd",
                    726:                         statp->size, statp->type, statp->dev,
                    727:                         &statp->qid, statp->mode, statp->atime,
                    728:                         statp->mtime, statp->length, &statp->name,
                    729:                         &statp->uid, &statp->gid, &statp->muid,
                    730:                         &statp->extension, statp->n_uid,
                    731:                         statp->n_gid, statp->n_muid);
                    732:             break;
                    733:         }
                    734:         default:
                    735:             break;
                    736:         }
                    737:     }
                    738:     va_end(ap);
                    739: 
                    740:     return offset - old_offset;
                    741: }
                    742: 
                    743: static void complete_pdu(V9fsState *s, V9fsPDU *pdu, ssize_t len)
                    744: {
                    745:     int8_t id = pdu->id + 1; /* Response */
                    746: 
                    747:     if (len < 0) {
                    748:         V9fsString str;
                    749:         int err = -len;
                    750: 
                    751:         str.data = strerror(err);
                    752:         str.size = strlen(str.data);
                    753: 
                    754:         len = 7;
                    755:         len += pdu_marshal(pdu, len, "s", &str);
                    756:         if (dotu) {
                    757:             len += pdu_marshal(pdu, len, "d", err);
                    758:         }
                    759: 
                    760:         id = P9_RERROR;
                    761:     }
                    762: 
                    763:     /* fill out the header */
                    764:     pdu_marshal(pdu, 0, "dbw", (int32_t)len, id, pdu->tag);
                    765: 
                    766:     /* keep these in sync */
                    767:     pdu->size = len;
                    768:     pdu->id = id;
                    769: 
                    770:     /* push onto queue and notify */
                    771:     virtqueue_push(s->vq, &pdu->elem, len);
                    772: 
                    773:     /* FIXME: we should batch these completions */
                    774:     virtio_notify(&s->vdev, s->vq);
                    775: 
                    776:     free_pdu(s, pdu);
                    777: }
                    778: 
                    779: static mode_t v9mode_to_mode(uint32_t mode, V9fsString *extension)
                    780: {
                    781:     mode_t ret;
                    782: 
                    783:     ret = mode & 0777;
                    784:     if (mode & P9_STAT_MODE_DIR) {
                    785:         ret |= S_IFDIR;
                    786:     }
                    787: 
                    788:     if (dotu) {
                    789:         if (mode & P9_STAT_MODE_SYMLINK) {
                    790:             ret |= S_IFLNK;
                    791:         }
                    792:         if (mode & P9_STAT_MODE_SOCKET) {
                    793:             ret |= S_IFSOCK;
                    794:         }
                    795:         if (mode & P9_STAT_MODE_NAMED_PIPE) {
                    796:             ret |= S_IFIFO;
                    797:         }
                    798:         if (mode & P9_STAT_MODE_DEVICE) {
                    799:             if (extension && extension->data[0] == 'c') {
                    800:                 ret |= S_IFCHR;
                    801:             } else {
                    802:                 ret |= S_IFBLK;
                    803:             }
                    804:         }
                    805:     }
                    806: 
                    807:     if (!(ret&~0777)) {
                    808:         ret |= S_IFREG;
                    809:     }
                    810: 
                    811:     if (mode & P9_STAT_MODE_SETUID) {
                    812:         ret |= S_ISUID;
                    813:     }
                    814:     if (mode & P9_STAT_MODE_SETGID) {
                    815:         ret |= S_ISGID;
                    816:     }
                    817:     if (mode & P9_STAT_MODE_SETVTX) {
                    818:         ret |= S_ISVTX;
                    819:     }
                    820: 
                    821:     return ret;
                    822: }
                    823: 
                    824: static int donttouch_stat(V9fsStat *stat)
                    825: {
                    826:     if (stat->type == -1 &&
                    827:         stat->dev == -1 &&
                    828:         stat->qid.type == -1 &&
                    829:         stat->qid.version == -1 &&
                    830:         stat->qid.path == -1 &&
                    831:         stat->mode == -1 &&
                    832:         stat->atime == -1 &&
                    833:         stat->mtime == -1 &&
                    834:         stat->length == -1 &&
                    835:         !stat->name.size &&
                    836:         !stat->uid.size &&
                    837:         !stat->gid.size &&
                    838:         !stat->muid.size &&
                    839:         stat->n_uid == -1 &&
                    840:         stat->n_gid == -1 &&
                    841:         stat->n_muid == -1) {
                    842:         return 1;
                    843:     }
                    844: 
                    845:     return 0;
                    846: }
                    847: 
                    848: static void v9fs_stat_free(V9fsStat *stat)
                    849: {
                    850:     v9fs_string_free(&stat->name);
                    851:     v9fs_string_free(&stat->uid);
                    852:     v9fs_string_free(&stat->gid);
                    853:     v9fs_string_free(&stat->muid);
                    854:     v9fs_string_free(&stat->extension);
                    855: }
                    856: 
                    857: static uint32_t stat_to_v9mode(const struct stat *stbuf)
                    858: {
                    859:     uint32_t mode;
                    860: 
                    861:     mode = stbuf->st_mode & 0777;
                    862:     if (S_ISDIR(stbuf->st_mode)) {
                    863:         mode |= P9_STAT_MODE_DIR;
                    864:     }
                    865: 
                    866:     if (dotu) {
                    867:         if (S_ISLNK(stbuf->st_mode)) {
                    868:             mode |= P9_STAT_MODE_SYMLINK;
                    869:         }
                    870: 
                    871:         if (S_ISSOCK(stbuf->st_mode)) {
                    872:             mode |= P9_STAT_MODE_SOCKET;
                    873:         }
                    874: 
                    875:         if (S_ISFIFO(stbuf->st_mode)) {
                    876:             mode |= P9_STAT_MODE_NAMED_PIPE;
                    877:         }
                    878: 
                    879:         if (S_ISBLK(stbuf->st_mode) || S_ISCHR(stbuf->st_mode)) {
                    880:             mode |= P9_STAT_MODE_DEVICE;
                    881:         }
                    882: 
                    883:         if (stbuf->st_mode & S_ISUID) {
                    884:             mode |= P9_STAT_MODE_SETUID;
                    885:         }
                    886: 
                    887:         if (stbuf->st_mode & S_ISGID) {
                    888:             mode |= P9_STAT_MODE_SETGID;
                    889:         }
                    890: 
                    891:         if (stbuf->st_mode & S_ISVTX) {
                    892:             mode |= P9_STAT_MODE_SETVTX;
                    893:         }
                    894:     }
                    895: 
                    896:     return mode;
                    897: }
                    898: 
                    899: static int stat_to_v9stat(V9fsState *s, V9fsString *name,
                    900:                             const struct stat *stbuf,
                    901:                             V9fsStat *v9stat)
                    902: {
                    903:     int err;
                    904:     const char *str;
                    905: 
                    906:     memset(v9stat, 0, sizeof(*v9stat));
                    907: 
                    908:     stat_to_qid(stbuf, &v9stat->qid);
                    909:     v9stat->mode = stat_to_v9mode(stbuf);
                    910:     v9stat->atime = stbuf->st_atime;
                    911:     v9stat->mtime = stbuf->st_mtime;
                    912:     v9stat->length = stbuf->st_size;
                    913: 
                    914:     v9fs_string_null(&v9stat->uid);
                    915:     v9fs_string_null(&v9stat->gid);
                    916:     v9fs_string_null(&v9stat->muid);
                    917: 
                    918:     if (dotu) {
                    919:         v9stat->n_uid = stbuf->st_uid;
                    920:         v9stat->n_gid = stbuf->st_gid;
                    921:         v9stat->n_muid = 0;
                    922: 
                    923:         v9fs_string_null(&v9stat->extension);
                    924: 
                    925:         if (v9stat->mode & P9_STAT_MODE_SYMLINK) {
                    926:             err = v9fs_do_readlink(s, name, &v9stat->extension);
                    927:             if (err == -1) {
                    928:                 err = -errno;
                    929:                 return err;
                    930:             }
                    931:             v9stat->extension.data[err] = 0;
                    932:             v9stat->extension.size = err;
                    933:         } else if (v9stat->mode & P9_STAT_MODE_DEVICE) {
                    934:             v9fs_string_sprintf(&v9stat->extension, "%c %u %u",
                    935:                     S_ISCHR(stbuf->st_mode) ? 'c' : 'b',
                    936:                     major(stbuf->st_rdev), minor(stbuf->st_rdev));
                    937:         } else if (S_ISDIR(stbuf->st_mode) || S_ISREG(stbuf->st_mode)) {
                    938:             v9fs_string_sprintf(&v9stat->extension, "%s %u",
                    939:                     "HARDLINKCOUNT", stbuf->st_nlink);
                    940:         }
                    941:     }
                    942: 
                    943:     str = strrchr(name->data, '/');
                    944:     if (str) {
                    945:         str += 1;
                    946:     } else {
                    947:         str = name->data;
                    948:     }
                    949: 
                    950:     v9fs_string_sprintf(&v9stat->name, "%s", str);
                    951: 
                    952:     v9stat->size = 61 +
                    953:         v9fs_string_size(&v9stat->name) +
                    954:         v9fs_string_size(&v9stat->uid) +
                    955:         v9fs_string_size(&v9stat->gid) +
                    956:         v9fs_string_size(&v9stat->muid) +
                    957:         v9fs_string_size(&v9stat->extension);
                    958:     return 0;
                    959: }
                    960: 
                    961: static struct iovec *adjust_sg(struct iovec *sg, int len, int *iovcnt)
                    962: {
                    963:     while (len && *iovcnt) {
                    964:         if (len < sg->iov_len) {
                    965:             sg->iov_len -= len;
                    966:             sg->iov_base += len;
                    967:             len = 0;
                    968:         } else {
                    969:             len -= sg->iov_len;
                    970:             sg++;
                    971:             *iovcnt -= 1;
                    972:         }
                    973:     }
                    974: 
                    975:     return sg;
                    976: }
                    977: 
                    978: static struct iovec *cap_sg(struct iovec *sg, int cap, int *cnt)
                    979: {
                    980:     int i;
                    981:     int total = 0;
                    982: 
                    983:     for (i = 0; i < *cnt; i++) {
                    984:         if ((total + sg[i].iov_len) > cap) {
                    985:             sg[i].iov_len -= ((total + sg[i].iov_len) - cap);
                    986:             i++;
                    987:             break;
                    988:         }
                    989:         total += sg[i].iov_len;
                    990:     }
                    991: 
                    992:     *cnt = i;
                    993: 
                    994:     return sg;
                    995: }
                    996: 
                    997: static void print_sg(struct iovec *sg, int cnt)
                    998: {
                    999:     int i;
                   1000: 
                   1001:     printf("sg[%d]: {", cnt);
                   1002:     for (i = 0; i < cnt; i++) {
                   1003:         if (i) {
                   1004:             printf(", ");
                   1005:         }
                   1006:         printf("(%p, %zd)", sg[i].iov_base, sg[i].iov_len);
                   1007:     }
                   1008:     printf("}\n");
                   1009: }
                   1010: 
                   1011: static void v9fs_fix_path(V9fsString *dst, V9fsString *src, int len)
                   1012: {
                   1013:     V9fsString str;
                   1014:     v9fs_string_init(&str);
                   1015:     v9fs_string_copy(&str, dst);
                   1016:     v9fs_string_sprintf(dst, "%s%s", src->data, str.data+len);
                   1017:     v9fs_string_free(&str);
                   1018: }
                   1019: 
                   1020: static void v9fs_version(V9fsState *s, V9fsPDU *pdu)
                   1021: {
                   1022:     int32_t msize;
                   1023:     V9fsString version;
                   1024:     size_t offset = 7;
                   1025: 
                   1026:     pdu_unmarshal(pdu, offset, "ds", &msize, &version);
                   1027: 
                   1028:     if (strcmp(version.data, "9P2000.u")) {
                   1029:         v9fs_string_sprintf(&version, "unknown");
                   1030:     }
                   1031: 
                   1032:     offset += pdu_marshal(pdu, offset, "ds", msize, &version);
                   1033:     complete_pdu(s, pdu, offset);
                   1034: 
                   1035:     v9fs_string_free(&version);
                   1036: }
                   1037: 
                   1038: static void v9fs_attach(V9fsState *s, V9fsPDU *pdu)
                   1039: {
                   1040:     int32_t fid, afid, n_uname;
                   1041:     V9fsString uname, aname;
                   1042:     V9fsFidState *fidp;
                   1043:     V9fsQID qid;
                   1044:     size_t offset = 7;
                   1045:     ssize_t err;
                   1046: 
                   1047:     pdu_unmarshal(pdu, offset, "ddssd", &fid, &afid, &uname, &aname, &n_uname);
                   1048: 
                   1049:     fidp = alloc_fid(s, fid);
                   1050:     if (fidp == NULL) {
                   1051:         err = -EINVAL;
                   1052:         goto out;
                   1053:     }
                   1054: 
                   1055:     fidp->uid = n_uname;
                   1056: 
                   1057:     v9fs_string_sprintf(&fidp->path, "%s", "/");
                   1058:     err = fid_to_qid(s, fidp, &qid);
                   1059:     if (err) {
                   1060:         err = -EINVAL;
                   1061:         free_fid(s, fid);
                   1062:         goto out;
                   1063:     }
                   1064: 
                   1065:     offset += pdu_marshal(pdu, offset, "Q", &qid);
                   1066: 
                   1067:     err = offset;
                   1068: out:
                   1069:     complete_pdu(s, pdu, err);
                   1070:     v9fs_string_free(&uname);
                   1071:     v9fs_string_free(&aname);
                   1072: }
                   1073: 
                   1074: static void v9fs_stat_post_lstat(V9fsState *s, V9fsStatState *vs, int err)
                   1075: {
                   1076:     if (err == -1) {
                   1077:         err = -errno;
                   1078:         goto out;
                   1079:     }
                   1080: 
                   1081:     err = stat_to_v9stat(s, &vs->fidp->path, &vs->stbuf, &vs->v9stat);
                   1082:     if (err) {
                   1083:         goto out;
                   1084:     }
                   1085:     vs->offset += pdu_marshal(vs->pdu, vs->offset, "wS", 0, &vs->v9stat);
                   1086:     err = vs->offset;
                   1087: 
                   1088: out:
                   1089:     complete_pdu(s, vs->pdu, err);
                   1090:     v9fs_stat_free(&vs->v9stat);
                   1091:     qemu_free(vs);
                   1092: }
                   1093: 
                   1094: static void v9fs_stat(V9fsState *s, V9fsPDU *pdu)
                   1095: {
                   1096:     int32_t fid;
                   1097:     V9fsStatState *vs;
                   1098:     ssize_t err = 0;
                   1099: 
                   1100:     vs = qemu_malloc(sizeof(*vs));
                   1101:     vs->pdu = pdu;
                   1102:     vs->offset = 7;
                   1103: 
                   1104:     memset(&vs->v9stat, 0, sizeof(vs->v9stat));
                   1105: 
                   1106:     pdu_unmarshal(vs->pdu, vs->offset, "d", &fid);
                   1107: 
                   1108:     vs->fidp = lookup_fid(s, fid);
                   1109:     if (vs->fidp == NULL) {
                   1110:         err = -ENOENT;
                   1111:         goto out;
                   1112:     }
                   1113: 
                   1114:     err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
                   1115:     v9fs_stat_post_lstat(s, vs, err);
                   1116:     return;
                   1117: 
                   1118: out:
                   1119:     complete_pdu(s, vs->pdu, err);
                   1120:     v9fs_stat_free(&vs->v9stat);
                   1121:     qemu_free(vs);
                   1122: }
                   1123: 
                   1124: static void v9fs_walk_complete(V9fsState *s, V9fsWalkState *vs, int err)
                   1125: {
                   1126:     complete_pdu(s, vs->pdu, err);
                   1127: 
                   1128:     if (vs->nwnames) {
                   1129:         for (vs->name_idx = 0; vs->name_idx < vs->nwnames; vs->name_idx++) {
                   1130:             v9fs_string_free(&vs->wnames[vs->name_idx]);
                   1131:         }
                   1132: 
                   1133:         qemu_free(vs->wnames);
                   1134:         qemu_free(vs->qids);
                   1135:     }
                   1136: }
                   1137: 
                   1138: static void v9fs_walk_marshal(V9fsWalkState *vs)
                   1139: {
                   1140:     int i;
                   1141:     vs->offset = 7;
                   1142:     vs->offset += pdu_marshal(vs->pdu, vs->offset, "w", vs->nwnames);
                   1143: 
                   1144:     for (i = 0; i < vs->nwnames; i++) {
                   1145:         vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qids[i]);
                   1146:     }
                   1147: }
                   1148: 
                   1149: static void v9fs_walk_post_newfid_lstat(V9fsState *s, V9fsWalkState *vs,
                   1150:                                                                 int err)
                   1151: {
                   1152:     if (err == -1) {
                   1153:         free_fid(s, vs->newfidp->fid);
                   1154:         v9fs_string_free(&vs->path);
                   1155:         err = -ENOENT;
                   1156:         goto out;
                   1157:     }
                   1158: 
                   1159:     stat_to_qid(&vs->stbuf, &vs->qids[vs->name_idx]);
                   1160: 
                   1161:     vs->name_idx++;
                   1162:     if (vs->name_idx < vs->nwnames) {
                   1163:         v9fs_string_sprintf(&vs->path, "%s/%s", vs->newfidp->path.data,
                   1164:                                             vs->wnames[vs->name_idx].data);
                   1165:         v9fs_string_copy(&vs->newfidp->path, &vs->path);
                   1166: 
                   1167:         err = v9fs_do_lstat(s, &vs->newfidp->path, &vs->stbuf);
                   1168:         v9fs_walk_post_newfid_lstat(s, vs, err);
                   1169:         return;
                   1170:     }
                   1171: 
                   1172:     v9fs_string_free(&vs->path);
                   1173:     v9fs_walk_marshal(vs);
                   1174:     err = vs->offset;
                   1175: out:
                   1176:     v9fs_walk_complete(s, vs, err);
                   1177: }
                   1178: 
                   1179: static void v9fs_walk_post_oldfid_lstat(V9fsState *s, V9fsWalkState *vs,
                   1180:         int err)
                   1181: {
                   1182:     if (err == -1) {
                   1183:         v9fs_string_free(&vs->path);
                   1184:         err = -ENOENT;
                   1185:         goto out;
                   1186:     }
                   1187: 
                   1188:     stat_to_qid(&vs->stbuf, &vs->qids[vs->name_idx]);
                   1189:     vs->name_idx++;
                   1190:     if (vs->name_idx < vs->nwnames) {
                   1191: 
                   1192:         v9fs_string_sprintf(&vs->path, "%s/%s",
                   1193:                 vs->fidp->path.data, vs->wnames[vs->name_idx].data);
                   1194:         v9fs_string_copy(&vs->fidp->path, &vs->path);
                   1195: 
                   1196:         err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
                   1197:         v9fs_walk_post_oldfid_lstat(s, vs, err);
                   1198:         return;
                   1199:     }
                   1200: 
                   1201:     v9fs_string_free(&vs->path);
                   1202:     v9fs_walk_marshal(vs);
                   1203:     err = vs->offset;
                   1204: out:
                   1205:     v9fs_walk_complete(s, vs, err);
                   1206: }
                   1207: 
                   1208: static void v9fs_walk(V9fsState *s, V9fsPDU *pdu)
                   1209: {
                   1210:     int32_t fid, newfid;
                   1211:     V9fsWalkState *vs;
                   1212:     int err = 0;
                   1213:     int i;
                   1214: 
                   1215:     vs = qemu_malloc(sizeof(*vs));
                   1216:     vs->pdu = pdu;
                   1217:     vs->wnames = NULL;
                   1218:     vs->qids = NULL;
                   1219:     vs->offset = 7;
                   1220: 
                   1221:     vs->offset += pdu_unmarshal(vs->pdu, vs->offset, "ddw", &fid,
                   1222:                                             &newfid, &vs->nwnames);
                   1223: 
                   1224:     if (vs->nwnames) {
                   1225:         vs->wnames = qemu_mallocz(sizeof(vs->wnames[0]) * vs->nwnames);
                   1226: 
                   1227:         vs->qids = qemu_mallocz(sizeof(vs->qids[0]) * vs->nwnames);
                   1228: 
                   1229:         for (i = 0; i < vs->nwnames; i++) {
                   1230:             vs->offset += pdu_unmarshal(vs->pdu, vs->offset, "s",
                   1231:                                             &vs->wnames[i]);
                   1232:         }
                   1233:     }
                   1234: 
                   1235:     vs->fidp = lookup_fid(s, fid);
                   1236:     if (vs->fidp == NULL) {
                   1237:         err = -ENOENT;
                   1238:         goto out;
                   1239:     }
                   1240: 
                   1241:     /* FIXME: is this really valid? */
                   1242:     if (fid == newfid) {
                   1243: 
                   1244:         BUG_ON(vs->fidp->fd != -1);
                   1245:         BUG_ON(vs->fidp->dir);
                   1246:         v9fs_string_init(&vs->path);
                   1247:         vs->name_idx = 0;
                   1248: 
                   1249:         if (vs->name_idx < vs->nwnames) {
                   1250:             v9fs_string_sprintf(&vs->path, "%s/%s",
                   1251:                 vs->fidp->path.data, vs->wnames[vs->name_idx].data);
                   1252:             v9fs_string_copy(&vs->fidp->path, &vs->path);
                   1253: 
                   1254:             err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
                   1255:             v9fs_walk_post_oldfid_lstat(s, vs, err);
                   1256:             return;
                   1257:         }
                   1258:     } else {
                   1259:         vs->newfidp = alloc_fid(s, newfid);
                   1260:         if (vs->newfidp == NULL) {
                   1261:             err = -EINVAL;
                   1262:             goto out;
                   1263:         }
                   1264: 
                   1265:         vs->newfidp->uid = vs->fidp->uid;
                   1266:         v9fs_string_init(&vs->path);
                   1267:         vs->name_idx = 0;
                   1268:         v9fs_string_copy(&vs->newfidp->path, &vs->fidp->path);
                   1269: 
                   1270:         if (vs->name_idx < vs->nwnames) {
                   1271:             v9fs_string_sprintf(&vs->path, "%s/%s", vs->newfidp->path.data,
                   1272:                                 vs->wnames[vs->name_idx].data);
                   1273:             v9fs_string_copy(&vs->newfidp->path, &vs->path);
                   1274: 
                   1275:             err = v9fs_do_lstat(s, &vs->newfidp->path, &vs->stbuf);
                   1276:             v9fs_walk_post_newfid_lstat(s, vs, err);
                   1277:             return;
                   1278:         }
                   1279:     }
                   1280: 
                   1281:     v9fs_walk_marshal(vs);
                   1282:     err = vs->offset;
                   1283: out:
                   1284:     v9fs_walk_complete(s, vs, err);
                   1285: }
                   1286: 
                   1287: static void v9fs_open_post_opendir(V9fsState *s, V9fsOpenState *vs, int err)
                   1288: {
                   1289:     if (vs->fidp->dir == NULL) {
                   1290:         err = -errno;
                   1291:         goto out;
                   1292:     }
                   1293: 
                   1294:     vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, 0);
                   1295:     err = vs->offset;
                   1296: out:
                   1297:     complete_pdu(s, vs->pdu, err);
                   1298:     qemu_free(vs);
                   1299: 
                   1300: }
                   1301: 
                   1302: static void v9fs_open_post_open(V9fsState *s, V9fsOpenState *vs, int err)
                   1303: {
                   1304:     if (vs->fidp->fd == -1) {
                   1305:         err = -errno;
                   1306:         goto out;
                   1307:     }
                   1308: 
                   1309:     vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, 0);
                   1310:     err = vs->offset;
                   1311: out:
                   1312:     complete_pdu(s, vs->pdu, err);
                   1313:     qemu_free(vs);
                   1314: }
                   1315: 
                   1316: static void v9fs_open_post_lstat(V9fsState *s, V9fsOpenState *vs, int err)
                   1317: {
                   1318:     if (err) {
                   1319:         err = -errno;
                   1320:         goto out;
                   1321:     }
                   1322: 
                   1323:     stat_to_qid(&vs->stbuf, &vs->qid);
                   1324: 
                   1325:     if (S_ISDIR(vs->stbuf.st_mode)) {
                   1326:         vs->fidp->dir = v9fs_do_opendir(s, &vs->fidp->path);
                   1327:         v9fs_open_post_opendir(s, vs, err);
                   1328:     } else {
                   1329:         vs->fidp->fd = v9fs_do_open(s, &vs->fidp->path,
                   1330:                                     omode_to_uflags(vs->mode));
                   1331:         v9fs_open_post_open(s, vs, err);
                   1332:     }
                   1333:     return;
                   1334: out:
                   1335:     complete_pdu(s, vs->pdu, err);
                   1336:     qemu_free(vs);
                   1337: }
                   1338: 
                   1339: static void v9fs_open(V9fsState *s, V9fsPDU *pdu)
                   1340: {
                   1341:     int32_t fid;
                   1342:     V9fsOpenState *vs;
                   1343:     ssize_t err = 0;
                   1344: 
                   1345: 
                   1346:     vs = qemu_malloc(sizeof(*vs));
                   1347:     vs->pdu = pdu;
                   1348:     vs->offset = 7;
                   1349: 
                   1350:     pdu_unmarshal(vs->pdu, vs->offset, "db", &fid, &vs->mode);
                   1351: 
                   1352:     vs->fidp = lookup_fid(s, fid);
                   1353:     if (vs->fidp == NULL) {
                   1354:         err = -ENOENT;
                   1355:         goto out;
                   1356:     }
                   1357: 
                   1358:     BUG_ON(vs->fidp->fd != -1);
                   1359:     BUG_ON(vs->fidp->dir);
                   1360: 
                   1361:     err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
                   1362: 
                   1363:     v9fs_open_post_lstat(s, vs, err);
                   1364:     return;
                   1365: out:
                   1366:     complete_pdu(s, pdu, err);
                   1367:     qemu_free(vs);
                   1368: }
                   1369: 
                   1370: static void v9fs_clunk(V9fsState *s, V9fsPDU *pdu)
                   1371: {
                   1372:     int32_t fid;
                   1373:     size_t offset = 7;
                   1374:     int err;
                   1375: 
                   1376:     pdu_unmarshal(pdu, offset, "d", &fid);
                   1377: 
                   1378:     err = free_fid(s, fid);
                   1379:     if (err < 0) {
                   1380:         goto out;
                   1381:     }
                   1382: 
                   1383:     offset = 7;
                   1384:     err = offset;
                   1385: out:
                   1386:     complete_pdu(s, pdu, err);
                   1387: }
                   1388: 
                   1389: static void v9fs_read_post_readdir(V9fsState *, V9fsReadState *, ssize_t);
                   1390: 
                   1391: static void v9fs_read_post_seekdir(V9fsState *s, V9fsReadState *vs, ssize_t err)
                   1392: {
                   1393:     if (err) {
                   1394:         goto out;
                   1395:     }
                   1396:     v9fs_stat_free(&vs->v9stat);
                   1397:     v9fs_string_free(&vs->name);
                   1398:     vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
                   1399:     vs->offset += vs->count;
                   1400:     err = vs->offset;
                   1401: out:
                   1402:     complete_pdu(s, vs->pdu, err);
                   1403:     qemu_free(vs);
                   1404:     return;
                   1405: }
                   1406: 
                   1407: static void v9fs_read_post_dir_lstat(V9fsState *s, V9fsReadState *vs,
                   1408:                                     ssize_t err)
                   1409: {
                   1410:     if (err) {
                   1411:         err = -errno;
                   1412:         goto out;
                   1413:     }
                   1414:     err = stat_to_v9stat(s, &vs->name, &vs->stbuf, &vs->v9stat);
                   1415:     if (err) {
                   1416:         goto out;
                   1417:     }
                   1418: 
                   1419:     vs->len = pdu_marshal(vs->pdu, vs->offset + 4 + vs->count, "S",
                   1420:                             &vs->v9stat);
                   1421:     if ((vs->len != (vs->v9stat.size + 2)) ||
                   1422:             ((vs->count + vs->len) > vs->max_count)) {
                   1423:         v9fs_do_seekdir(s, vs->fidp->dir, vs->dir_pos);
                   1424:         v9fs_read_post_seekdir(s, vs, err);
                   1425:         return;
                   1426:     }
                   1427:     vs->count += vs->len;
                   1428:     v9fs_stat_free(&vs->v9stat);
                   1429:     v9fs_string_free(&vs->name);
                   1430:     vs->dir_pos = vs->dent->d_off;
                   1431:     vs->dent = v9fs_do_readdir(s, vs->fidp->dir);
                   1432:     v9fs_read_post_readdir(s, vs, err);
                   1433:     return;
                   1434: out:
                   1435:     v9fs_do_seekdir(s, vs->fidp->dir, vs->dir_pos);
                   1436:     v9fs_read_post_seekdir(s, vs, err);
                   1437:     return;
                   1438: 
                   1439: }
                   1440: 
                   1441: static void v9fs_read_post_readdir(V9fsState *s, V9fsReadState *vs, ssize_t err)
                   1442: {
                   1443:     if (vs->dent) {
                   1444:         memset(&vs->v9stat, 0, sizeof(vs->v9stat));
                   1445:         v9fs_string_init(&vs->name);
                   1446:         v9fs_string_sprintf(&vs->name, "%s/%s", vs->fidp->path.data,
                   1447:                             vs->dent->d_name);
                   1448:         err = v9fs_do_lstat(s, &vs->name, &vs->stbuf);
                   1449:         v9fs_read_post_dir_lstat(s, vs, err);
                   1450:         return;
                   1451:     }
                   1452: 
                   1453:     vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
                   1454:     vs->offset += vs->count;
                   1455:     err = vs->offset;
                   1456:     complete_pdu(s, vs->pdu, err);
                   1457:     qemu_free(vs);
                   1458:     return;
                   1459: }
                   1460: 
                   1461: static void v9fs_read_post_telldir(V9fsState *s, V9fsReadState *vs, ssize_t err)
                   1462: {
                   1463:     vs->dent = v9fs_do_readdir(s, vs->fidp->dir);
                   1464:     v9fs_read_post_readdir(s, vs, err);
                   1465:     return;
                   1466: }
                   1467: 
                   1468: static void v9fs_read_post_rewinddir(V9fsState *s, V9fsReadState *vs,
                   1469:                                        ssize_t err)
                   1470: {
                   1471:     vs->dir_pos = v9fs_do_telldir(s, vs->fidp->dir);
                   1472:     v9fs_read_post_telldir(s, vs, err);
                   1473:     return;
                   1474: }
                   1475: 
                   1476: static void v9fs_read_post_readv(V9fsState *s, V9fsReadState *vs, ssize_t err)
                   1477: {
                   1478:     if (err  < 0) {
                   1479:         /* IO error return the error */
                   1480:         err = -errno;
                   1481:         goto out;
                   1482:     }
                   1483:     vs->total += vs->len;
                   1484:     vs->sg = adjust_sg(vs->sg, vs->len, &vs->cnt);
                   1485:     if (vs->total < vs->count && vs->len > 0) {
                   1486:         do {
                   1487:             if (0) {
                   1488:                 print_sg(vs->sg, vs->cnt);
                   1489:             }
                   1490:             vs->len = v9fs_do_readv(s, vs->fidp->fd, vs->sg, vs->cnt);
                   1491:         } while (vs->len == -1 && errno == EINTR);
                   1492:         if (vs->len == -1) {
                   1493:             err  = -errno;
                   1494:         }
                   1495:         v9fs_read_post_readv(s, vs, err);
                   1496:         return;
                   1497:     }
                   1498:     vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->total);
                   1499:     vs->offset += vs->count;
                   1500:     err = vs->offset;
                   1501: 
                   1502: out:
                   1503:     complete_pdu(s, vs->pdu, err);
                   1504:     qemu_free(vs);
                   1505: }
                   1506: 
                   1507: static void v9fs_read_post_lseek(V9fsState *s, V9fsReadState *vs, ssize_t err)
                   1508: {
                   1509:     if (err == -1) {
                   1510:         err = -errno;
                   1511:         goto out;
                   1512:     }
                   1513:     vs->sg = cap_sg(vs->sg, vs->count, &vs->cnt);
                   1514: 
                   1515:     if (vs->total < vs->count) {
                   1516:         do {
                   1517:             if (0) {
                   1518:                 print_sg(vs->sg, vs->cnt);
                   1519:             }
                   1520:             vs->len = v9fs_do_readv(s, vs->fidp->fd, vs->sg, vs->cnt);
                   1521:         } while (vs->len == -1 && errno == EINTR);
                   1522:         if (vs->len == -1) {
                   1523:             err  = -errno;
                   1524:         }
                   1525:         v9fs_read_post_readv(s, vs, err);
                   1526:         return;
                   1527:     }
                   1528: out:
                   1529:     complete_pdu(s, vs->pdu, err);
                   1530:     qemu_free(vs);
                   1531: }
                   1532: 
                   1533: static void v9fs_read(V9fsState *s, V9fsPDU *pdu)
                   1534: {
                   1535:     int32_t fid;
                   1536:     V9fsReadState *vs;
                   1537:     ssize_t err = 0;
                   1538: 
                   1539:     vs = qemu_malloc(sizeof(*vs));
                   1540:     vs->pdu = pdu;
                   1541:     vs->offset = 7;
                   1542:     vs->total = 0;
                   1543:     vs->len = 0;
                   1544:     vs->count = 0;
                   1545: 
                   1546:     pdu_unmarshal(vs->pdu, vs->offset, "dqd", &fid, &vs->off, &vs->count);
                   1547: 
                   1548:     vs->fidp = lookup_fid(s, fid);
                   1549:     if (vs->fidp == NULL) {
                   1550:         err = -EINVAL;
                   1551:         goto out;
                   1552:     }
                   1553: 
                   1554:     if (vs->fidp->dir) {
                   1555:         vs->max_count = vs->count;
                   1556:         vs->count = 0;
                   1557:         if (vs->off == 0) {
                   1558:             v9fs_do_rewinddir(s, vs->fidp->dir);
                   1559:         }
                   1560:         v9fs_read_post_rewinddir(s, vs, err);
                   1561:         return;
                   1562:     } else if (vs->fidp->fd != -1) {
                   1563:         vs->sg = vs->iov;
                   1564:         pdu_marshal(vs->pdu, vs->offset + 4, "v", vs->sg, &vs->cnt);
                   1565:         err = v9fs_do_lseek(s, vs->fidp->fd, vs->off, SEEK_SET);
                   1566:         v9fs_read_post_lseek(s, vs, err);
                   1567:         return;
                   1568:     } else {
                   1569:         err = -EINVAL;
                   1570:     }
                   1571: out:
                   1572:     complete_pdu(s, pdu, err);
                   1573:     qemu_free(vs);
                   1574: }
                   1575: 
                   1576: static void v9fs_write_post_writev(V9fsState *s, V9fsWriteState *vs,
                   1577:                                    ssize_t err)
                   1578: {
                   1579:     if (err  < 0) {
                   1580:         /* IO error return the error */
                   1581:         err = -errno;
                   1582:         goto out;
                   1583:     }
                   1584:     vs->total += vs->len;
                   1585:     vs->sg = adjust_sg(vs->sg, vs->len, &vs->cnt);
                   1586:     if (vs->total < vs->count && vs->len > 0) {
                   1587:         do {
                   1588:             if (0) {
                   1589:                 print_sg(vs->sg, vs->cnt);
                   1590:             }
                   1591:             vs->len =  v9fs_do_writev(s, vs->fidp->fd, vs->sg, vs->cnt);
                   1592:         } while (vs->len == -1 && errno == EINTR);
                   1593:         if (vs->len == -1) {
                   1594:             err  = -errno;
                   1595:         }
                   1596:         v9fs_write_post_writev(s, vs, err);
                   1597:         return;
                   1598:     }
                   1599:     vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->total);
                   1600: 
                   1601:     err = vs->offset;
                   1602: out:
                   1603:     complete_pdu(s, vs->pdu, err);
                   1604:     qemu_free(vs);
                   1605: }
                   1606: 
                   1607: static void v9fs_write_post_lseek(V9fsState *s, V9fsWriteState *vs, ssize_t err)
                   1608: {
                   1609:     if (err == -1) {
                   1610:         err = -errno;
                   1611:         goto out;
                   1612:     }
                   1613:     vs->sg = cap_sg(vs->sg, vs->count, &vs->cnt);
                   1614: 
                   1615:     if (vs->total < vs->count) {
                   1616:         do {
                   1617:             if (0) {
                   1618:                 print_sg(vs->sg, vs->cnt);
                   1619:             }
                   1620:             vs->len = v9fs_do_writev(s, vs->fidp->fd, vs->sg, vs->cnt);
                   1621:         } while (vs->len == -1 && errno == EINTR);
                   1622:         if (vs->len == -1) {
                   1623:             err  = -errno;
                   1624:         }
                   1625:         v9fs_write_post_writev(s, vs, err);
                   1626:         return;
                   1627:     }
                   1628: 
                   1629: out:
                   1630:     complete_pdu(s, vs->pdu, err);
                   1631:     qemu_free(vs);
                   1632: }
                   1633: 
                   1634: static void v9fs_write(V9fsState *s, V9fsPDU *pdu)
                   1635: {
                   1636:     int32_t fid;
                   1637:     V9fsWriteState *vs;
                   1638:     ssize_t err;
                   1639: 
                   1640:     vs = qemu_malloc(sizeof(*vs));
                   1641: 
                   1642:     vs->pdu = pdu;
                   1643:     vs->offset = 7;
                   1644:     vs->sg = vs->iov;
                   1645:     vs->total = 0;
                   1646:     vs->len = 0;
                   1647: 
                   1648:     pdu_unmarshal(vs->pdu, vs->offset, "dqdv", &fid, &vs->off, &vs->count,
                   1649:                     vs->sg, &vs->cnt);
                   1650: 
                   1651:     vs->fidp = lookup_fid(s, fid);
                   1652:     if (vs->fidp == NULL) {
                   1653:         err = -EINVAL;
                   1654:         goto out;
                   1655:     }
                   1656: 
                   1657:     if (vs->fidp->fd == -1) {
                   1658:         err = -EINVAL;
                   1659:         goto out;
                   1660:     }
                   1661: 
                   1662:     err = v9fs_do_lseek(s, vs->fidp->fd, vs->off, SEEK_SET);
                   1663: 
                   1664:     v9fs_write_post_lseek(s, vs, err);
                   1665:     return;
                   1666: 
                   1667: out:
                   1668:     complete_pdu(s, vs->pdu, err);
                   1669:     qemu_free(vs);
                   1670: }
                   1671: 
                   1672: static void v9fs_post_create(V9fsState *s, V9fsCreateState *vs, int err)
                   1673: {
                   1674:     if (err == 0) {
                   1675:         v9fs_string_copy(&vs->fidp->path, &vs->fullname);
                   1676:         stat_to_qid(&vs->stbuf, &vs->qid);
                   1677: 
                   1678:         vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, 0);
                   1679: 
                   1680:         err = vs->offset;
                   1681:     }
                   1682: 
                   1683:     complete_pdu(s, vs->pdu, err);
                   1684:     v9fs_string_free(&vs->name);
                   1685:     v9fs_string_free(&vs->extension);
                   1686:     v9fs_string_free(&vs->fullname);
                   1687:     qemu_free(vs);
                   1688: }
                   1689: 
                   1690: static void v9fs_create_post_perms(V9fsState *s, V9fsCreateState *vs, int err)
                   1691: {
                   1692:     if (err) {
                   1693:         err = -errno;
                   1694:     }
                   1695:     v9fs_post_create(s, vs, err);
                   1696: }
                   1697: 
                   1698: static void v9fs_create_post_opendir(V9fsState *s, V9fsCreateState *vs,
                   1699:                                                                     int err)
                   1700: {
                   1701:     if (!vs->fidp->dir) {
                   1702:         err = -errno;
                   1703:     }
                   1704:     v9fs_post_create(s, vs, err);
                   1705: }
                   1706: 
                   1707: static void v9fs_create_post_dir_lstat(V9fsState *s, V9fsCreateState *vs,
                   1708:                                                                     int err)
                   1709: {
                   1710:     if (err) {
                   1711:         err = -errno;
                   1712:         goto out;
                   1713:     }
                   1714: 
                   1715:     vs->fidp->dir = v9fs_do_opendir(s, &vs->fullname);
                   1716:     v9fs_create_post_opendir(s, vs, err);
                   1717:     return;
                   1718: 
                   1719: out:
                   1720:     v9fs_post_create(s, vs, err);
                   1721: }
                   1722: 
                   1723: static void v9fs_create_post_mkdir(V9fsState *s, V9fsCreateState *vs, int err)
                   1724: {
                   1725:     if (err) {
                   1726:         err = -errno;
                   1727:         goto out;
                   1728:     }
                   1729: 
                   1730:     err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
                   1731:     v9fs_create_post_dir_lstat(s, vs, err);
                   1732:     return;
                   1733: 
                   1734: out:
                   1735:     v9fs_post_create(s, vs, err);
                   1736: }
                   1737: 
                   1738: static void v9fs_create_post_fstat(V9fsState *s, V9fsCreateState *vs, int err)
                   1739: {
                   1740:     if (err) {
                   1741:         vs->fidp->fd = -1;
                   1742:         err = -errno;
                   1743:     }
                   1744: 
                   1745:     v9fs_post_create(s, vs, err);
                   1746:     return;
                   1747: }
                   1748: 
                   1749: static void v9fs_create_post_open2(V9fsState *s, V9fsCreateState *vs, int err)
                   1750: {
                   1751:     if (vs->fidp->fd == -1) {
                   1752:         err = -errno;
                   1753:         goto out;
                   1754:     }
                   1755: 
                   1756:     err = v9fs_do_fstat(s, vs->fidp->fd, &vs->stbuf);
                   1757:     v9fs_create_post_fstat(s, vs, err);
                   1758: 
                   1759:     return;
                   1760: 
                   1761: out:
                   1762:     v9fs_post_create(s, vs, err);
                   1763: 
                   1764: }
                   1765: 
                   1766: static void v9fs_create_post_lstat(V9fsState *s, V9fsCreateState *vs, int err)
                   1767: {
                   1768: 
                   1769:     if (err == 0 || errno != ENOENT) {
                   1770:         err = -errno;
                   1771:         goto out;
                   1772:     }
                   1773: 
                   1774:     if (vs->perm & P9_STAT_MODE_DIR) {
                   1775:         err = v9fs_do_mkdir(s, vs);
                   1776:         v9fs_create_post_mkdir(s, vs, err);
                   1777:     } else if (vs->perm & P9_STAT_MODE_SYMLINK) {
                   1778:         err = v9fs_do_symlink(s, vs);
                   1779:         v9fs_create_post_perms(s, vs, err);
                   1780:     } else if (vs->perm & P9_STAT_MODE_LINK) {
                   1781:         int32_t nfid = atoi(vs->extension.data);
                   1782:         V9fsFidState *nfidp = lookup_fid(s, nfid);
                   1783:         if (nfidp == NULL) {
                   1784:             err = -errno;
                   1785:             v9fs_post_create(s, vs, err);
                   1786:         }
                   1787:         err = v9fs_do_link(s, &nfidp->path, &vs->fullname);
                   1788:         v9fs_create_post_perms(s, vs, err);
                   1789:     } else if (vs->perm & P9_STAT_MODE_DEVICE) {
                   1790:         char ctype;
                   1791:         uint32_t major, minor;
                   1792:         mode_t nmode = 0;
                   1793: 
                   1794:         if (sscanf(vs->extension.data, "%c %u %u", &ctype, &major,
                   1795:                                         &minor) != 3) {
                   1796:             err = -errno;
                   1797:             v9fs_post_create(s, vs, err);
                   1798:         }
                   1799: 
                   1800:         switch (ctype) {
                   1801:         case 'c':
                   1802:             nmode = S_IFCHR;
                   1803:             break;
                   1804:         case 'b':
                   1805:             nmode = S_IFBLK;
                   1806:             break;
                   1807:         default:
                   1808:             err = -EIO;
                   1809:             v9fs_post_create(s, vs, err);
                   1810:         }
                   1811: 
                   1812:         nmode |= vs->perm & 0777;
                   1813:         err = v9fs_do_mknod(s, vs, nmode, makedev(major, minor));
                   1814:         v9fs_create_post_perms(s, vs, err);
                   1815:     } else if (vs->perm & P9_STAT_MODE_NAMED_PIPE) {
                   1816:         err = v9fs_do_mknod(s, vs, S_IFIFO | (vs->perm & 0777), 0);
                   1817:         v9fs_post_create(s, vs, err);
                   1818:     } else if (vs->perm & P9_STAT_MODE_SOCKET) {
                   1819:         err = v9fs_do_mknod(s, vs, S_IFSOCK | (vs->perm & 0777), 0);
                   1820:         v9fs_post_create(s, vs, err);
                   1821:     } else {
                   1822:         vs->fidp->fd = v9fs_do_open2(s, vs);
                   1823:         v9fs_create_post_open2(s, vs, err);
                   1824:     }
                   1825: 
                   1826:     return;
                   1827: 
                   1828: out:
                   1829:     v9fs_post_create(s, vs, err);
                   1830: }
                   1831: 
                   1832: static void v9fs_create(V9fsState *s, V9fsPDU *pdu)
                   1833: {
                   1834:     int32_t fid;
                   1835:     V9fsCreateState *vs;
                   1836:     int err = 0;
                   1837: 
                   1838:     vs = qemu_malloc(sizeof(*vs));
                   1839:     vs->pdu = pdu;
                   1840:     vs->offset = 7;
                   1841: 
                   1842:     v9fs_string_init(&vs->fullname);
                   1843: 
                   1844:     pdu_unmarshal(vs->pdu, vs->offset, "dsdbs", &fid, &vs->name,
                   1845:                                 &vs->perm, &vs->mode, &vs->extension);
                   1846: 
                   1847:     vs->fidp = lookup_fid(s, fid);
                   1848:     if (vs->fidp == NULL) {
                   1849:         err = -EINVAL;
                   1850:         goto out;
                   1851:     }
                   1852: 
                   1853:     v9fs_string_sprintf(&vs->fullname, "%s/%s", vs->fidp->path.data,
                   1854:                                                         vs->name.data);
                   1855: 
                   1856:     err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
                   1857:     v9fs_create_post_lstat(s, vs, err);
                   1858:     return;
                   1859: 
                   1860: out:
                   1861:     complete_pdu(s, vs->pdu, err);
                   1862:     v9fs_string_free(&vs->name);
                   1863:     v9fs_string_free(&vs->extension);
                   1864:     qemu_free(vs);
                   1865: }
                   1866: 
                   1867: static void v9fs_flush(V9fsState *s, V9fsPDU *pdu)
                   1868: {
                   1869:     /* A nop call with no return */
                   1870:     complete_pdu(s, pdu, 7);
                   1871: }
                   1872: 
                   1873: static void v9fs_remove_post_remove(V9fsState *s, V9fsRemoveState *vs,
                   1874:                                                                 int err)
                   1875: {
                   1876:     /* For TREMOVE we need to clunk the fid even on failed remove */
                   1877:     err = free_fid(s, vs->fidp->fid);
                   1878:     if (err < 0) {
                   1879:         goto out;
                   1880:     }
                   1881: 
                   1882:     err = vs->offset;
                   1883: out:
                   1884:     complete_pdu(s, vs->pdu, err);
                   1885:     qemu_free(vs);
                   1886: }
                   1887: 
                   1888: static void v9fs_remove(V9fsState *s, V9fsPDU *pdu)
                   1889: {
                   1890:     int32_t fid;
                   1891:     V9fsRemoveState *vs;
                   1892:     int err = 0;
                   1893: 
                   1894:     vs = qemu_malloc(sizeof(*vs));
                   1895:     vs->pdu = pdu;
                   1896:     vs->offset = 7;
                   1897: 
                   1898:     pdu_unmarshal(vs->pdu, vs->offset, "d", &fid);
                   1899: 
                   1900:     vs->fidp = lookup_fid(s, fid);
                   1901:     if (vs->fidp == NULL) {
                   1902:         err = -EINVAL;
                   1903:         goto out;
                   1904:     }
                   1905: 
                   1906:     err = v9fs_do_remove(s, &vs->fidp->path);
                   1907:     v9fs_remove_post_remove(s, vs, err);
                   1908:     return;
                   1909: 
                   1910: out:
                   1911:     complete_pdu(s, pdu, err);
                   1912:     qemu_free(vs);
                   1913: }
                   1914: 
                   1915: static void v9fs_wstat_post_truncate(V9fsState *s, V9fsWstatState *vs, int err)
                   1916: {
                   1917:     if (err < 0) {
                   1918:         goto out;
                   1919:     }
                   1920: 
                   1921:     err = vs->offset;
                   1922: 
                   1923: out:
                   1924:     v9fs_stat_free(&vs->v9stat);
                   1925:     complete_pdu(s, vs->pdu, err);
                   1926:     qemu_free(vs);
                   1927: }
                   1928: 
                   1929: static void v9fs_wstat_post_rename(V9fsState *s, V9fsWstatState *vs, int err)
                   1930: {
                   1931:     if (err < 0) {
                   1932:         goto out;
                   1933:     }
                   1934: 
                   1935:     if (vs->v9stat.name.size != 0) {
                   1936:         v9fs_string_free(&vs->nname);
                   1937:     }
                   1938: 
                   1939:     if (vs->v9stat.length != -1) {
                   1940:         if (v9fs_do_truncate(s, &vs->fidp->path, vs->v9stat.length) < 0) {
                   1941:             err = -errno;
                   1942:         }
                   1943:     }
                   1944:     v9fs_wstat_post_truncate(s, vs, err);
                   1945:     return;
                   1946: 
                   1947: out:
                   1948:     v9fs_stat_free(&vs->v9stat);
                   1949:     complete_pdu(s, vs->pdu, err);
                   1950:     qemu_free(vs);
                   1951: }
                   1952: 
                   1953: static void v9fs_wstat_post_chown(V9fsState *s, V9fsWstatState *vs, int err)
                   1954: {
                   1955:     V9fsFidState *fidp;
                   1956:     if (err < 0) {
                   1957:         goto out;
                   1958:     }
                   1959: 
                   1960:     if (vs->v9stat.name.size != 0) {
                   1961:         char *old_name, *new_name;
                   1962:         char *end;
                   1963: 
                   1964:         old_name = vs->fidp->path.data;
                   1965:         end = strrchr(old_name, '/');
                   1966:         if (end) {
                   1967:             end++;
                   1968:         } else {
                   1969:             end = old_name;
                   1970:         }
                   1971: 
                   1972:         new_name = qemu_malloc(end - old_name + vs->v9stat.name.size + 1);
                   1973: 
                   1974:         memset(new_name, 0, end - old_name + vs->v9stat.name.size + 1);
                   1975:         memcpy(new_name, old_name, end - old_name);
                   1976:         memcpy(new_name + (end - old_name), vs->v9stat.name.data,
                   1977:                 vs->v9stat.name.size);
                   1978:         vs->nname.data = new_name;
                   1979:         vs->nname.size = strlen(new_name);
                   1980: 
                   1981:         if (strcmp(new_name, vs->fidp->path.data) != 0) {
                   1982:             if (v9fs_do_rename(s, &vs->fidp->path, &vs->nname)) {
                   1983:                 err = -errno;
                   1984:             } else {
                   1985:                 /*
                   1986:                  * Fixup fid's pointing to the old name to
                   1987:                  * start pointing to the new name
                   1988:                  */
                   1989:                 for (fidp = s->fid_list; fidp; fidp = fidp->next) {
                   1990: 
                   1991:                     if (vs->fidp == fidp) {
                   1992:                         /*
                   1993:                          * we replace name of this fid towards the end
                   1994:                          * so that our below strcmp will work
                   1995:                          */
                   1996:                         continue;
                   1997:                     }
                   1998:                     if (!strncmp(vs->fidp->path.data, fidp->path.data,
                   1999:                                  strlen(vs->fidp->path.data))) {
                   2000:                         /* replace the name */
                   2001:                         v9fs_fix_path(&fidp->path, &vs->nname,
                   2002:                                       strlen(vs->fidp->path.data));
                   2003:                     }
                   2004:                 }
                   2005:                 v9fs_string_copy(&vs->fidp->path, &vs->nname);
                   2006:             }
                   2007:         }
                   2008:     }
                   2009:     v9fs_wstat_post_rename(s, vs, err);
                   2010:     return;
                   2011: 
                   2012: out:
                   2013:     v9fs_stat_free(&vs->v9stat);
                   2014:     complete_pdu(s, vs->pdu, err);
                   2015:     qemu_free(vs);
                   2016: }
                   2017: 
                   2018: static void v9fs_wstat_post_utime(V9fsState *s, V9fsWstatState *vs, int err)
                   2019: {
                   2020:     if (err < 0) {
                   2021:         goto out;
                   2022:     }
                   2023: 
                   2024:     if (vs->v9stat.n_gid != -1 || vs->v9stat.n_uid != -1) {
                   2025:         if (v9fs_do_chown(s, &vs->fidp->path, vs->v9stat.n_uid,
                   2026:                     vs->v9stat.n_gid)) {
                   2027:             err = -errno;
                   2028:         }
                   2029:     }
                   2030:     v9fs_wstat_post_chown(s, vs, err);
                   2031:     return;
                   2032: 
                   2033: out:
                   2034:     v9fs_stat_free(&vs->v9stat);
                   2035:     complete_pdu(s, vs->pdu, err);
                   2036:     qemu_free(vs);
                   2037: }
                   2038: 
                   2039: static void v9fs_wstat_post_chmod(V9fsState *s, V9fsWstatState *vs, int err)
                   2040: {
                   2041:     if (err < 0) {
                   2042:         goto out;
                   2043:     }
                   2044: 
                   2045:     if (vs->v9stat.mtime != -1) {
                   2046:         struct utimbuf tb;
                   2047:         tb.actime = 0;
                   2048:         tb.modtime = vs->v9stat.mtime;
                   2049:         if (v9fs_do_utime(s, &vs->fidp->path, &tb)) {
                   2050:             err = -errno;
                   2051:         }
                   2052:     }
                   2053: 
                   2054:     v9fs_wstat_post_utime(s, vs, err);
                   2055:     return;
                   2056: 
                   2057: out:
                   2058:     v9fs_stat_free(&vs->v9stat);
                   2059:     complete_pdu(s, vs->pdu, err);
                   2060:     qemu_free(vs);
                   2061: }
                   2062: 
                   2063: static void v9fs_wstat_post_fsync(V9fsState *s, V9fsWstatState *vs, int err)
                   2064: {
                   2065:     if (err == -1) {
                   2066:         err = -errno;
                   2067:     }
                   2068:     v9fs_stat_free(&vs->v9stat);
                   2069:     complete_pdu(s, vs->pdu, err);
                   2070:     qemu_free(vs);
                   2071: }
                   2072: 
                   2073: static void v9fs_wstat_post_lstat(V9fsState *s, V9fsWstatState *vs, int err)
                   2074: {
                   2075:     uint32_t v9_mode;
                   2076: 
                   2077:     if (err == -1) {
                   2078:         err = -errno;
                   2079:         goto out;
                   2080:     }
                   2081: 
                   2082:     v9_mode = stat_to_v9mode(&vs->stbuf);
                   2083: 
                   2084:     if ((vs->v9stat.mode & P9_STAT_MODE_TYPE_BITS) !=
                   2085:         (v9_mode & P9_STAT_MODE_TYPE_BITS)) {
                   2086:             /* Attempting to change the type */
                   2087:             err = -EIO;
                   2088:             goto out;
                   2089:     }
                   2090: 
                   2091:     if (v9fs_do_chmod(s, &vs->fidp->path, v9mode_to_mode(vs->v9stat.mode,
                   2092:                     &vs->v9stat.extension))) {
                   2093:             err = -errno;
                   2094:      }
                   2095:     v9fs_wstat_post_chmod(s, vs, err);
                   2096:     return;
                   2097: 
                   2098: out:
                   2099:     v9fs_stat_free(&vs->v9stat);
                   2100:     complete_pdu(s, vs->pdu, err);
                   2101:     qemu_free(vs);
                   2102: }
                   2103: 
                   2104: static void v9fs_wstat(V9fsState *s, V9fsPDU *pdu)
                   2105: {
                   2106:     int32_t fid;
                   2107:     V9fsWstatState *vs;
                   2108:     int err = 0;
                   2109: 
                   2110:     vs = qemu_malloc(sizeof(*vs));
                   2111:     vs->pdu = pdu;
                   2112:     vs->offset = 7;
                   2113: 
                   2114:     pdu_unmarshal(pdu, vs->offset, "dwS", &fid, &vs->unused, &vs->v9stat);
                   2115: 
                   2116:     vs->fidp = lookup_fid(s, fid);
                   2117:     if (vs->fidp == NULL) {
                   2118:         err = -EINVAL;
                   2119:         goto out;
                   2120:     }
                   2121: 
                   2122:     /* do we need to sync the file? */
                   2123:     if (donttouch_stat(&vs->v9stat)) {
                   2124:         err = v9fs_do_fsync(s, vs->fidp->fd);
                   2125:         v9fs_wstat_post_fsync(s, vs, err);
                   2126:         return;
                   2127:     }
                   2128: 
                   2129:     if (vs->v9stat.mode != -1) {
                   2130:         err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
                   2131:         v9fs_wstat_post_lstat(s, vs, err);
                   2132:         return;
                   2133:     }
                   2134: 
                   2135:     v9fs_wstat_post_chmod(s, vs, err);
                   2136:     return;
                   2137: 
                   2138: out:
                   2139:     v9fs_stat_free(&vs->v9stat);
                   2140:     complete_pdu(s, vs->pdu, err);
                   2141:     qemu_free(vs);
                   2142: }
                   2143: 
                   2144: typedef void (pdu_handler_t)(V9fsState *s, V9fsPDU *pdu);
                   2145: 
                   2146: static pdu_handler_t *pdu_handlers[] = {
                   2147:     [P9_TVERSION] = v9fs_version,
                   2148:     [P9_TATTACH] = v9fs_attach,
                   2149:     [P9_TSTAT] = v9fs_stat,
                   2150:     [P9_TWALK] = v9fs_walk,
                   2151:     [P9_TCLUNK] = v9fs_clunk,
                   2152:     [P9_TOPEN] = v9fs_open,
                   2153:     [P9_TREAD] = v9fs_read,
                   2154: #if 0
                   2155:     [P9_TAUTH] = v9fs_auth,
                   2156: #endif
                   2157:     [P9_TFLUSH] = v9fs_flush,
                   2158:     [P9_TCREATE] = v9fs_create,
                   2159:     [P9_TWRITE] = v9fs_write,
                   2160:     [P9_TWSTAT] = v9fs_wstat,
                   2161:     [P9_TREMOVE] = v9fs_remove,
                   2162: };
                   2163: 
                   2164: static void submit_pdu(V9fsState *s, V9fsPDU *pdu)
                   2165: {
                   2166:     pdu_handler_t *handler;
                   2167: 
                   2168:     if (debug_9p_pdu) {
                   2169:         pprint_pdu(pdu);
                   2170:     }
                   2171: 
                   2172:     BUG_ON(pdu->id >= ARRAY_SIZE(pdu_handlers));
                   2173: 
                   2174:     handler = pdu_handlers[pdu->id];
                   2175:     BUG_ON(handler == NULL);
                   2176: 
                   2177:     handler(s, pdu);
                   2178: }
                   2179: 
                   2180: static void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
                   2181: {
                   2182:     V9fsState *s = (V9fsState *)vdev;
                   2183:     V9fsPDU *pdu;
                   2184:     ssize_t len;
                   2185: 
                   2186:     while ((pdu = alloc_pdu(s)) &&
                   2187:             (len = virtqueue_pop(vq, &pdu->elem)) != 0) {
                   2188:         uint8_t *ptr;
                   2189: 
                   2190:         BUG_ON(pdu->elem.out_num == 0 || pdu->elem.in_num == 0);
                   2191:         BUG_ON(pdu->elem.out_sg[0].iov_len < 7);
                   2192: 
                   2193:         ptr = pdu->elem.out_sg[0].iov_base;
                   2194: 
                   2195:         memcpy(&pdu->size, ptr, 4);
                   2196:         pdu->id = ptr[4];
                   2197:         memcpy(&pdu->tag, ptr + 5, 2);
                   2198: 
                   2199:         submit_pdu(s, pdu);
                   2200:     }
                   2201: 
                   2202:     free_pdu(s, pdu);
                   2203: }
                   2204: 
                   2205: static uint32_t virtio_9p_get_features(VirtIODevice *vdev, uint32_t features)
                   2206: {
                   2207:     features |= 1 << VIRTIO_9P_MOUNT_TAG;
                   2208:     return features;
                   2209: }
                   2210: 
                   2211: static V9fsState *to_virtio_9p(VirtIODevice *vdev)
                   2212: {
                   2213:     return (V9fsState *)vdev;
                   2214: }
                   2215: 
                   2216: static void virtio_9p_get_config(VirtIODevice *vdev, uint8_t *config)
                   2217: {
                   2218:     struct virtio_9p_config *cfg;
                   2219:     V9fsState *s = to_virtio_9p(vdev);
                   2220: 
                   2221:     cfg = qemu_mallocz(sizeof(struct virtio_9p_config) +
                   2222:                         s->tag_len);
                   2223:     stw_raw(&cfg->tag_len, s->tag_len);
                   2224:     memcpy(cfg->tag, s->tag, s->tag_len);
                   2225:     memcpy(config, cfg, s->config_size);
                   2226:     qemu_free(cfg);
                   2227: }
                   2228: 
                   2229: VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
                   2230:  {
                   2231:     V9fsState *s;
                   2232:     int i, len;
                   2233:     struct stat stat;
                   2234:     FsTypeEntry *fse;
                   2235: 
                   2236: 
                   2237:     s = (V9fsState *)virtio_common_init("virtio-9p",
                   2238:                                     VIRTIO_ID_9P,
                   2239:                                     sizeof(struct virtio_9p_config)+
                   2240:                                     MAX_TAG_LEN,
                   2241:                                     sizeof(V9fsState));
                   2242: 
                   2243:     /* initialize pdu allocator */
                   2244:     QLIST_INIT(&s->free_list);
                   2245:     for (i = 0; i < (MAX_REQ - 1); i++) {
                   2246:        QLIST_INSERT_HEAD(&s->free_list, &s->pdus[i], next);
                   2247:     }
                   2248: 
                   2249:     s->vq = virtio_add_queue(&s->vdev, MAX_REQ, handle_9p_output);
                   2250: 
                   2251:     fse = get_fsdev_fsentry(conf->fsdev_id);
                   2252: 
                   2253:     if (!fse) {
                   2254:         /* We don't have a fsdev identified by fsdev_id */
                   2255:         fprintf(stderr, "Virtio-9p device couldn't find fsdev "
                   2256:                     "with the id %s\n", conf->fsdev_id);
                   2257:         exit(1);
                   2258:     }
                   2259: 
                   2260:     if (!fse->path || !conf->tag) {
                   2261:         /* we haven't specified a mount_tag or the path */
                   2262:         fprintf(stderr, "fsdev with id %s needs path "
                   2263:                 "and Virtio-9p device needs mount_tag arguments\n",
                   2264:                 conf->fsdev_id);
                   2265:         exit(1);
                   2266:     }
                   2267: 
                   2268:     if (!strcmp(fse->security_model, "passthrough")) {
                   2269:         /* Files on the Fileserver set to client user credentials */
                   2270:         s->ctx.fs_sm = SM_PASSTHROUGH;
                   2271:     } else if (!strcmp(fse->security_model, "mapped")) {
                   2272:         /* Files on the fileserver are set to QEMU credentials.
                   2273:          * Client user credentials are saved in extended attributes.
                   2274:          */
                   2275:         s->ctx.fs_sm = SM_MAPPED;
                   2276:     } else {
                   2277:         /* user haven't specified a correct security option */
                   2278:         fprintf(stderr, "one of the following must be specified as the"
                   2279:                 "security option:\n\t security_model=passthrough \n\t "
                   2280:                 "security_model=mapped\n");
                   2281:         return NULL;
                   2282:     }
                   2283: 
                   2284:     if (lstat(fse->path, &stat)) {
                   2285:         fprintf(stderr, "share path %s does not exist\n", fse->path);
                   2286:         exit(1);
                   2287:     } else if (!S_ISDIR(stat.st_mode)) {
                   2288:         fprintf(stderr, "share path %s is not a directory \n", fse->path);
                   2289:         exit(1);
                   2290:     }
                   2291: 
                   2292:     s->ctx.fs_root = qemu_strdup(fse->path);
                   2293:     len = strlen(conf->tag);
                   2294:     if (len > MAX_TAG_LEN) {
                   2295:         len = MAX_TAG_LEN;
                   2296:     }
                   2297:     /* s->tag is non-NULL terminated string */
                   2298:     s->tag = qemu_malloc(len);
                   2299:     memcpy(s->tag, conf->tag, len);
                   2300:     s->tag_len = len;
                   2301:     s->ctx.uid = -1;
                   2302: 
                   2303:     s->ops = fse->ops;
                   2304:     s->vdev.get_features = virtio_9p_get_features;
                   2305:     s->config_size = sizeof(struct virtio_9p_config) +
                   2306:                         s->tag_len;
                   2307:     s->vdev.get_config = virtio_9p_get_config;
                   2308: 
                   2309:     return &s->vdev;
                   2310: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.