Annotation of qemu/hw/virtio-9p.c, revision 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.