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

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"
1.1.1.2 ! root       20: #include "virtio-9p-xattr.h"
1.1       root       21: 
                     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: 
1.1.1.2 ! root      138: static int v9fs_do_preadv(V9fsState *s, int fd, const struct iovec *iov,
        !           139:                             int iovcnt, int64_t offset)
1.1       root      140: {
1.1.1.2 ! root      141:     return s->ops->preadv(&s->ctx, fd, iov, iovcnt, offset);
1.1       root      142: }
                    143: 
1.1.1.2 ! root      144: static int v9fs_do_pwritev(V9fsState *s, int fd, const struct iovec *iov,
        !           145:                        int iovcnt, int64_t offset)
1.1       root      146: {
1.1.1.2 ! root      147:     return s->ops->pwritev(&s->ctx, fd, iov, iovcnt, offset);
1.1       root      148: }
                    149: 
                    150: static int v9fs_do_chmod(V9fsState *s, V9fsString *path, mode_t mode)
                    151: {
                    152:     FsCred cred;
                    153:     cred_init(&cred);
                    154:     cred.fc_mode = mode;
                    155:     return s->ops->chmod(&s->ctx, path->data, &cred);
                    156: }
                    157: 
1.1.1.2 ! root      158: static int v9fs_do_mknod(V9fsState *s, char *name,
        !           159:         mode_t mode, dev_t dev, uid_t uid, gid_t gid)
1.1       root      160: {
                    161:     FsCred cred;
                    162:     cred_init(&cred);
1.1.1.2 ! root      163:     cred.fc_uid = uid;
        !           164:     cred.fc_gid = gid;
1.1       root      165:     cred.fc_mode = mode;
                    166:     cred.fc_rdev = dev;
1.1.1.2 ! root      167:     return s->ops->mknod(&s->ctx, name, &cred);
1.1       root      168: }
                    169: 
1.1.1.2 ! root      170: static int v9fs_do_mkdir(V9fsState *s, char *name, mode_t mode,
        !           171:                 uid_t uid, gid_t gid)
1.1       root      172: {
                    173:     FsCred cred;
                    174: 
                    175:     cred_init(&cred);
1.1.1.2 ! root      176:     cred.fc_uid = uid;
        !           177:     cred.fc_gid = gid;
        !           178:     cred.fc_mode = mode;
1.1       root      179: 
1.1.1.2 ! root      180:     return s->ops->mkdir(&s->ctx, name, &cred);
1.1       root      181: }
                    182: 
                    183: static int v9fs_do_fstat(V9fsState *s, int fd, struct stat *stbuf)
                    184: {
                    185:     return s->ops->fstat(&s->ctx, fd, stbuf);
                    186: }
                    187: 
1.1.1.2 ! root      188: static int v9fs_do_open2(V9fsState *s, char *fullname, uid_t uid, gid_t gid,
        !           189:         int flags, int mode)
1.1       root      190: {
                    191:     FsCred cred;
                    192: 
                    193:     cred_init(&cred);
1.1.1.2 ! root      194:     cred.fc_uid = uid;
        !           195:     cred.fc_gid = gid;
        !           196:     cred.fc_mode = mode & 07777;
        !           197:     flags = flags;
1.1       root      198: 
1.1.1.2 ! root      199:     return s->ops->open2(&s->ctx, fullname, flags, &cred);
1.1       root      200: }
                    201: 
1.1.1.2 ! root      202: static int v9fs_do_symlink(V9fsState *s, V9fsFidState *fidp,
        !           203:         const char *oldpath, const char *newpath, gid_t gid)
1.1       root      204: {
                    205:     FsCred cred;
                    206:     cred_init(&cred);
1.1.1.2 ! root      207:     cred.fc_uid = fidp->uid;
        !           208:     cred.fc_gid = gid;
        !           209:     cred.fc_mode = 0777;
1.1       root      210: 
1.1.1.2 ! root      211:     return s->ops->symlink(&s->ctx, oldpath, newpath, &cred);
1.1       root      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: 
1.1.1.2 ! root      240: static int v9fs_do_utimensat(V9fsState *s, V9fsString *path,
        !           241:                                            const struct timespec times[2])
1.1       root      242: {
1.1.1.2 ! root      243:     return s->ops->utimensat(&s->ctx, path->data, times);
1.1       root      244: }
                    245: 
                    246: static int v9fs_do_remove(V9fsState *s, V9fsString *path)
                    247: {
                    248:     return s->ops->remove(&s->ctx, path->data);
                    249: }
                    250: 
1.1.1.2 ! root      251: static int v9fs_do_fsync(V9fsState *s, int fd, int datasync)
        !           252: {
        !           253:     return s->ops->fsync(&s->ctx, fd, datasync);
        !           254: }
        !           255: 
        !           256: static int v9fs_do_statfs(V9fsState *s, V9fsString *path, struct statfs *stbuf)
        !           257: {
        !           258:     return s->ops->statfs(&s->ctx, path->data, stbuf);
        !           259: }
        !           260: 
        !           261: static ssize_t v9fs_do_lgetxattr(V9fsState *s, V9fsString *path,
        !           262:                              V9fsString *xattr_name,
        !           263:                              void *value, size_t size)
        !           264: {
        !           265:     return s->ops->lgetxattr(&s->ctx, path->data,
        !           266:                              xattr_name->data, value, size);
        !           267: }
        !           268: 
        !           269: static ssize_t v9fs_do_llistxattr(V9fsState *s, V9fsString *path,
        !           270:                               void *value, size_t size)
        !           271: {
        !           272:     return s->ops->llistxattr(&s->ctx, path->data,
        !           273:                               value, size);
        !           274: }
        !           275: 
        !           276: static int v9fs_do_lsetxattr(V9fsState *s, V9fsString *path,
        !           277:                              V9fsString *xattr_name,
        !           278:                              void *value, size_t size, int flags)
1.1       root      279: {
1.1.1.2 ! root      280:     return s->ops->lsetxattr(&s->ctx, path->data,
        !           281:                              xattr_name->data, value, size, flags);
1.1       root      282: }
                    283: 
1.1.1.2 ! root      284: static int v9fs_do_lremovexattr(V9fsState *s, V9fsString *path,
        !           285:                                 V9fsString *xattr_name)
        !           286: {
        !           287:     return s->ops->lremovexattr(&s->ctx, path->data,
        !           288:                                 xattr_name->data);
        !           289: }
        !           290: 
        !           291: 
1.1       root      292: static void v9fs_string_init(V9fsString *str)
                    293: {
                    294:     str->data = NULL;
                    295:     str->size = 0;
                    296: }
                    297: 
                    298: static void v9fs_string_free(V9fsString *str)
                    299: {
                    300:     qemu_free(str->data);
                    301:     str->data = NULL;
                    302:     str->size = 0;
                    303: }
                    304: 
                    305: static void v9fs_string_null(V9fsString *str)
                    306: {
                    307:     v9fs_string_free(str);
                    308: }
                    309: 
                    310: static int number_to_string(void *arg, char type)
                    311: {
                    312:     unsigned int ret = 0;
                    313: 
                    314:     switch (type) {
                    315:     case 'u': {
                    316:         unsigned int num = *(unsigned int *)arg;
                    317: 
                    318:         do {
                    319:             ret++;
                    320:             num = num/10;
                    321:         } while (num);
                    322:         break;
                    323:     }
1.1.1.2 ! root      324:     case 'U': {
        !           325:         unsigned long num = *(unsigned long *)arg;
        !           326:         do {
        !           327:             ret++;
        !           328:             num = num/10;
        !           329:         } while (num);
        !           330:         break;
        !           331:     }
1.1       root      332:     default:
                    333:         printf("Number_to_string: Unknown number format\n");
                    334:         return -1;
                    335:     }
                    336: 
                    337:     return ret;
                    338: }
                    339: 
1.1.1.2 ! root      340: static int GCC_FMT_ATTR(2, 0)
        !           341: v9fs_string_alloc_printf(char **strp, const char *fmt, va_list ap)
1.1       root      342: {
                    343:     va_list ap2;
                    344:     char *iter = (char *)fmt;
                    345:     int len = 0;
                    346:     int nr_args = 0;
                    347:     char *arg_char_ptr;
                    348:     unsigned int arg_uint;
1.1.1.2 ! root      349:     unsigned long arg_ulong;
1.1       root      350: 
                    351:     /* Find the number of %'s that denotes an argument */
                    352:     for (iter = strstr(iter, "%"); iter; iter = strstr(iter, "%")) {
                    353:         nr_args++;
                    354:         iter++;
                    355:     }
                    356: 
                    357:     len = strlen(fmt) - 2*nr_args;
                    358: 
                    359:     if (!nr_args) {
                    360:         goto alloc_print;
                    361:     }
                    362: 
                    363:     va_copy(ap2, ap);
                    364: 
                    365:     iter = (char *)fmt;
                    366: 
                    367:     /* Now parse the format string */
                    368:     for (iter = strstr(iter, "%"); iter; iter = strstr(iter, "%")) {
                    369:         iter++;
                    370:         switch (*iter) {
                    371:         case 'u':
                    372:             arg_uint = va_arg(ap2, unsigned int);
                    373:             len += number_to_string((void *)&arg_uint, 'u');
                    374:             break;
1.1.1.2 ! root      375:         case 'l':
        !           376:             if (*++iter == 'u') {
        !           377:                 arg_ulong = va_arg(ap2, unsigned long);
        !           378:                 len += number_to_string((void *)&arg_ulong, 'U');
        !           379:             } else {
        !           380:                 return -1;
        !           381:             }
        !           382:             break;
1.1       root      383:         case 's':
                    384:             arg_char_ptr = va_arg(ap2, char *);
                    385:             len += strlen(arg_char_ptr);
                    386:             break;
                    387:         case 'c':
                    388:             len += 1;
                    389:             break;
                    390:         default:
                    391:             fprintf(stderr,
                    392:                    "v9fs_string_alloc_printf:Incorrect format %c", *iter);
                    393:             return -1;
                    394:         }
                    395:         iter++;
                    396:     }
                    397: 
                    398: alloc_print:
                    399:     *strp = qemu_malloc((len + 1) * sizeof(**strp));
                    400: 
                    401:     return vsprintf(*strp, fmt, ap);
                    402: }
                    403: 
1.1.1.2 ! root      404: static void GCC_FMT_ATTR(2, 3)
        !           405: v9fs_string_sprintf(V9fsString *str, const char *fmt, ...)
1.1       root      406: {
                    407:     va_list ap;
                    408:     int err;
                    409: 
                    410:     v9fs_string_free(str);
                    411: 
                    412:     va_start(ap, fmt);
                    413:     err = v9fs_string_alloc_printf(&str->data, fmt, ap);
                    414:     BUG_ON(err == -1);
                    415:     va_end(ap);
                    416: 
                    417:     str->size = err;
                    418: }
                    419: 
                    420: static void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs)
                    421: {
                    422:     v9fs_string_free(lhs);
                    423:     v9fs_string_sprintf(lhs, "%s", rhs->data);
                    424: }
                    425: 
                    426: static size_t v9fs_string_size(V9fsString *str)
                    427: {
                    428:     return str->size;
                    429: }
                    430: 
                    431: static V9fsFidState *lookup_fid(V9fsState *s, int32_t fid)
                    432: {
                    433:     V9fsFidState *f;
                    434: 
                    435:     for (f = s->fid_list; f; f = f->next) {
                    436:         if (f->fid == fid) {
                    437:             return f;
                    438:         }
                    439:     }
                    440: 
                    441:     return NULL;
                    442: }
                    443: 
                    444: static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid)
                    445: {
                    446:     V9fsFidState *f;
                    447: 
                    448:     f = lookup_fid(s, fid);
                    449:     if (f) {
                    450:         return NULL;
                    451:     }
                    452: 
                    453:     f = qemu_mallocz(sizeof(V9fsFidState));
                    454: 
                    455:     f->fid = fid;
1.1.1.2 ! root      456:     f->fid_type = P9_FID_NONE;
1.1       root      457: 
                    458:     f->next = s->fid_list;
                    459:     s->fid_list = f;
                    460: 
                    461:     return f;
                    462: }
                    463: 
1.1.1.2 ! root      464: static int v9fs_xattr_fid_clunk(V9fsState *s, V9fsFidState *fidp)
        !           465: {
        !           466:     int retval = 0;
        !           467: 
        !           468:     if (fidp->fs.xattr.copied_len == -1) {
        !           469:         /* getxattr/listxattr fid */
        !           470:         goto free_value;
        !           471:     }
        !           472:     /*
        !           473:      * if this is fid for setxattr. clunk should
        !           474:      * result in setxattr localcall
        !           475:      */
        !           476:     if (fidp->fs.xattr.len != fidp->fs.xattr.copied_len) {
        !           477:         /* clunk after partial write */
        !           478:         retval = -EINVAL;
        !           479:         goto free_out;
        !           480:     }
        !           481:     if (fidp->fs.xattr.len) {
        !           482:         retval = v9fs_do_lsetxattr(s, &fidp->path, &fidp->fs.xattr.name,
        !           483:                                    fidp->fs.xattr.value,
        !           484:                                    fidp->fs.xattr.len,
        !           485:                                    fidp->fs.xattr.flags);
        !           486:     } else {
        !           487:         retval = v9fs_do_lremovexattr(s, &fidp->path, &fidp->fs.xattr.name);
        !           488:     }
        !           489: free_out:
        !           490:     v9fs_string_free(&fidp->fs.xattr.name);
        !           491: free_value:
        !           492:     if (fidp->fs.xattr.value) {
        !           493:         qemu_free(fidp->fs.xattr.value);
        !           494:     }
        !           495:     return retval;
        !           496: }
        !           497: 
1.1       root      498: static int free_fid(V9fsState *s, int32_t fid)
                    499: {
1.1.1.2 ! root      500:     int retval = 0;
1.1       root      501:     V9fsFidState **fidpp, *fidp;
                    502: 
                    503:     for (fidpp = &s->fid_list; *fidpp; fidpp = &(*fidpp)->next) {
                    504:         if ((*fidpp)->fid == fid) {
                    505:             break;
                    506:         }
                    507:     }
                    508: 
                    509:     if (*fidpp == NULL) {
                    510:         return -ENOENT;
                    511:     }
                    512: 
                    513:     fidp = *fidpp;
                    514:     *fidpp = fidp->next;
                    515: 
1.1.1.2 ! root      516:     if (fidp->fid_type == P9_FID_FILE) {
        !           517:         v9fs_do_close(s, fidp->fs.fd);
        !           518:     } else if (fidp->fid_type == P9_FID_DIR) {
        !           519:         v9fs_do_closedir(s, fidp->fs.dir);
        !           520:     } else if (fidp->fid_type == P9_FID_XATTR) {
        !           521:         retval = v9fs_xattr_fid_clunk(s, fidp);
1.1       root      522:     }
                    523:     v9fs_string_free(&fidp->path);
                    524:     qemu_free(fidp);
                    525: 
1.1.1.2 ! root      526:     return retval;
1.1       root      527: }
                    528: 
                    529: #define P9_QID_TYPE_DIR         0x80
                    530: #define P9_QID_TYPE_SYMLINK     0x02
                    531: 
                    532: #define P9_STAT_MODE_DIR        0x80000000
                    533: #define P9_STAT_MODE_APPEND     0x40000000
                    534: #define P9_STAT_MODE_EXCL       0x20000000
                    535: #define P9_STAT_MODE_MOUNT      0x10000000
                    536: #define P9_STAT_MODE_AUTH       0x08000000
                    537: #define P9_STAT_MODE_TMP        0x04000000
                    538: #define P9_STAT_MODE_SYMLINK    0x02000000
                    539: #define P9_STAT_MODE_LINK       0x01000000
                    540: #define P9_STAT_MODE_DEVICE     0x00800000
                    541: #define P9_STAT_MODE_NAMED_PIPE 0x00200000
                    542: #define P9_STAT_MODE_SOCKET     0x00100000
                    543: #define P9_STAT_MODE_SETUID     0x00080000
                    544: #define P9_STAT_MODE_SETGID     0x00040000
                    545: #define P9_STAT_MODE_SETVTX     0x00010000
                    546: 
                    547: #define P9_STAT_MODE_TYPE_BITS (P9_STAT_MODE_DIR |          \
                    548:                                 P9_STAT_MODE_SYMLINK |      \
                    549:                                 P9_STAT_MODE_LINK |         \
                    550:                                 P9_STAT_MODE_DEVICE |       \
                    551:                                 P9_STAT_MODE_NAMED_PIPE |   \
                    552:                                 P9_STAT_MODE_SOCKET)
                    553: 
                    554: /* This is the algorithm from ufs in spfs */
                    555: static void stat_to_qid(const struct stat *stbuf, V9fsQID *qidp)
                    556: {
                    557:     size_t size;
                    558: 
                    559:     size = MIN(sizeof(stbuf->st_ino), sizeof(qidp->path));
                    560:     memcpy(&qidp->path, &stbuf->st_ino, size);
                    561:     qidp->version = stbuf->st_mtime ^ (stbuf->st_size << 8);
                    562:     qidp->type = 0;
                    563:     if (S_ISDIR(stbuf->st_mode)) {
                    564:         qidp->type |= P9_QID_TYPE_DIR;
                    565:     }
                    566:     if (S_ISLNK(stbuf->st_mode)) {
                    567:         qidp->type |= P9_QID_TYPE_SYMLINK;
                    568:     }
                    569: }
                    570: 
                    571: static int fid_to_qid(V9fsState *s, V9fsFidState *fidp, V9fsQID *qidp)
                    572: {
                    573:     struct stat stbuf;
                    574:     int err;
                    575: 
                    576:     err = v9fs_do_lstat(s, &fidp->path, &stbuf);
                    577:     if (err) {
                    578:         return err;
                    579:     }
                    580: 
                    581:     stat_to_qid(&stbuf, qidp);
                    582:     return 0;
                    583: }
                    584: 
                    585: static V9fsPDU *alloc_pdu(V9fsState *s)
                    586: {
                    587:     V9fsPDU *pdu = NULL;
                    588: 
                    589:     if (!QLIST_EMPTY(&s->free_list)) {
                    590:        pdu = QLIST_FIRST(&s->free_list);
                    591:        QLIST_REMOVE(pdu, next);
                    592:     }
                    593:     return pdu;
                    594: }
                    595: 
                    596: static void free_pdu(V9fsState *s, V9fsPDU *pdu)
                    597: {
                    598:     if (pdu) {
                    599:        QLIST_INSERT_HEAD(&s->free_list, pdu, next);
                    600:     }
                    601: }
                    602: 
                    603: size_t pdu_packunpack(void *addr, struct iovec *sg, int sg_count,
                    604:                         size_t offset, size_t size, int pack)
                    605: {
                    606:     int i = 0;
                    607:     size_t copied = 0;
                    608: 
                    609:     for (i = 0; size && i < sg_count; i++) {
                    610:         size_t len;
                    611:         if (offset >= sg[i].iov_len) {
                    612:             /* skip this sg */
                    613:             offset -= sg[i].iov_len;
                    614:             continue;
                    615:         } else {
                    616:             len = MIN(sg[i].iov_len - offset, size);
                    617:             if (pack) {
                    618:                 memcpy(sg[i].iov_base + offset, addr, len);
                    619:             } else {
                    620:                 memcpy(addr, sg[i].iov_base + offset, len);
                    621:             }
                    622:             size -= len;
                    623:             copied += len;
                    624:             addr += len;
                    625:             if (size) {
                    626:                 offset = 0;
                    627:                 continue;
                    628:             }
                    629:         }
                    630:     }
                    631: 
                    632:     return copied;
                    633: }
                    634: 
                    635: static size_t pdu_unpack(void *dst, V9fsPDU *pdu, size_t offset, size_t size)
                    636: {
                    637:     return pdu_packunpack(dst, pdu->elem.out_sg, pdu->elem.out_num,
                    638:                          offset, size, 0);
                    639: }
                    640: 
                    641: static size_t pdu_pack(V9fsPDU *pdu, size_t offset, const void *src,
                    642:                         size_t size)
                    643: {
                    644:     return pdu_packunpack((void *)src, pdu->elem.in_sg, pdu->elem.in_num,
                    645:                              offset, size, 1);
                    646: }
                    647: 
                    648: static int pdu_copy_sg(V9fsPDU *pdu, size_t offset, int rx, struct iovec *sg)
                    649: {
                    650:     size_t pos = 0;
                    651:     int i, j;
                    652:     struct iovec *src_sg;
                    653:     unsigned int num;
                    654: 
                    655:     if (rx) {
                    656:         src_sg = pdu->elem.in_sg;
                    657:         num = pdu->elem.in_num;
                    658:     } else {
                    659:         src_sg = pdu->elem.out_sg;
                    660:         num = pdu->elem.out_num;
                    661:     }
                    662: 
                    663:     j = 0;
                    664:     for (i = 0; i < num; i++) {
                    665:         if (offset <= pos) {
                    666:             sg[j].iov_base = src_sg[i].iov_base;
                    667:             sg[j].iov_len = src_sg[i].iov_len;
                    668:             j++;
                    669:         } else if (offset < (src_sg[i].iov_len + pos)) {
                    670:             sg[j].iov_base = src_sg[i].iov_base;
                    671:             sg[j].iov_len = src_sg[i].iov_len;
                    672:             sg[j].iov_base += (offset - pos);
                    673:             sg[j].iov_len -= (offset - pos);
                    674:             j++;
                    675:         }
                    676:         pos += src_sg[i].iov_len;
                    677:     }
                    678: 
                    679:     return j;
                    680: }
                    681: 
                    682: static size_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
                    683: {
                    684:     size_t old_offset = offset;
                    685:     va_list ap;
                    686:     int i;
                    687: 
                    688:     va_start(ap, fmt);
                    689:     for (i = 0; fmt[i]; i++) {
                    690:         switch (fmt[i]) {
                    691:         case 'b': {
                    692:             uint8_t *valp = va_arg(ap, uint8_t *);
                    693:             offset += pdu_unpack(valp, pdu, offset, sizeof(*valp));
                    694:             break;
                    695:         }
                    696:         case 'w': {
                    697:             uint16_t val, *valp;
                    698:             valp = va_arg(ap, uint16_t *);
                    699:             val = le16_to_cpupu(valp);
                    700:             offset += pdu_unpack(&val, pdu, offset, sizeof(val));
                    701:             *valp = val;
                    702:             break;
                    703:         }
                    704:         case 'd': {
                    705:             uint32_t val, *valp;
                    706:             valp = va_arg(ap, uint32_t *);
                    707:             val = le32_to_cpupu(valp);
                    708:             offset += pdu_unpack(&val, pdu, offset, sizeof(val));
                    709:             *valp = val;
                    710:             break;
                    711:         }
                    712:         case 'q': {
                    713:             uint64_t val, *valp;
                    714:             valp = va_arg(ap, uint64_t *);
                    715:             val = le64_to_cpup(valp);
                    716:             offset += pdu_unpack(&val, pdu, offset, sizeof(val));
                    717:             *valp = val;
                    718:             break;
                    719:         }
                    720:         case 'v': {
                    721:             struct iovec *iov = va_arg(ap, struct iovec *);
                    722:             int *iovcnt = va_arg(ap, int *);
                    723:             *iovcnt = pdu_copy_sg(pdu, offset, 0, iov);
                    724:             break;
                    725:         }
                    726:         case 's': {
                    727:             V9fsString *str = va_arg(ap, V9fsString *);
                    728:             offset += pdu_unmarshal(pdu, offset, "w", &str->size);
                    729:             /* FIXME: sanity check str->size */
                    730:             str->data = qemu_malloc(str->size + 1);
                    731:             offset += pdu_unpack(str->data, pdu, offset, str->size);
                    732:             str->data[str->size] = 0;
                    733:             break;
                    734:         }
                    735:         case 'Q': {
                    736:             V9fsQID *qidp = va_arg(ap, V9fsQID *);
                    737:             offset += pdu_unmarshal(pdu, offset, "bdq",
                    738:                         &qidp->type, &qidp->version, &qidp->path);
                    739:             break;
                    740:         }
                    741:         case 'S': {
                    742:             V9fsStat *statp = va_arg(ap, V9fsStat *);
                    743:             offset += pdu_unmarshal(pdu, offset, "wwdQdddqsssssddd",
                    744:                         &statp->size, &statp->type, &statp->dev,
                    745:                         &statp->qid, &statp->mode, &statp->atime,
                    746:                         &statp->mtime, &statp->length,
                    747:                         &statp->name, &statp->uid, &statp->gid,
                    748:                         &statp->muid, &statp->extension,
                    749:                         &statp->n_uid, &statp->n_gid,
                    750:                         &statp->n_muid);
                    751:             break;
                    752:         }
1.1.1.2 ! root      753:         case 'I': {
        !           754:             V9fsIattr *iattr = va_arg(ap, V9fsIattr *);
        !           755:             offset += pdu_unmarshal(pdu, offset, "ddddqqqqq",
        !           756:                         &iattr->valid, &iattr->mode,
        !           757:                         &iattr->uid, &iattr->gid, &iattr->size,
        !           758:                         &iattr->atime_sec, &iattr->atime_nsec,
        !           759:                         &iattr->mtime_sec, &iattr->mtime_nsec);
        !           760:             break;
        !           761:         }
1.1       root      762:         default:
                    763:             break;
                    764:         }
                    765:     }
                    766: 
                    767:     va_end(ap);
                    768: 
                    769:     return offset - old_offset;
                    770: }
                    771: 
                    772: static size_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
                    773: {
                    774:     size_t old_offset = offset;
                    775:     va_list ap;
                    776:     int i;
                    777: 
                    778:     va_start(ap, fmt);
                    779:     for (i = 0; fmt[i]; i++) {
                    780:         switch (fmt[i]) {
                    781:         case 'b': {
                    782:             uint8_t val = va_arg(ap, int);
                    783:             offset += pdu_pack(pdu, offset, &val, sizeof(val));
                    784:             break;
                    785:         }
                    786:         case 'w': {
                    787:             uint16_t val;
                    788:             cpu_to_le16w(&val, va_arg(ap, int));
                    789:             offset += pdu_pack(pdu, offset, &val, sizeof(val));
                    790:             break;
                    791:         }
                    792:         case 'd': {
                    793:             uint32_t val;
                    794:             cpu_to_le32w(&val, va_arg(ap, uint32_t));
                    795:             offset += pdu_pack(pdu, offset, &val, sizeof(val));
                    796:             break;
                    797:         }
                    798:         case 'q': {
                    799:             uint64_t val;
                    800:             cpu_to_le64w(&val, va_arg(ap, uint64_t));
                    801:             offset += pdu_pack(pdu, offset, &val, sizeof(val));
                    802:             break;
                    803:         }
                    804:         case 'v': {
                    805:             struct iovec *iov = va_arg(ap, struct iovec *);
                    806:             int *iovcnt = va_arg(ap, int *);
                    807:             *iovcnt = pdu_copy_sg(pdu, offset, 1, iov);
                    808:             break;
                    809:         }
                    810:         case 's': {
                    811:             V9fsString *str = va_arg(ap, V9fsString *);
                    812:             offset += pdu_marshal(pdu, offset, "w", str->size);
                    813:             offset += pdu_pack(pdu, offset, str->data, str->size);
                    814:             break;
                    815:         }
                    816:         case 'Q': {
                    817:             V9fsQID *qidp = va_arg(ap, V9fsQID *);
                    818:             offset += pdu_marshal(pdu, offset, "bdq",
                    819:                         qidp->type, qidp->version, qidp->path);
                    820:             break;
                    821:         }
                    822:         case 'S': {
                    823:             V9fsStat *statp = va_arg(ap, V9fsStat *);
                    824:             offset += pdu_marshal(pdu, offset, "wwdQdddqsssssddd",
                    825:                         statp->size, statp->type, statp->dev,
                    826:                         &statp->qid, statp->mode, statp->atime,
                    827:                         statp->mtime, statp->length, &statp->name,
                    828:                         &statp->uid, &statp->gid, &statp->muid,
                    829:                         &statp->extension, statp->n_uid,
                    830:                         statp->n_gid, statp->n_muid);
                    831:             break;
                    832:         }
1.1.1.2 ! root      833:         case 'A': {
        !           834:             V9fsStatDotl *statp = va_arg(ap, V9fsStatDotl *);
        !           835:             offset += pdu_marshal(pdu, offset, "qQdddqqqqqqqqqqqqqqq",
        !           836:                         statp->st_result_mask,
        !           837:                         &statp->qid, statp->st_mode,
        !           838:                         statp->st_uid, statp->st_gid,
        !           839:                         statp->st_nlink, statp->st_rdev,
        !           840:                         statp->st_size, statp->st_blksize, statp->st_blocks,
        !           841:                         statp->st_atime_sec, statp->st_atime_nsec,
        !           842:                         statp->st_mtime_sec, statp->st_mtime_nsec,
        !           843:                         statp->st_ctime_sec, statp->st_ctime_nsec,
        !           844:                         statp->st_btime_sec, statp->st_btime_nsec,
        !           845:                         statp->st_gen, statp->st_data_version);
        !           846:             break;
        !           847:         }
1.1       root      848:         default:
                    849:             break;
                    850:         }
                    851:     }
                    852:     va_end(ap);
                    853: 
                    854:     return offset - old_offset;
                    855: }
                    856: 
                    857: static void complete_pdu(V9fsState *s, V9fsPDU *pdu, ssize_t len)
                    858: {
                    859:     int8_t id = pdu->id + 1; /* Response */
                    860: 
                    861:     if (len < 0) {
                    862:         int err = -len;
1.1.1.2 ! root      863:         len = 7;
1.1       root      864: 
1.1.1.2 ! root      865:         if (s->proto_version != V9FS_PROTO_2000L) {
        !           866:             V9fsString str;
1.1       root      867: 
1.1.1.2 ! root      868:             str.data = strerror(err);
        !           869:             str.size = strlen(str.data);
        !           870: 
        !           871:             len += pdu_marshal(pdu, len, "s", &str);
        !           872:             id = P9_RERROR;
1.1       root      873:         }
                    874: 
1.1.1.2 ! root      875:         len += pdu_marshal(pdu, len, "d", err);
        !           876: 
        !           877:         if (s->proto_version == V9FS_PROTO_2000L) {
        !           878:             id = P9_RLERROR;
        !           879:         }
1.1       root      880:     }
                    881: 
                    882:     /* fill out the header */
                    883:     pdu_marshal(pdu, 0, "dbw", (int32_t)len, id, pdu->tag);
                    884: 
                    885:     /* keep these in sync */
                    886:     pdu->size = len;
                    887:     pdu->id = id;
                    888: 
                    889:     /* push onto queue and notify */
                    890:     virtqueue_push(s->vq, &pdu->elem, len);
                    891: 
                    892:     /* FIXME: we should batch these completions */
                    893:     virtio_notify(&s->vdev, s->vq);
                    894: 
                    895:     free_pdu(s, pdu);
                    896: }
                    897: 
                    898: static mode_t v9mode_to_mode(uint32_t mode, V9fsString *extension)
                    899: {
                    900:     mode_t ret;
                    901: 
                    902:     ret = mode & 0777;
                    903:     if (mode & P9_STAT_MODE_DIR) {
                    904:         ret |= S_IFDIR;
                    905:     }
                    906: 
1.1.1.2 ! root      907:     if (mode & P9_STAT_MODE_SYMLINK) {
        !           908:         ret |= S_IFLNK;
        !           909:     }
        !           910:     if (mode & P9_STAT_MODE_SOCKET) {
        !           911:         ret |= S_IFSOCK;
        !           912:     }
        !           913:     if (mode & P9_STAT_MODE_NAMED_PIPE) {
        !           914:         ret |= S_IFIFO;
        !           915:     }
        !           916:     if (mode & P9_STAT_MODE_DEVICE) {
        !           917:         if (extension && extension->data[0] == 'c') {
        !           918:             ret |= S_IFCHR;
        !           919:         } else {
        !           920:             ret |= S_IFBLK;
1.1       root      921:         }
                    922:     }
                    923: 
                    924:     if (!(ret&~0777)) {
                    925:         ret |= S_IFREG;
                    926:     }
                    927: 
                    928:     if (mode & P9_STAT_MODE_SETUID) {
                    929:         ret |= S_ISUID;
                    930:     }
                    931:     if (mode & P9_STAT_MODE_SETGID) {
                    932:         ret |= S_ISGID;
                    933:     }
                    934:     if (mode & P9_STAT_MODE_SETVTX) {
                    935:         ret |= S_ISVTX;
                    936:     }
                    937: 
                    938:     return ret;
                    939: }
                    940: 
                    941: static int donttouch_stat(V9fsStat *stat)
                    942: {
                    943:     if (stat->type == -1 &&
                    944:         stat->dev == -1 &&
                    945:         stat->qid.type == -1 &&
                    946:         stat->qid.version == -1 &&
                    947:         stat->qid.path == -1 &&
                    948:         stat->mode == -1 &&
                    949:         stat->atime == -1 &&
                    950:         stat->mtime == -1 &&
                    951:         stat->length == -1 &&
                    952:         !stat->name.size &&
                    953:         !stat->uid.size &&
                    954:         !stat->gid.size &&
                    955:         !stat->muid.size &&
                    956:         stat->n_uid == -1 &&
                    957:         stat->n_gid == -1 &&
                    958:         stat->n_muid == -1) {
                    959:         return 1;
                    960:     }
                    961: 
                    962:     return 0;
                    963: }
                    964: 
                    965: static void v9fs_stat_free(V9fsStat *stat)
                    966: {
                    967:     v9fs_string_free(&stat->name);
                    968:     v9fs_string_free(&stat->uid);
                    969:     v9fs_string_free(&stat->gid);
                    970:     v9fs_string_free(&stat->muid);
                    971:     v9fs_string_free(&stat->extension);
                    972: }
                    973: 
                    974: static uint32_t stat_to_v9mode(const struct stat *stbuf)
                    975: {
                    976:     uint32_t mode;
                    977: 
                    978:     mode = stbuf->st_mode & 0777;
                    979:     if (S_ISDIR(stbuf->st_mode)) {
                    980:         mode |= P9_STAT_MODE_DIR;
                    981:     }
                    982: 
1.1.1.2 ! root      983:     if (S_ISLNK(stbuf->st_mode)) {
        !           984:         mode |= P9_STAT_MODE_SYMLINK;
        !           985:     }
1.1       root      986: 
1.1.1.2 ! root      987:     if (S_ISSOCK(stbuf->st_mode)) {
        !           988:         mode |= P9_STAT_MODE_SOCKET;
        !           989:     }
1.1       root      990: 
1.1.1.2 ! root      991:     if (S_ISFIFO(stbuf->st_mode)) {
        !           992:         mode |= P9_STAT_MODE_NAMED_PIPE;
        !           993:     }
1.1       root      994: 
1.1.1.2 ! root      995:     if (S_ISBLK(stbuf->st_mode) || S_ISCHR(stbuf->st_mode)) {
        !           996:         mode |= P9_STAT_MODE_DEVICE;
        !           997:     }
1.1       root      998: 
1.1.1.2 ! root      999:     if (stbuf->st_mode & S_ISUID) {
        !          1000:         mode |= P9_STAT_MODE_SETUID;
        !          1001:     }
1.1       root     1002: 
1.1.1.2 ! root     1003:     if (stbuf->st_mode & S_ISGID) {
        !          1004:         mode |= P9_STAT_MODE_SETGID;
        !          1005:     }
1.1       root     1006: 
1.1.1.2 ! root     1007:     if (stbuf->st_mode & S_ISVTX) {
        !          1008:         mode |= P9_STAT_MODE_SETVTX;
1.1       root     1009:     }
                   1010: 
                   1011:     return mode;
                   1012: }
                   1013: 
                   1014: static int stat_to_v9stat(V9fsState *s, V9fsString *name,
                   1015:                             const struct stat *stbuf,
                   1016:                             V9fsStat *v9stat)
                   1017: {
                   1018:     int err;
                   1019:     const char *str;
                   1020: 
                   1021:     memset(v9stat, 0, sizeof(*v9stat));
                   1022: 
                   1023:     stat_to_qid(stbuf, &v9stat->qid);
                   1024:     v9stat->mode = stat_to_v9mode(stbuf);
                   1025:     v9stat->atime = stbuf->st_atime;
                   1026:     v9stat->mtime = stbuf->st_mtime;
                   1027:     v9stat->length = stbuf->st_size;
                   1028: 
                   1029:     v9fs_string_null(&v9stat->uid);
                   1030:     v9fs_string_null(&v9stat->gid);
                   1031:     v9fs_string_null(&v9stat->muid);
                   1032: 
1.1.1.2 ! root     1033:     v9stat->n_uid = stbuf->st_uid;
        !          1034:     v9stat->n_gid = stbuf->st_gid;
        !          1035:     v9stat->n_muid = 0;
        !          1036: 
        !          1037:     v9fs_string_null(&v9stat->extension);
        !          1038: 
        !          1039:     if (v9stat->mode & P9_STAT_MODE_SYMLINK) {
        !          1040:         err = v9fs_do_readlink(s, name, &v9stat->extension);
        !          1041:         if (err == -1) {
        !          1042:             err = -errno;
        !          1043:             return err;
1.1       root     1044:         }
1.1.1.2 ! root     1045:         v9stat->extension.data[err] = 0;
        !          1046:         v9stat->extension.size = err;
        !          1047:     } else if (v9stat->mode & P9_STAT_MODE_DEVICE) {
        !          1048:         v9fs_string_sprintf(&v9stat->extension, "%c %u %u",
        !          1049:                 S_ISCHR(stbuf->st_mode) ? 'c' : 'b',
        !          1050:                 major(stbuf->st_rdev), minor(stbuf->st_rdev));
        !          1051:     } else if (S_ISDIR(stbuf->st_mode) || S_ISREG(stbuf->st_mode)) {
        !          1052:         v9fs_string_sprintf(&v9stat->extension, "%s %lu",
        !          1053:                 "HARDLINKCOUNT", (unsigned long)stbuf->st_nlink);
1.1       root     1054:     }
                   1055: 
                   1056:     str = strrchr(name->data, '/');
                   1057:     if (str) {
                   1058:         str += 1;
                   1059:     } else {
                   1060:         str = name->data;
                   1061:     }
                   1062: 
                   1063:     v9fs_string_sprintf(&v9stat->name, "%s", str);
                   1064: 
                   1065:     v9stat->size = 61 +
                   1066:         v9fs_string_size(&v9stat->name) +
                   1067:         v9fs_string_size(&v9stat->uid) +
                   1068:         v9fs_string_size(&v9stat->gid) +
                   1069:         v9fs_string_size(&v9stat->muid) +
                   1070:         v9fs_string_size(&v9stat->extension);
                   1071:     return 0;
                   1072: }
                   1073: 
1.1.1.2 ! root     1074: #define P9_STATS_MODE          0x00000001ULL
        !          1075: #define P9_STATS_NLINK         0x00000002ULL
        !          1076: #define P9_STATS_UID           0x00000004ULL
        !          1077: #define P9_STATS_GID           0x00000008ULL
        !          1078: #define P9_STATS_RDEV          0x00000010ULL
        !          1079: #define P9_STATS_ATIME         0x00000020ULL
        !          1080: #define P9_STATS_MTIME         0x00000040ULL
        !          1081: #define P9_STATS_CTIME         0x00000080ULL
        !          1082: #define P9_STATS_INO           0x00000100ULL
        !          1083: #define P9_STATS_SIZE          0x00000200ULL
        !          1084: #define P9_STATS_BLOCKS        0x00000400ULL
        !          1085: 
        !          1086: #define P9_STATS_BTIME         0x00000800ULL
        !          1087: #define P9_STATS_GEN           0x00001000ULL
        !          1088: #define P9_STATS_DATA_VERSION  0x00002000ULL
        !          1089: 
        !          1090: #define P9_STATS_BASIC         0x000007ffULL /* Mask for fields up to BLOCKS */
        !          1091: #define P9_STATS_ALL           0x00003fffULL /* Mask for All fields above */
        !          1092: 
        !          1093: 
        !          1094: static void stat_to_v9stat_dotl(V9fsState *s, const struct stat *stbuf,
        !          1095:                             V9fsStatDotl *v9lstat)
        !          1096: {
        !          1097:     memset(v9lstat, 0, sizeof(*v9lstat));
        !          1098: 
        !          1099:     v9lstat->st_mode = stbuf->st_mode;
        !          1100:     v9lstat->st_nlink = stbuf->st_nlink;
        !          1101:     v9lstat->st_uid = stbuf->st_uid;
        !          1102:     v9lstat->st_gid = stbuf->st_gid;
        !          1103:     v9lstat->st_rdev = stbuf->st_rdev;
        !          1104:     v9lstat->st_size = stbuf->st_size;
        !          1105:     v9lstat->st_blksize = stbuf->st_blksize;
        !          1106:     v9lstat->st_blocks = stbuf->st_blocks;
        !          1107:     v9lstat->st_atime_sec = stbuf->st_atime;
        !          1108:     v9lstat->st_atime_nsec = stbuf->st_atim.tv_nsec;
        !          1109:     v9lstat->st_mtime_sec = stbuf->st_mtime;
        !          1110:     v9lstat->st_mtime_nsec = stbuf->st_mtim.tv_nsec;
        !          1111:     v9lstat->st_ctime_sec = stbuf->st_ctime;
        !          1112:     v9lstat->st_ctime_nsec = stbuf->st_ctim.tv_nsec;
        !          1113:     /* Currently we only support BASIC fields in stat */
        !          1114:     v9lstat->st_result_mask = P9_STATS_BASIC;
        !          1115: 
        !          1116:     stat_to_qid(stbuf, &v9lstat->qid);
        !          1117: }
        !          1118: 
1.1       root     1119: static struct iovec *adjust_sg(struct iovec *sg, int len, int *iovcnt)
                   1120: {
                   1121:     while (len && *iovcnt) {
                   1122:         if (len < sg->iov_len) {
                   1123:             sg->iov_len -= len;
                   1124:             sg->iov_base += len;
                   1125:             len = 0;
                   1126:         } else {
                   1127:             len -= sg->iov_len;
                   1128:             sg++;
                   1129:             *iovcnt -= 1;
                   1130:         }
                   1131:     }
                   1132: 
                   1133:     return sg;
                   1134: }
                   1135: 
                   1136: static struct iovec *cap_sg(struct iovec *sg, int cap, int *cnt)
                   1137: {
                   1138:     int i;
                   1139:     int total = 0;
                   1140: 
                   1141:     for (i = 0; i < *cnt; i++) {
                   1142:         if ((total + sg[i].iov_len) > cap) {
                   1143:             sg[i].iov_len -= ((total + sg[i].iov_len) - cap);
                   1144:             i++;
                   1145:             break;
                   1146:         }
                   1147:         total += sg[i].iov_len;
                   1148:     }
                   1149: 
                   1150:     *cnt = i;
                   1151: 
                   1152:     return sg;
                   1153: }
                   1154: 
                   1155: static void print_sg(struct iovec *sg, int cnt)
                   1156: {
                   1157:     int i;
                   1158: 
                   1159:     printf("sg[%d]: {", cnt);
                   1160:     for (i = 0; i < cnt; i++) {
                   1161:         if (i) {
                   1162:             printf(", ");
                   1163:         }
                   1164:         printf("(%p, %zd)", sg[i].iov_base, sg[i].iov_len);
                   1165:     }
                   1166:     printf("}\n");
                   1167: }
                   1168: 
                   1169: static void v9fs_fix_path(V9fsString *dst, V9fsString *src, int len)
                   1170: {
                   1171:     V9fsString str;
                   1172:     v9fs_string_init(&str);
                   1173:     v9fs_string_copy(&str, dst);
                   1174:     v9fs_string_sprintf(dst, "%s%s", src->data, str.data+len);
                   1175:     v9fs_string_free(&str);
                   1176: }
                   1177: 
                   1178: static void v9fs_version(V9fsState *s, V9fsPDU *pdu)
                   1179: {
                   1180:     V9fsString version;
                   1181:     size_t offset = 7;
                   1182: 
1.1.1.2 ! root     1183:     pdu_unmarshal(pdu, offset, "ds", &s->msize, &version);
1.1       root     1184: 
1.1.1.2 ! root     1185:     if (!strcmp(version.data, "9P2000.u")) {
        !          1186:         s->proto_version = V9FS_PROTO_2000U;
        !          1187:     } else if (!strcmp(version.data, "9P2000.L")) {
        !          1188:         s->proto_version = V9FS_PROTO_2000L;
        !          1189:     } else {
1.1       root     1190:         v9fs_string_sprintf(&version, "unknown");
                   1191:     }
                   1192: 
1.1.1.2 ! root     1193:     offset += pdu_marshal(pdu, offset, "ds", s->msize, &version);
1.1       root     1194:     complete_pdu(s, pdu, offset);
                   1195: 
                   1196:     v9fs_string_free(&version);
                   1197: }
                   1198: 
                   1199: static void v9fs_attach(V9fsState *s, V9fsPDU *pdu)
                   1200: {
                   1201:     int32_t fid, afid, n_uname;
                   1202:     V9fsString uname, aname;
                   1203:     V9fsFidState *fidp;
                   1204:     V9fsQID qid;
                   1205:     size_t offset = 7;
                   1206:     ssize_t err;
                   1207: 
                   1208:     pdu_unmarshal(pdu, offset, "ddssd", &fid, &afid, &uname, &aname, &n_uname);
                   1209: 
                   1210:     fidp = alloc_fid(s, fid);
                   1211:     if (fidp == NULL) {
                   1212:         err = -EINVAL;
                   1213:         goto out;
                   1214:     }
                   1215: 
                   1216:     fidp->uid = n_uname;
                   1217: 
                   1218:     v9fs_string_sprintf(&fidp->path, "%s", "/");
                   1219:     err = fid_to_qid(s, fidp, &qid);
                   1220:     if (err) {
                   1221:         err = -EINVAL;
                   1222:         free_fid(s, fid);
                   1223:         goto out;
                   1224:     }
                   1225: 
                   1226:     offset += pdu_marshal(pdu, offset, "Q", &qid);
                   1227: 
                   1228:     err = offset;
                   1229: out:
                   1230:     complete_pdu(s, pdu, err);
                   1231:     v9fs_string_free(&uname);
                   1232:     v9fs_string_free(&aname);
                   1233: }
                   1234: 
                   1235: static void v9fs_stat_post_lstat(V9fsState *s, V9fsStatState *vs, int err)
                   1236: {
                   1237:     if (err == -1) {
                   1238:         err = -errno;
                   1239:         goto out;
                   1240:     }
                   1241: 
                   1242:     err = stat_to_v9stat(s, &vs->fidp->path, &vs->stbuf, &vs->v9stat);
                   1243:     if (err) {
                   1244:         goto out;
                   1245:     }
                   1246:     vs->offset += pdu_marshal(vs->pdu, vs->offset, "wS", 0, &vs->v9stat);
                   1247:     err = vs->offset;
                   1248: 
                   1249: out:
                   1250:     complete_pdu(s, vs->pdu, err);
                   1251:     v9fs_stat_free(&vs->v9stat);
                   1252:     qemu_free(vs);
                   1253: }
                   1254: 
                   1255: static void v9fs_stat(V9fsState *s, V9fsPDU *pdu)
                   1256: {
                   1257:     int32_t fid;
                   1258:     V9fsStatState *vs;
                   1259:     ssize_t err = 0;
                   1260: 
                   1261:     vs = qemu_malloc(sizeof(*vs));
                   1262:     vs->pdu = pdu;
                   1263:     vs->offset = 7;
                   1264: 
                   1265:     memset(&vs->v9stat, 0, sizeof(vs->v9stat));
                   1266: 
                   1267:     pdu_unmarshal(vs->pdu, vs->offset, "d", &fid);
                   1268: 
                   1269:     vs->fidp = lookup_fid(s, fid);
                   1270:     if (vs->fidp == NULL) {
                   1271:         err = -ENOENT;
                   1272:         goto out;
                   1273:     }
                   1274: 
                   1275:     err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
                   1276:     v9fs_stat_post_lstat(s, vs, err);
                   1277:     return;
                   1278: 
                   1279: out:
                   1280:     complete_pdu(s, vs->pdu, err);
                   1281:     v9fs_stat_free(&vs->v9stat);
                   1282:     qemu_free(vs);
                   1283: }
                   1284: 
1.1.1.2 ! root     1285: static void v9fs_getattr_post_lstat(V9fsState *s, V9fsStatStateDotl *vs,
        !          1286:                                                                 int err)
        !          1287: {
        !          1288:     if (err == -1) {
        !          1289:         err = -errno;
        !          1290:         goto out;
        !          1291:     }
        !          1292: 
        !          1293:     stat_to_v9stat_dotl(s, &vs->stbuf, &vs->v9stat_dotl);
        !          1294:     vs->offset += pdu_marshal(vs->pdu, vs->offset, "A", &vs->v9stat_dotl);
        !          1295:     err = vs->offset;
        !          1296: 
        !          1297: out:
        !          1298:     complete_pdu(s, vs->pdu, err);
        !          1299:     qemu_free(vs);
        !          1300: }
        !          1301: 
        !          1302: static void v9fs_getattr(V9fsState *s, V9fsPDU *pdu)
        !          1303: {
        !          1304:     int32_t fid;
        !          1305:     V9fsStatStateDotl *vs;
        !          1306:     ssize_t err = 0;
        !          1307:     V9fsFidState *fidp;
        !          1308:     uint64_t request_mask;
        !          1309: 
        !          1310:     vs = qemu_malloc(sizeof(*vs));
        !          1311:     vs->pdu = pdu;
        !          1312:     vs->offset = 7;
        !          1313: 
        !          1314:     memset(&vs->v9stat_dotl, 0, sizeof(vs->v9stat_dotl));
        !          1315: 
        !          1316:     pdu_unmarshal(vs->pdu, vs->offset, "dq", &fid, &request_mask);
        !          1317: 
        !          1318:     fidp = lookup_fid(s, fid);
        !          1319:     if (fidp == NULL) {
        !          1320:         err = -ENOENT;
        !          1321:         goto out;
        !          1322:     }
        !          1323: 
        !          1324:     /* Currently we only support BASIC fields in stat, so there is no
        !          1325:      * need to look at request_mask.
        !          1326:      */
        !          1327:     err = v9fs_do_lstat(s, &fidp->path, &vs->stbuf);
        !          1328:     v9fs_getattr_post_lstat(s, vs, err);
        !          1329:     return;
        !          1330: 
        !          1331: out:
        !          1332:     complete_pdu(s, vs->pdu, err);
        !          1333:     qemu_free(vs);
        !          1334: }
        !          1335: 
        !          1336: /* From Linux kernel code */
        !          1337: #define ATTR_MODE    (1 << 0)
        !          1338: #define ATTR_UID     (1 << 1)
        !          1339: #define ATTR_GID     (1 << 2)
        !          1340: #define ATTR_SIZE    (1 << 3)
        !          1341: #define ATTR_ATIME   (1 << 4)
        !          1342: #define ATTR_MTIME   (1 << 5)
        !          1343: #define ATTR_CTIME   (1 << 6)
        !          1344: #define ATTR_MASK    127
        !          1345: #define ATTR_ATIME_SET  (1 << 7)
        !          1346: #define ATTR_MTIME_SET  (1 << 8)
        !          1347: 
        !          1348: static void v9fs_setattr_post_truncate(V9fsState *s, V9fsSetattrState *vs,
        !          1349:                                                                   int err)
        !          1350: {
        !          1351:     if (err == -1) {
        !          1352:         err = -errno;
        !          1353:         goto out;
        !          1354:     }
        !          1355:     err = vs->offset;
        !          1356: 
        !          1357: out:
        !          1358:     complete_pdu(s, vs->pdu, err);
        !          1359:     qemu_free(vs);
        !          1360: }
        !          1361: 
        !          1362: static void v9fs_setattr_post_chown(V9fsState *s, V9fsSetattrState *vs, int err)
        !          1363: {
        !          1364:     if (err == -1) {
        !          1365:         err = -errno;
        !          1366:         goto out;
        !          1367:     }
        !          1368: 
        !          1369:     if (vs->v9iattr.valid & (ATTR_SIZE)) {
        !          1370:         err = v9fs_do_truncate(s, &vs->fidp->path, vs->v9iattr.size);
        !          1371:     }
        !          1372:     v9fs_setattr_post_truncate(s, vs, err);
        !          1373:     return;
        !          1374: 
        !          1375: out:
        !          1376:     complete_pdu(s, vs->pdu, err);
        !          1377:     qemu_free(vs);
        !          1378: }
        !          1379: 
        !          1380: static void v9fs_setattr_post_utimensat(V9fsState *s, V9fsSetattrState *vs,
        !          1381:                                                                    int err)
        !          1382: {
        !          1383:     if (err == -1) {
        !          1384:         err = -errno;
        !          1385:         goto out;
        !          1386:     }
        !          1387: 
        !          1388:     /* If the only valid entry in iattr is ctime we can call
        !          1389:      * chown(-1,-1) to update the ctime of the file
        !          1390:      */
        !          1391:     if ((vs->v9iattr.valid & (ATTR_UID | ATTR_GID)) ||
        !          1392:             ((vs->v9iattr.valid & ATTR_CTIME)
        !          1393:             && !((vs->v9iattr.valid & ATTR_MASK) & ~ATTR_CTIME))) {
        !          1394:         if (!(vs->v9iattr.valid & ATTR_UID)) {
        !          1395:             vs->v9iattr.uid = -1;
        !          1396:         }
        !          1397:         if (!(vs->v9iattr.valid & ATTR_GID)) {
        !          1398:             vs->v9iattr.gid = -1;
        !          1399:         }
        !          1400:         err = v9fs_do_chown(s, &vs->fidp->path, vs->v9iattr.uid,
        !          1401:                                                 vs->v9iattr.gid);
        !          1402:     }
        !          1403:     v9fs_setattr_post_chown(s, vs, err);
        !          1404:     return;
        !          1405: 
        !          1406: out:
        !          1407:     complete_pdu(s, vs->pdu, err);
        !          1408:     qemu_free(vs);
        !          1409: }
        !          1410: 
        !          1411: static void v9fs_setattr_post_chmod(V9fsState *s, V9fsSetattrState *vs, int err)
        !          1412: {
        !          1413:     if (err == -1) {
        !          1414:         err = -errno;
        !          1415:         goto out;
        !          1416:     }
        !          1417: 
        !          1418:     if (vs->v9iattr.valid & (ATTR_ATIME | ATTR_MTIME)) {
        !          1419:         struct timespec times[2];
        !          1420:         if (vs->v9iattr.valid & ATTR_ATIME) {
        !          1421:             if (vs->v9iattr.valid & ATTR_ATIME_SET) {
        !          1422:                 times[0].tv_sec = vs->v9iattr.atime_sec;
        !          1423:                 times[0].tv_nsec = vs->v9iattr.atime_nsec;
        !          1424:             } else {
        !          1425:                 times[0].tv_nsec = UTIME_NOW;
        !          1426:             }
        !          1427:         } else {
        !          1428:             times[0].tv_nsec = UTIME_OMIT;
        !          1429:         }
        !          1430: 
        !          1431:         if (vs->v9iattr.valid & ATTR_MTIME) {
        !          1432:             if (vs->v9iattr.valid & ATTR_MTIME_SET) {
        !          1433:                 times[1].tv_sec = vs->v9iattr.mtime_sec;
        !          1434:                 times[1].tv_nsec = vs->v9iattr.mtime_nsec;
        !          1435:             } else {
        !          1436:                 times[1].tv_nsec = UTIME_NOW;
        !          1437:             }
        !          1438:         } else {
        !          1439:             times[1].tv_nsec = UTIME_OMIT;
        !          1440:         }
        !          1441:         err = v9fs_do_utimensat(s, &vs->fidp->path, times);
        !          1442:     }
        !          1443:     v9fs_setattr_post_utimensat(s, vs, err);
        !          1444:     return;
        !          1445: 
        !          1446: out:
        !          1447:     complete_pdu(s, vs->pdu, err);
        !          1448:     qemu_free(vs);
        !          1449: }
        !          1450: 
        !          1451: static void v9fs_setattr(V9fsState *s, V9fsPDU *pdu)
        !          1452: {
        !          1453:     int32_t fid;
        !          1454:     V9fsSetattrState *vs;
        !          1455:     int err = 0;
        !          1456: 
        !          1457:     vs = qemu_malloc(sizeof(*vs));
        !          1458:     vs->pdu = pdu;
        !          1459:     vs->offset = 7;
        !          1460: 
        !          1461:     pdu_unmarshal(pdu, vs->offset, "dI", &fid, &vs->v9iattr);
        !          1462: 
        !          1463:     vs->fidp = lookup_fid(s, fid);
        !          1464:     if (vs->fidp == NULL) {
        !          1465:         err = -EINVAL;
        !          1466:         goto out;
        !          1467:     }
        !          1468: 
        !          1469:     if (vs->v9iattr.valid & ATTR_MODE) {
        !          1470:         err = v9fs_do_chmod(s, &vs->fidp->path, vs->v9iattr.mode);
        !          1471:     }
        !          1472: 
        !          1473:     v9fs_setattr_post_chmod(s, vs, err);
        !          1474:     return;
        !          1475: 
        !          1476: out:
        !          1477:     complete_pdu(s, vs->pdu, err);
        !          1478:     qemu_free(vs);
        !          1479: }
        !          1480: 
1.1       root     1481: static void v9fs_walk_complete(V9fsState *s, V9fsWalkState *vs, int err)
                   1482: {
                   1483:     complete_pdu(s, vs->pdu, err);
                   1484: 
                   1485:     if (vs->nwnames) {
                   1486:         for (vs->name_idx = 0; vs->name_idx < vs->nwnames; vs->name_idx++) {
                   1487:             v9fs_string_free(&vs->wnames[vs->name_idx]);
                   1488:         }
                   1489: 
                   1490:         qemu_free(vs->wnames);
                   1491:         qemu_free(vs->qids);
                   1492:     }
                   1493: }
                   1494: 
                   1495: static void v9fs_walk_marshal(V9fsWalkState *vs)
                   1496: {
                   1497:     int i;
                   1498:     vs->offset = 7;
                   1499:     vs->offset += pdu_marshal(vs->pdu, vs->offset, "w", vs->nwnames);
                   1500: 
                   1501:     for (i = 0; i < vs->nwnames; i++) {
                   1502:         vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qids[i]);
                   1503:     }
                   1504: }
                   1505: 
                   1506: static void v9fs_walk_post_newfid_lstat(V9fsState *s, V9fsWalkState *vs,
                   1507:                                                                 int err)
                   1508: {
                   1509:     if (err == -1) {
                   1510:         free_fid(s, vs->newfidp->fid);
                   1511:         v9fs_string_free(&vs->path);
                   1512:         err = -ENOENT;
                   1513:         goto out;
                   1514:     }
                   1515: 
                   1516:     stat_to_qid(&vs->stbuf, &vs->qids[vs->name_idx]);
                   1517: 
                   1518:     vs->name_idx++;
                   1519:     if (vs->name_idx < vs->nwnames) {
                   1520:         v9fs_string_sprintf(&vs->path, "%s/%s", vs->newfidp->path.data,
                   1521:                                             vs->wnames[vs->name_idx].data);
                   1522:         v9fs_string_copy(&vs->newfidp->path, &vs->path);
                   1523: 
                   1524:         err = v9fs_do_lstat(s, &vs->newfidp->path, &vs->stbuf);
                   1525:         v9fs_walk_post_newfid_lstat(s, vs, err);
                   1526:         return;
                   1527:     }
                   1528: 
                   1529:     v9fs_string_free(&vs->path);
                   1530:     v9fs_walk_marshal(vs);
                   1531:     err = vs->offset;
                   1532: out:
                   1533:     v9fs_walk_complete(s, vs, err);
                   1534: }
                   1535: 
                   1536: static void v9fs_walk_post_oldfid_lstat(V9fsState *s, V9fsWalkState *vs,
                   1537:         int err)
                   1538: {
                   1539:     if (err == -1) {
                   1540:         v9fs_string_free(&vs->path);
                   1541:         err = -ENOENT;
                   1542:         goto out;
                   1543:     }
                   1544: 
                   1545:     stat_to_qid(&vs->stbuf, &vs->qids[vs->name_idx]);
                   1546:     vs->name_idx++;
                   1547:     if (vs->name_idx < vs->nwnames) {
                   1548: 
                   1549:         v9fs_string_sprintf(&vs->path, "%s/%s",
                   1550:                 vs->fidp->path.data, vs->wnames[vs->name_idx].data);
                   1551:         v9fs_string_copy(&vs->fidp->path, &vs->path);
                   1552: 
                   1553:         err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
                   1554:         v9fs_walk_post_oldfid_lstat(s, vs, err);
                   1555:         return;
                   1556:     }
                   1557: 
                   1558:     v9fs_string_free(&vs->path);
                   1559:     v9fs_walk_marshal(vs);
                   1560:     err = vs->offset;
                   1561: out:
                   1562:     v9fs_walk_complete(s, vs, err);
                   1563: }
                   1564: 
                   1565: static void v9fs_walk(V9fsState *s, V9fsPDU *pdu)
                   1566: {
                   1567:     int32_t fid, newfid;
                   1568:     V9fsWalkState *vs;
                   1569:     int err = 0;
                   1570:     int i;
                   1571: 
                   1572:     vs = qemu_malloc(sizeof(*vs));
                   1573:     vs->pdu = pdu;
                   1574:     vs->wnames = NULL;
                   1575:     vs->qids = NULL;
                   1576:     vs->offset = 7;
                   1577: 
                   1578:     vs->offset += pdu_unmarshal(vs->pdu, vs->offset, "ddw", &fid,
                   1579:                                             &newfid, &vs->nwnames);
                   1580: 
                   1581:     if (vs->nwnames) {
                   1582:         vs->wnames = qemu_mallocz(sizeof(vs->wnames[0]) * vs->nwnames);
                   1583: 
                   1584:         vs->qids = qemu_mallocz(sizeof(vs->qids[0]) * vs->nwnames);
                   1585: 
                   1586:         for (i = 0; i < vs->nwnames; i++) {
                   1587:             vs->offset += pdu_unmarshal(vs->pdu, vs->offset, "s",
                   1588:                                             &vs->wnames[i]);
                   1589:         }
                   1590:     }
                   1591: 
                   1592:     vs->fidp = lookup_fid(s, fid);
                   1593:     if (vs->fidp == NULL) {
                   1594:         err = -ENOENT;
                   1595:         goto out;
                   1596:     }
                   1597: 
                   1598:     /* FIXME: is this really valid? */
                   1599:     if (fid == newfid) {
                   1600: 
1.1.1.2 ! root     1601:         BUG_ON(vs->fidp->fid_type != P9_FID_NONE);
1.1       root     1602:         v9fs_string_init(&vs->path);
                   1603:         vs->name_idx = 0;
                   1604: 
                   1605:         if (vs->name_idx < vs->nwnames) {
                   1606:             v9fs_string_sprintf(&vs->path, "%s/%s",
                   1607:                 vs->fidp->path.data, vs->wnames[vs->name_idx].data);
                   1608:             v9fs_string_copy(&vs->fidp->path, &vs->path);
                   1609: 
                   1610:             err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
                   1611:             v9fs_walk_post_oldfid_lstat(s, vs, err);
                   1612:             return;
                   1613:         }
                   1614:     } else {
                   1615:         vs->newfidp = alloc_fid(s, newfid);
                   1616:         if (vs->newfidp == NULL) {
                   1617:             err = -EINVAL;
                   1618:             goto out;
                   1619:         }
                   1620: 
                   1621:         vs->newfidp->uid = vs->fidp->uid;
                   1622:         v9fs_string_init(&vs->path);
                   1623:         vs->name_idx = 0;
                   1624:         v9fs_string_copy(&vs->newfidp->path, &vs->fidp->path);
                   1625: 
                   1626:         if (vs->name_idx < vs->nwnames) {
                   1627:             v9fs_string_sprintf(&vs->path, "%s/%s", vs->newfidp->path.data,
                   1628:                                 vs->wnames[vs->name_idx].data);
                   1629:             v9fs_string_copy(&vs->newfidp->path, &vs->path);
                   1630: 
                   1631:             err = v9fs_do_lstat(s, &vs->newfidp->path, &vs->stbuf);
                   1632:             v9fs_walk_post_newfid_lstat(s, vs, err);
                   1633:             return;
                   1634:         }
                   1635:     }
                   1636: 
                   1637:     v9fs_walk_marshal(vs);
                   1638:     err = vs->offset;
                   1639: out:
                   1640:     v9fs_walk_complete(s, vs, err);
                   1641: }
                   1642: 
1.1.1.2 ! root     1643: static int32_t get_iounit(V9fsState *s, V9fsString *name)
        !          1644: {
        !          1645:     struct statfs stbuf;
        !          1646:     int32_t iounit = 0;
        !          1647: 
        !          1648:     /*
        !          1649:      * iounit should be multiples of f_bsize (host filesystem block size
        !          1650:      * and as well as less than (client msize - P9_IOHDRSZ))
        !          1651:      */
        !          1652:     if (!v9fs_do_statfs(s, name, &stbuf)) {
        !          1653:         iounit = stbuf.f_bsize;
        !          1654:         iounit *= (s->msize - P9_IOHDRSZ)/stbuf.f_bsize;
        !          1655:     }
        !          1656: 
        !          1657:     if (!iounit) {
        !          1658:         iounit = s->msize - P9_IOHDRSZ;
        !          1659:     }
        !          1660:     return iounit;
        !          1661: }
        !          1662: 
1.1       root     1663: static void v9fs_open_post_opendir(V9fsState *s, V9fsOpenState *vs, int err)
                   1664: {
1.1.1.2 ! root     1665:     if (vs->fidp->fs.dir == NULL) {
1.1       root     1666:         err = -errno;
                   1667:         goto out;
                   1668:     }
1.1.1.2 ! root     1669:     vs->fidp->fid_type = P9_FID_DIR;
1.1       root     1670:     vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, 0);
                   1671:     err = vs->offset;
                   1672: out:
                   1673:     complete_pdu(s, vs->pdu, err);
                   1674:     qemu_free(vs);
                   1675: 
                   1676: }
                   1677: 
1.1.1.2 ! root     1678: static void v9fs_open_post_getiounit(V9fsState *s, V9fsOpenState *vs)
        !          1679: {
        !          1680:     int err;
        !          1681:     vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, vs->iounit);
        !          1682:     err = vs->offset;
        !          1683:     complete_pdu(s, vs->pdu, err);
        !          1684:     qemu_free(vs);
        !          1685: }
        !          1686: 
1.1       root     1687: static void v9fs_open_post_open(V9fsState *s, V9fsOpenState *vs, int err)
                   1688: {
1.1.1.2 ! root     1689:     if (vs->fidp->fs.fd == -1) {
1.1       root     1690:         err = -errno;
                   1691:         goto out;
                   1692:     }
1.1.1.2 ! root     1693:     vs->fidp->fid_type = P9_FID_FILE;
        !          1694:     vs->iounit = get_iounit(s, &vs->fidp->path);
        !          1695:     v9fs_open_post_getiounit(s, vs);
        !          1696:     return;
1.1       root     1697: out:
                   1698:     complete_pdu(s, vs->pdu, err);
                   1699:     qemu_free(vs);
                   1700: }
                   1701: 
                   1702: static void v9fs_open_post_lstat(V9fsState *s, V9fsOpenState *vs, int err)
                   1703: {
1.1.1.2 ! root     1704:     int flags;
        !          1705: 
1.1       root     1706:     if (err) {
                   1707:         err = -errno;
                   1708:         goto out;
                   1709:     }
                   1710: 
                   1711:     stat_to_qid(&vs->stbuf, &vs->qid);
                   1712: 
                   1713:     if (S_ISDIR(vs->stbuf.st_mode)) {
1.1.1.2 ! root     1714:         vs->fidp->fs.dir = v9fs_do_opendir(s, &vs->fidp->path);
1.1       root     1715:         v9fs_open_post_opendir(s, vs, err);
                   1716:     } else {
1.1.1.2 ! root     1717:         if (s->proto_version == V9FS_PROTO_2000L) {
        !          1718:             flags = vs->mode;
        !          1719:             flags &= ~(O_NOCTTY | O_ASYNC | O_CREAT);
        !          1720:             /* Ignore direct disk access hint until the server supports it. */
        !          1721:             flags &= ~O_DIRECT;
        !          1722:         } else {
        !          1723:             flags = omode_to_uflags(vs->mode);
        !          1724:         }
        !          1725:         vs->fidp->fs.fd = v9fs_do_open(s, &vs->fidp->path, flags);
1.1       root     1726:         v9fs_open_post_open(s, vs, err);
                   1727:     }
                   1728:     return;
                   1729: out:
                   1730:     complete_pdu(s, vs->pdu, err);
                   1731:     qemu_free(vs);
                   1732: }
                   1733: 
                   1734: static void v9fs_open(V9fsState *s, V9fsPDU *pdu)
                   1735: {
                   1736:     int32_t fid;
                   1737:     V9fsOpenState *vs;
                   1738:     ssize_t err = 0;
                   1739: 
                   1740:     vs = qemu_malloc(sizeof(*vs));
                   1741:     vs->pdu = pdu;
                   1742:     vs->offset = 7;
1.1.1.2 ! root     1743:     vs->mode = 0;
1.1       root     1744: 
1.1.1.2 ! root     1745:     if (s->proto_version == V9FS_PROTO_2000L) {
        !          1746:         pdu_unmarshal(vs->pdu, vs->offset, "dd", &fid, &vs->mode);
        !          1747:     } else {
        !          1748:         pdu_unmarshal(vs->pdu, vs->offset, "db", &fid, &vs->mode);
        !          1749:     }
1.1       root     1750: 
                   1751:     vs->fidp = lookup_fid(s, fid);
                   1752:     if (vs->fidp == NULL) {
                   1753:         err = -ENOENT;
                   1754:         goto out;
                   1755:     }
                   1756: 
1.1.1.2 ! root     1757:     BUG_ON(vs->fidp->fid_type != P9_FID_NONE);
1.1       root     1758: 
                   1759:     err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
                   1760: 
                   1761:     v9fs_open_post_lstat(s, vs, err);
                   1762:     return;
                   1763: out:
                   1764:     complete_pdu(s, pdu, err);
                   1765:     qemu_free(vs);
                   1766: }
                   1767: 
1.1.1.2 ! root     1768: static void v9fs_post_lcreate(V9fsState *s, V9fsLcreateState *vs, int err)
1.1       root     1769: {
1.1.1.2 ! root     1770:     if (err == 0) {
        !          1771:         v9fs_string_copy(&vs->fidp->path, &vs->fullname);
        !          1772:         stat_to_qid(&vs->stbuf, &vs->qid);
        !          1773:         vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid,
        !          1774:                 &vs->iounit);
        !          1775:         err = vs->offset;
        !          1776:     } else {
        !          1777:         vs->fidp->fid_type = P9_FID_NONE;
        !          1778:         err = -errno;
        !          1779:         if (vs->fidp->fs.fd > 0) {
        !          1780:             close(vs->fidp->fs.fd);
        !          1781:         }
1.1       root     1782:     }
                   1783: 
1.1.1.2 ! root     1784:     complete_pdu(s, vs->pdu, err);
        !          1785:     v9fs_string_free(&vs->name);
        !          1786:     v9fs_string_free(&vs->fullname);
        !          1787:     qemu_free(vs);
        !          1788: }
        !          1789: 
        !          1790: static void v9fs_lcreate_post_get_iounit(V9fsState *s, V9fsLcreateState *vs,
        !          1791:         int err)
        !          1792: {
        !          1793:     if (err) {
        !          1794:         err = -errno;
        !          1795:         goto out;
        !          1796:     }
        !          1797:     err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
        !          1798: 
        !          1799: out:
        !          1800:     v9fs_post_lcreate(s, vs, err);
        !          1801: }
        !          1802: 
        !          1803: static void v9fs_lcreate_post_do_open2(V9fsState *s, V9fsLcreateState *vs,
        !          1804:         int err)
        !          1805: {
        !          1806:     if (vs->fidp->fs.fd == -1) {
        !          1807:         err = -errno;
        !          1808:         goto out;
        !          1809:     }
        !          1810:     vs->fidp->fid_type = P9_FID_FILE;
        !          1811:     vs->iounit =  get_iounit(s, &vs->fullname);
        !          1812:     v9fs_lcreate_post_get_iounit(s, vs, err);
        !          1813:     return;
        !          1814: 
        !          1815: out:
        !          1816:     v9fs_post_lcreate(s, vs, err);
        !          1817: }
        !          1818: 
        !          1819: static void v9fs_lcreate(V9fsState *s, V9fsPDU *pdu)
        !          1820: {
        !          1821:     int32_t dfid, flags, mode;
        !          1822:     gid_t gid;
        !          1823:     V9fsLcreateState *vs;
        !          1824:     ssize_t err = 0;
        !          1825: 
        !          1826:     vs = qemu_malloc(sizeof(*vs));
        !          1827:     vs->pdu = pdu;
        !          1828:     vs->offset = 7;
        !          1829: 
        !          1830:     v9fs_string_init(&vs->fullname);
        !          1831: 
        !          1832:     pdu_unmarshal(vs->pdu, vs->offset, "dsddd", &dfid, &vs->name, &flags,
        !          1833:             &mode, &gid);
        !          1834: 
        !          1835:     vs->fidp = lookup_fid(s, dfid);
        !          1836:     if (vs->fidp == NULL) {
        !          1837:         err = -ENOENT;
        !          1838:         goto out;
        !          1839:     }
        !          1840: 
        !          1841:     v9fs_string_sprintf(&vs->fullname, "%s/%s", vs->fidp->path.data,
        !          1842:              vs->name.data);
        !          1843: 
        !          1844:     /* Ignore direct disk access hint until the server supports it. */
        !          1845:     flags &= ~O_DIRECT;
        !          1846: 
        !          1847:     vs->fidp->fs.fd = v9fs_do_open2(s, vs->fullname.data, vs->fidp->uid,
        !          1848:             gid, flags, mode);
        !          1849:     v9fs_lcreate_post_do_open2(s, vs, err);
        !          1850:     return;
        !          1851: 
        !          1852: out:
        !          1853:     complete_pdu(s, vs->pdu, err);
        !          1854:     v9fs_string_free(&vs->name);
        !          1855:     qemu_free(vs);
        !          1856: }
        !          1857: 
        !          1858: static void v9fs_post_do_fsync(V9fsState *s, V9fsPDU *pdu, int err)
        !          1859: {
        !          1860:     if (err == -1) {
        !          1861:         err = -errno;
        !          1862:     }
        !          1863:     complete_pdu(s, pdu, err);
        !          1864: }
        !          1865: 
        !          1866: static void v9fs_fsync(V9fsState *s, V9fsPDU *pdu)
        !          1867: {
        !          1868:     int32_t fid;
        !          1869:     size_t offset = 7;
        !          1870:     V9fsFidState *fidp;
        !          1871:     int datasync;
        !          1872:     int err;
        !          1873: 
        !          1874:     pdu_unmarshal(pdu, offset, "dd", &fid, &datasync);
        !          1875:     fidp = lookup_fid(s, fid);
        !          1876:     if (fidp == NULL) {
        !          1877:         err = -ENOENT;
        !          1878:         v9fs_post_do_fsync(s, pdu, err);
        !          1879:         return;
        !          1880:     }
        !          1881:     err = v9fs_do_fsync(s, fidp->fs.fd, datasync);
        !          1882:     v9fs_post_do_fsync(s, pdu, err);
        !          1883: }
        !          1884: 
        !          1885: static void v9fs_clunk(V9fsState *s, V9fsPDU *pdu)
        !          1886: {
        !          1887:     int32_t fid;
        !          1888:     size_t offset = 7;
        !          1889:     int err;
        !          1890: 
        !          1891:     pdu_unmarshal(pdu, offset, "d", &fid);
        !          1892: 
        !          1893:     err = free_fid(s, fid);
        !          1894:     if (err < 0) {
        !          1895:         goto out;
        !          1896:     }
        !          1897: 
        !          1898:     offset = 7;
        !          1899:     err = offset;
        !          1900: out:
        !          1901:     complete_pdu(s, pdu, err);
        !          1902: }
1.1       root     1903: 
                   1904: static void v9fs_read_post_readdir(V9fsState *, V9fsReadState *, ssize_t);
                   1905: 
                   1906: static void v9fs_read_post_seekdir(V9fsState *s, V9fsReadState *vs, ssize_t err)
                   1907: {
                   1908:     if (err) {
                   1909:         goto out;
                   1910:     }
                   1911:     v9fs_stat_free(&vs->v9stat);
                   1912:     v9fs_string_free(&vs->name);
                   1913:     vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
                   1914:     vs->offset += vs->count;
                   1915:     err = vs->offset;
                   1916: out:
                   1917:     complete_pdu(s, vs->pdu, err);
                   1918:     qemu_free(vs);
                   1919:     return;
                   1920: }
                   1921: 
                   1922: static void v9fs_read_post_dir_lstat(V9fsState *s, V9fsReadState *vs,
                   1923:                                     ssize_t err)
                   1924: {
                   1925:     if (err) {
                   1926:         err = -errno;
                   1927:         goto out;
                   1928:     }
                   1929:     err = stat_to_v9stat(s, &vs->name, &vs->stbuf, &vs->v9stat);
                   1930:     if (err) {
                   1931:         goto out;
                   1932:     }
                   1933: 
                   1934:     vs->len = pdu_marshal(vs->pdu, vs->offset + 4 + vs->count, "S",
                   1935:                             &vs->v9stat);
                   1936:     if ((vs->len != (vs->v9stat.size + 2)) ||
                   1937:             ((vs->count + vs->len) > vs->max_count)) {
1.1.1.2 ! root     1938:         v9fs_do_seekdir(s, vs->fidp->fs.dir, vs->dir_pos);
1.1       root     1939:         v9fs_read_post_seekdir(s, vs, err);
                   1940:         return;
                   1941:     }
                   1942:     vs->count += vs->len;
                   1943:     v9fs_stat_free(&vs->v9stat);
                   1944:     v9fs_string_free(&vs->name);
                   1945:     vs->dir_pos = vs->dent->d_off;
1.1.1.2 ! root     1946:     vs->dent = v9fs_do_readdir(s, vs->fidp->fs.dir);
1.1       root     1947:     v9fs_read_post_readdir(s, vs, err);
                   1948:     return;
                   1949: out:
1.1.1.2 ! root     1950:     v9fs_do_seekdir(s, vs->fidp->fs.dir, vs->dir_pos);
1.1       root     1951:     v9fs_read_post_seekdir(s, vs, err);
                   1952:     return;
                   1953: 
                   1954: }
                   1955: 
                   1956: static void v9fs_read_post_readdir(V9fsState *s, V9fsReadState *vs, ssize_t err)
                   1957: {
                   1958:     if (vs->dent) {
                   1959:         memset(&vs->v9stat, 0, sizeof(vs->v9stat));
                   1960:         v9fs_string_init(&vs->name);
                   1961:         v9fs_string_sprintf(&vs->name, "%s/%s", vs->fidp->path.data,
                   1962:                             vs->dent->d_name);
                   1963:         err = v9fs_do_lstat(s, &vs->name, &vs->stbuf);
                   1964:         v9fs_read_post_dir_lstat(s, vs, err);
                   1965:         return;
                   1966:     }
                   1967: 
                   1968:     vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
                   1969:     vs->offset += vs->count;
                   1970:     err = vs->offset;
                   1971:     complete_pdu(s, vs->pdu, err);
                   1972:     qemu_free(vs);
                   1973:     return;
                   1974: }
                   1975: 
                   1976: static void v9fs_read_post_telldir(V9fsState *s, V9fsReadState *vs, ssize_t err)
                   1977: {
1.1.1.2 ! root     1978:     vs->dent = v9fs_do_readdir(s, vs->fidp->fs.dir);
1.1       root     1979:     v9fs_read_post_readdir(s, vs, err);
                   1980:     return;
                   1981: }
                   1982: 
                   1983: static void v9fs_read_post_rewinddir(V9fsState *s, V9fsReadState *vs,
                   1984:                                        ssize_t err)
                   1985: {
1.1.1.2 ! root     1986:     vs->dir_pos = v9fs_do_telldir(s, vs->fidp->fs.dir);
1.1       root     1987:     v9fs_read_post_telldir(s, vs, err);
                   1988:     return;
                   1989: }
                   1990: 
1.1.1.2 ! root     1991: static void v9fs_read_post_preadv(V9fsState *s, V9fsReadState *vs, ssize_t err)
1.1       root     1992: {
                   1993:     if (err  < 0) {
                   1994:         /* IO error return the error */
                   1995:         err = -errno;
                   1996:         goto out;
                   1997:     }
                   1998:     vs->total += vs->len;
                   1999:     vs->sg = adjust_sg(vs->sg, vs->len, &vs->cnt);
                   2000:     if (vs->total < vs->count && vs->len > 0) {
                   2001:         do {
                   2002:             if (0) {
                   2003:                 print_sg(vs->sg, vs->cnt);
                   2004:             }
1.1.1.2 ! root     2005:             vs->len = v9fs_do_preadv(s, vs->fidp->fs.fd, vs->sg, vs->cnt,
        !          2006:                       vs->off);
        !          2007:             if (vs->len > 0) {
        !          2008:                 vs->off += vs->len;
        !          2009:             }
1.1       root     2010:         } while (vs->len == -1 && errno == EINTR);
                   2011:         if (vs->len == -1) {
                   2012:             err  = -errno;
                   2013:         }
1.1.1.2 ! root     2014:         v9fs_read_post_preadv(s, vs, err);
1.1       root     2015:         return;
                   2016:     }
                   2017:     vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->total);
                   2018:     vs->offset += vs->count;
                   2019:     err = vs->offset;
                   2020: 
                   2021: out:
                   2022:     complete_pdu(s, vs->pdu, err);
                   2023:     qemu_free(vs);
                   2024: }
                   2025: 
1.1.1.2 ! root     2026: static void v9fs_xattr_read(V9fsState *s, V9fsReadState *vs)
1.1       root     2027: {
1.1.1.2 ! root     2028:     ssize_t err = 0;
        !          2029:     int read_count;
        !          2030:     int64_t xattr_len;
1.1       root     2031: 
1.1.1.2 ! root     2032:     xattr_len = vs->fidp->fs.xattr.len;
        !          2033:     read_count = xattr_len - vs->off;
        !          2034:     if (read_count > vs->count) {
        !          2035:         read_count = vs->count;
        !          2036:     } else if (read_count < 0) {
        !          2037:         /*
        !          2038:          * read beyond XATTR value
        !          2039:          */
        !          2040:         read_count = 0;
1.1       root     2041:     }
1.1.1.2 ! root     2042:     vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", read_count);
        !          2043:     vs->offset += pdu_pack(vs->pdu, vs->offset,
        !          2044:                            ((char *)vs->fidp->fs.xattr.value) + vs->off,
        !          2045:                            read_count);
        !          2046:     err = vs->offset;
1.1       root     2047:     complete_pdu(s, vs->pdu, err);
                   2048:     qemu_free(vs);
                   2049: }
                   2050: 
                   2051: static void v9fs_read(V9fsState *s, V9fsPDU *pdu)
                   2052: {
                   2053:     int32_t fid;
                   2054:     V9fsReadState *vs;
                   2055:     ssize_t err = 0;
                   2056: 
                   2057:     vs = qemu_malloc(sizeof(*vs));
                   2058:     vs->pdu = pdu;
                   2059:     vs->offset = 7;
                   2060:     vs->total = 0;
                   2061:     vs->len = 0;
                   2062:     vs->count = 0;
                   2063: 
                   2064:     pdu_unmarshal(vs->pdu, vs->offset, "dqd", &fid, &vs->off, &vs->count);
                   2065: 
                   2066:     vs->fidp = lookup_fid(s, fid);
                   2067:     if (vs->fidp == NULL) {
                   2068:         err = -EINVAL;
                   2069:         goto out;
                   2070:     }
                   2071: 
1.1.1.2 ! root     2072:     if (vs->fidp->fid_type == P9_FID_DIR) {
1.1       root     2073:         vs->max_count = vs->count;
                   2074:         vs->count = 0;
                   2075:         if (vs->off == 0) {
1.1.1.2 ! root     2076:             v9fs_do_rewinddir(s, vs->fidp->fs.dir);
1.1       root     2077:         }
                   2078:         v9fs_read_post_rewinddir(s, vs, err);
                   2079:         return;
1.1.1.2 ! root     2080:     } else if (vs->fidp->fid_type == P9_FID_FILE) {
1.1       root     2081:         vs->sg = vs->iov;
                   2082:         pdu_marshal(vs->pdu, vs->offset + 4, "v", vs->sg, &vs->cnt);
1.1.1.2 ! root     2083:         vs->sg = cap_sg(vs->sg, vs->count, &vs->cnt);
        !          2084:         if (vs->total <= vs->count) {
        !          2085:             vs->len = v9fs_do_preadv(s, vs->fidp->fs.fd, vs->sg, vs->cnt,
        !          2086:                                     vs->off);
        !          2087:             if (vs->len > 0) {
        !          2088:                 vs->off += vs->len;
        !          2089:             }
        !          2090:             err = vs->len;
        !          2091:             v9fs_read_post_preadv(s, vs, err);
        !          2092:         }
        !          2093:         return;
        !          2094:     } else if (vs->fidp->fid_type == P9_FID_XATTR) {
        !          2095:         v9fs_xattr_read(s, vs);
1.1       root     2096:         return;
                   2097:     } else {
                   2098:         err = -EINVAL;
                   2099:     }
                   2100: out:
                   2101:     complete_pdu(s, pdu, err);
                   2102:     qemu_free(vs);
                   2103: }
                   2104: 
1.1.1.2 ! root     2105: typedef struct V9fsReadDirState {
        !          2106:     V9fsPDU *pdu;
        !          2107:     V9fsFidState *fidp;
        !          2108:     V9fsQID qid;
        !          2109:     off_t saved_dir_pos;
        !          2110:     struct dirent *dent;
        !          2111:     int32_t count;
        !          2112:     int32_t max_count;
        !          2113:     size_t offset;
        !          2114:     int64_t initial_offset;
        !          2115:     V9fsString name;
        !          2116: } V9fsReadDirState;
        !          2117: 
        !          2118: static void v9fs_readdir_post_seekdir(V9fsState *s, V9fsReadDirState *vs)
        !          2119: {
        !          2120:     vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
        !          2121:     vs->offset += vs->count;
        !          2122:     complete_pdu(s, vs->pdu, vs->offset);
        !          2123:     qemu_free(vs);
        !          2124:     return;
        !          2125: }
        !          2126: 
        !          2127: /* Size of each dirent on the wire: size of qid (13) + size of offset (8)
        !          2128:  * size of type (1) + size of name.size (2) + strlen(name.data)
        !          2129:  */
        !          2130: #define V9_READDIR_DATA_SZ (24 + strlen(vs->name.data))
        !          2131: 
        !          2132: static void v9fs_readdir_post_readdir(V9fsState *s, V9fsReadDirState *vs)
        !          2133: {
        !          2134:     int len;
        !          2135:     size_t size;
        !          2136: 
        !          2137:     if (vs->dent) {
        !          2138:         v9fs_string_init(&vs->name);
        !          2139:         v9fs_string_sprintf(&vs->name, "%s", vs->dent->d_name);
        !          2140: 
        !          2141:         if ((vs->count + V9_READDIR_DATA_SZ) > vs->max_count) {
        !          2142:             /* Ran out of buffer. Set dir back to old position and return */
        !          2143:             v9fs_do_seekdir(s, vs->fidp->fs.dir, vs->saved_dir_pos);
        !          2144:             v9fs_readdir_post_seekdir(s, vs);
        !          2145:             return;
        !          2146:         }
        !          2147: 
        !          2148:         /* Fill up just the path field of qid because the client uses
        !          2149:          * only that. To fill the entire qid structure we will have
        !          2150:          * to stat each dirent found, which is expensive
        !          2151:          */
        !          2152:         size = MIN(sizeof(vs->dent->d_ino), sizeof(vs->qid.path));
        !          2153:         memcpy(&vs->qid.path, &vs->dent->d_ino, size);
        !          2154:         /* Fill the other fields with dummy values */
        !          2155:         vs->qid.type = 0;
        !          2156:         vs->qid.version = 0;
        !          2157: 
        !          2158:         len = pdu_marshal(vs->pdu, vs->offset+4+vs->count, "Qqbs",
        !          2159:                               &vs->qid, vs->dent->d_off,
        !          2160:                               vs->dent->d_type, &vs->name);
        !          2161:         vs->count += len;
        !          2162:         v9fs_string_free(&vs->name);
        !          2163:         vs->saved_dir_pos = vs->dent->d_off;
        !          2164:         vs->dent = v9fs_do_readdir(s, vs->fidp->fs.dir);
        !          2165:         v9fs_readdir_post_readdir(s, vs);
        !          2166:         return;
        !          2167:     }
        !          2168: 
        !          2169:     vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
        !          2170:     vs->offset += vs->count;
        !          2171:     complete_pdu(s, vs->pdu, vs->offset);
        !          2172:     qemu_free(vs);
        !          2173:     return;
        !          2174: }
        !          2175: 
        !          2176: static void v9fs_readdir_post_telldir(V9fsState *s, V9fsReadDirState *vs)
        !          2177: {
        !          2178:     vs->dent = v9fs_do_readdir(s, vs->fidp->fs.dir);
        !          2179:     v9fs_readdir_post_readdir(s, vs);
        !          2180:     return;
        !          2181: }
        !          2182: 
        !          2183: static void v9fs_readdir_post_setdir(V9fsState *s, V9fsReadDirState *vs)
        !          2184: {
        !          2185:     vs->saved_dir_pos = v9fs_do_telldir(s, vs->fidp->fs.dir);
        !          2186:     v9fs_readdir_post_telldir(s, vs);
        !          2187:     return;
        !          2188: }
        !          2189: 
        !          2190: static void v9fs_readdir(V9fsState *s, V9fsPDU *pdu)
        !          2191: {
        !          2192:     int32_t fid;
        !          2193:     V9fsReadDirState *vs;
        !          2194:     ssize_t err = 0;
        !          2195:     size_t offset = 7;
        !          2196: 
        !          2197:     vs = qemu_malloc(sizeof(*vs));
        !          2198:     vs->pdu = pdu;
        !          2199:     vs->offset = 7;
        !          2200:     vs->count = 0;
        !          2201: 
        !          2202:     pdu_unmarshal(vs->pdu, offset, "dqd", &fid, &vs->initial_offset,
        !          2203:                                                         &vs->max_count);
        !          2204: 
        !          2205:     vs->fidp = lookup_fid(s, fid);
        !          2206:     if (vs->fidp == NULL || !(vs->fidp->fs.dir)) {
        !          2207:         err = -EINVAL;
        !          2208:         goto out;
        !          2209:     }
        !          2210: 
        !          2211:     if (vs->initial_offset == 0) {
        !          2212:         v9fs_do_rewinddir(s, vs->fidp->fs.dir);
        !          2213:     } else {
        !          2214:         v9fs_do_seekdir(s, vs->fidp->fs.dir, vs->initial_offset);
        !          2215:     }
        !          2216: 
        !          2217:     v9fs_readdir_post_setdir(s, vs);
        !          2218:     return;
        !          2219: 
        !          2220: out:
        !          2221:     complete_pdu(s, pdu, err);
        !          2222:     qemu_free(vs);
        !          2223:     return;
        !          2224: }
        !          2225: 
        !          2226: static void v9fs_write_post_pwritev(V9fsState *s, V9fsWriteState *vs,
1.1       root     2227:                                    ssize_t err)
                   2228: {
                   2229:     if (err  < 0) {
                   2230:         /* IO error return the error */
                   2231:         err = -errno;
                   2232:         goto out;
                   2233:     }
                   2234:     vs->total += vs->len;
                   2235:     vs->sg = adjust_sg(vs->sg, vs->len, &vs->cnt);
                   2236:     if (vs->total < vs->count && vs->len > 0) {
                   2237:         do {
                   2238:             if (0) {
                   2239:                 print_sg(vs->sg, vs->cnt);
                   2240:             }
1.1.1.2 ! root     2241:             vs->len = v9fs_do_pwritev(s, vs->fidp->fs.fd, vs->sg, vs->cnt,
        !          2242:                       vs->off);
        !          2243:             if (vs->len > 0) {
        !          2244:                 vs->off += vs->len;
        !          2245:             }
1.1       root     2246:         } while (vs->len == -1 && errno == EINTR);
                   2247:         if (vs->len == -1) {
                   2248:             err  = -errno;
                   2249:         }
1.1.1.2 ! root     2250:         v9fs_write_post_pwritev(s, vs, err);
1.1       root     2251:         return;
                   2252:     }
                   2253:     vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->total);
                   2254:     err = vs->offset;
                   2255: out:
                   2256:     complete_pdu(s, vs->pdu, err);
                   2257:     qemu_free(vs);
                   2258: }
                   2259: 
1.1.1.2 ! root     2260: static void v9fs_xattr_write(V9fsState *s, V9fsWriteState *vs)
1.1       root     2261: {
1.1.1.2 ! root     2262:     int i, to_copy;
        !          2263:     ssize_t err = 0;
        !          2264:     int write_count;
        !          2265:     int64_t xattr_len;
        !          2266: 
        !          2267:     xattr_len = vs->fidp->fs.xattr.len;
        !          2268:     write_count = xattr_len - vs->off;
        !          2269:     if (write_count > vs->count) {
        !          2270:         write_count = vs->count;
        !          2271:     } else if (write_count < 0) {
        !          2272:         /*
        !          2273:          * write beyond XATTR value len specified in
        !          2274:          * xattrcreate
        !          2275:          */
        !          2276:         err = -ENOSPC;
1.1       root     2277:         goto out;
                   2278:     }
1.1.1.2 ! root     2279:     vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", write_count);
        !          2280:     err = vs->offset;
        !          2281:     vs->fidp->fs.xattr.copied_len += write_count;
        !          2282:     /*
        !          2283:      * Now copy the content from sg list
        !          2284:      */
        !          2285:     for (i = 0; i < vs->cnt; i++) {
        !          2286:         if (write_count > vs->sg[i].iov_len) {
        !          2287:             to_copy = vs->sg[i].iov_len;
        !          2288:         } else {
        !          2289:             to_copy = write_count;
1.1       root     2290:         }
1.1.1.2 ! root     2291:         memcpy((char *)vs->fidp->fs.xattr.value + vs->off,
        !          2292:                vs->sg[i].iov_base, to_copy);
        !          2293:         /* updating vs->off since we are not using below */
        !          2294:         vs->off += to_copy;
        !          2295:         write_count -= to_copy;
1.1       root     2296:     }
                   2297: out:
                   2298:     complete_pdu(s, vs->pdu, err);
                   2299:     qemu_free(vs);
                   2300: }
                   2301: 
                   2302: static void v9fs_write(V9fsState *s, V9fsPDU *pdu)
                   2303: {
                   2304:     int32_t fid;
                   2305:     V9fsWriteState *vs;
                   2306:     ssize_t err;
                   2307: 
                   2308:     vs = qemu_malloc(sizeof(*vs));
                   2309: 
                   2310:     vs->pdu = pdu;
                   2311:     vs->offset = 7;
                   2312:     vs->sg = vs->iov;
                   2313:     vs->total = 0;
                   2314:     vs->len = 0;
                   2315: 
                   2316:     pdu_unmarshal(vs->pdu, vs->offset, "dqdv", &fid, &vs->off, &vs->count,
1.1.1.2 ! root     2317:                   vs->sg, &vs->cnt);
1.1       root     2318: 
                   2319:     vs->fidp = lookup_fid(s, fid);
                   2320:     if (vs->fidp == NULL) {
                   2321:         err = -EINVAL;
                   2322:         goto out;
                   2323:     }
                   2324: 
1.1.1.2 ! root     2325:     if (vs->fidp->fid_type == P9_FID_FILE) {
        !          2326:         if (vs->fidp->fs.fd == -1) {
        !          2327:             err = -EINVAL;
        !          2328:             goto out;
        !          2329:         }
        !          2330:     } else if (vs->fidp->fid_type == P9_FID_XATTR) {
        !          2331:         /*
        !          2332:          * setxattr operation
        !          2333:          */
        !          2334:         v9fs_xattr_write(s, vs);
        !          2335:         return;
        !          2336:     } else {
1.1       root     2337:         err = -EINVAL;
                   2338:         goto out;
                   2339:     }
1.1.1.2 ! root     2340:     vs->sg = cap_sg(vs->sg, vs->count, &vs->cnt);
        !          2341:     if (vs->total <= vs->count) {
        !          2342:         vs->len = v9fs_do_pwritev(s, vs->fidp->fs.fd, vs->sg, vs->cnt, vs->off);
        !          2343:         if (vs->len > 0) {
        !          2344:             vs->off += vs->len;
        !          2345:         }
        !          2346:         err = vs->len;
        !          2347:         v9fs_write_post_pwritev(s, vs, err);
        !          2348:     }
        !          2349:     return;
        !          2350: out:
        !          2351:     complete_pdu(s, vs->pdu, err);
        !          2352:     qemu_free(vs);
        !          2353: }
1.1       root     2354: 
1.1.1.2 ! root     2355: static void v9fs_create_post_getiounit(V9fsState *s, V9fsCreateState *vs)
        !          2356: {
        !          2357:     int err;
        !          2358:     v9fs_string_copy(&vs->fidp->path, &vs->fullname);
        !          2359:     stat_to_qid(&vs->stbuf, &vs->qid);
1.1       root     2360: 
1.1.1.2 ! root     2361:     vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, vs->iounit);
        !          2362:     err = vs->offset;
1.1       root     2363: 
                   2364:     complete_pdu(s, vs->pdu, err);
1.1.1.2 ! root     2365:     v9fs_string_free(&vs->name);
        !          2366:     v9fs_string_free(&vs->extension);
        !          2367:     v9fs_string_free(&vs->fullname);
1.1       root     2368:     qemu_free(vs);
                   2369: }
                   2370: 
                   2371: static void v9fs_post_create(V9fsState *s, V9fsCreateState *vs, int err)
                   2372: {
                   2373:     if (err == 0) {
1.1.1.2 ! root     2374:         vs->iounit = get_iounit(s, &vs->fidp->path);
        !          2375:         v9fs_create_post_getiounit(s, vs);
        !          2376:         return;
1.1       root     2377:     }
                   2378: 
                   2379:     complete_pdu(s, vs->pdu, err);
                   2380:     v9fs_string_free(&vs->name);
                   2381:     v9fs_string_free(&vs->extension);
                   2382:     v9fs_string_free(&vs->fullname);
                   2383:     qemu_free(vs);
                   2384: }
                   2385: 
                   2386: static void v9fs_create_post_perms(V9fsState *s, V9fsCreateState *vs, int err)
                   2387: {
                   2388:     if (err) {
                   2389:         err = -errno;
                   2390:     }
                   2391:     v9fs_post_create(s, vs, err);
                   2392: }
                   2393: 
                   2394: static void v9fs_create_post_opendir(V9fsState *s, V9fsCreateState *vs,
                   2395:                                                                     int err)
                   2396: {
1.1.1.2 ! root     2397:     if (!vs->fidp->fs.dir) {
1.1       root     2398:         err = -errno;
                   2399:     }
1.1.1.2 ! root     2400:     vs->fidp->fid_type = P9_FID_DIR;
1.1       root     2401:     v9fs_post_create(s, vs, err);
                   2402: }
                   2403: 
                   2404: static void v9fs_create_post_dir_lstat(V9fsState *s, V9fsCreateState *vs,
                   2405:                                                                     int err)
                   2406: {
                   2407:     if (err) {
                   2408:         err = -errno;
                   2409:         goto out;
                   2410:     }
                   2411: 
1.1.1.2 ! root     2412:     vs->fidp->fs.dir = v9fs_do_opendir(s, &vs->fullname);
1.1       root     2413:     v9fs_create_post_opendir(s, vs, err);
                   2414:     return;
                   2415: 
                   2416: out:
                   2417:     v9fs_post_create(s, vs, err);
                   2418: }
                   2419: 
                   2420: static void v9fs_create_post_mkdir(V9fsState *s, V9fsCreateState *vs, int err)
                   2421: {
                   2422:     if (err) {
                   2423:         err = -errno;
                   2424:         goto out;
                   2425:     }
                   2426: 
                   2427:     err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
                   2428:     v9fs_create_post_dir_lstat(s, vs, err);
                   2429:     return;
                   2430: 
                   2431: out:
                   2432:     v9fs_post_create(s, vs, err);
                   2433: }
                   2434: 
                   2435: static void v9fs_create_post_fstat(V9fsState *s, V9fsCreateState *vs, int err)
                   2436: {
                   2437:     if (err) {
1.1.1.2 ! root     2438:         vs->fidp->fid_type = P9_FID_NONE;
        !          2439:         close(vs->fidp->fs.fd);
1.1       root     2440:         err = -errno;
                   2441:     }
                   2442:     v9fs_post_create(s, vs, err);
                   2443:     return;
                   2444: }
                   2445: 
                   2446: static void v9fs_create_post_open2(V9fsState *s, V9fsCreateState *vs, int err)
                   2447: {
1.1.1.2 ! root     2448:     if (vs->fidp->fs.fd == -1) {
1.1       root     2449:         err = -errno;
                   2450:         goto out;
                   2451:     }
1.1.1.2 ! root     2452:     vs->fidp->fid_type = P9_FID_FILE;
        !          2453:     err = v9fs_do_fstat(s, vs->fidp->fs.fd, &vs->stbuf);
1.1       root     2454:     v9fs_create_post_fstat(s, vs, err);
                   2455: 
                   2456:     return;
                   2457: 
                   2458: out:
                   2459:     v9fs_post_create(s, vs, err);
                   2460: 
                   2461: }
                   2462: 
                   2463: static void v9fs_create_post_lstat(V9fsState *s, V9fsCreateState *vs, int err)
                   2464: {
                   2465: 
                   2466:     if (err == 0 || errno != ENOENT) {
                   2467:         err = -errno;
                   2468:         goto out;
                   2469:     }
                   2470: 
                   2471:     if (vs->perm & P9_STAT_MODE_DIR) {
1.1.1.2 ! root     2472:         err = v9fs_do_mkdir(s, vs->fullname.data, vs->perm & 0777,
        !          2473:                 vs->fidp->uid, -1);
1.1       root     2474:         v9fs_create_post_mkdir(s, vs, err);
                   2475:     } else if (vs->perm & P9_STAT_MODE_SYMLINK) {
1.1.1.2 ! root     2476:         err = v9fs_do_symlink(s, vs->fidp, vs->extension.data,
        !          2477:                 vs->fullname.data, -1);
1.1       root     2478:         v9fs_create_post_perms(s, vs, err);
                   2479:     } else if (vs->perm & P9_STAT_MODE_LINK) {
                   2480:         int32_t nfid = atoi(vs->extension.data);
                   2481:         V9fsFidState *nfidp = lookup_fid(s, nfid);
                   2482:         if (nfidp == NULL) {
                   2483:             err = -errno;
                   2484:             v9fs_post_create(s, vs, err);
                   2485:         }
                   2486:         err = v9fs_do_link(s, &nfidp->path, &vs->fullname);
                   2487:         v9fs_create_post_perms(s, vs, err);
                   2488:     } else if (vs->perm & P9_STAT_MODE_DEVICE) {
                   2489:         char ctype;
                   2490:         uint32_t major, minor;
                   2491:         mode_t nmode = 0;
                   2492: 
                   2493:         if (sscanf(vs->extension.data, "%c %u %u", &ctype, &major,
                   2494:                                         &minor) != 3) {
                   2495:             err = -errno;
                   2496:             v9fs_post_create(s, vs, err);
                   2497:         }
                   2498: 
                   2499:         switch (ctype) {
                   2500:         case 'c':
                   2501:             nmode = S_IFCHR;
                   2502:             break;
                   2503:         case 'b':
                   2504:             nmode = S_IFBLK;
                   2505:             break;
                   2506:         default:
                   2507:             err = -EIO;
                   2508:             v9fs_post_create(s, vs, err);
                   2509:         }
                   2510: 
                   2511:         nmode |= vs->perm & 0777;
1.1.1.2 ! root     2512:         err = v9fs_do_mknod(s, vs->fullname.data, nmode,
        !          2513:                 makedev(major, minor), vs->fidp->uid, -1);
1.1       root     2514:         v9fs_create_post_perms(s, vs, err);
                   2515:     } else if (vs->perm & P9_STAT_MODE_NAMED_PIPE) {
1.1.1.2 ! root     2516:         err = v9fs_do_mknod(s, vs->fullname.data, S_IFIFO | (vs->perm & 0777),
        !          2517:                 0, vs->fidp->uid, -1);
1.1       root     2518:         v9fs_post_create(s, vs, err);
                   2519:     } else if (vs->perm & P9_STAT_MODE_SOCKET) {
1.1.1.2 ! root     2520:         err = v9fs_do_mknod(s, vs->fullname.data, S_IFSOCK | (vs->perm & 0777),
        !          2521:                 0, vs->fidp->uid, -1);
1.1       root     2522:         v9fs_post_create(s, vs, err);
                   2523:     } else {
1.1.1.2 ! root     2524:         vs->fidp->fs.fd = v9fs_do_open2(s, vs->fullname.data, vs->fidp->uid,
        !          2525:                 -1, omode_to_uflags(vs->mode)|O_CREAT, vs->perm);
        !          2526: 
1.1       root     2527:         v9fs_create_post_open2(s, vs, err);
                   2528:     }
                   2529: 
                   2530:     return;
                   2531: 
                   2532: out:
                   2533:     v9fs_post_create(s, vs, err);
                   2534: }
                   2535: 
                   2536: static void v9fs_create(V9fsState *s, V9fsPDU *pdu)
                   2537: {
                   2538:     int32_t fid;
                   2539:     V9fsCreateState *vs;
                   2540:     int err = 0;
                   2541: 
                   2542:     vs = qemu_malloc(sizeof(*vs));
                   2543:     vs->pdu = pdu;
                   2544:     vs->offset = 7;
                   2545: 
                   2546:     v9fs_string_init(&vs->fullname);
                   2547: 
                   2548:     pdu_unmarshal(vs->pdu, vs->offset, "dsdbs", &fid, &vs->name,
                   2549:                                 &vs->perm, &vs->mode, &vs->extension);
                   2550: 
                   2551:     vs->fidp = lookup_fid(s, fid);
                   2552:     if (vs->fidp == NULL) {
                   2553:         err = -EINVAL;
                   2554:         goto out;
                   2555:     }
                   2556: 
                   2557:     v9fs_string_sprintf(&vs->fullname, "%s/%s", vs->fidp->path.data,
                   2558:                                                         vs->name.data);
                   2559: 
                   2560:     err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
                   2561:     v9fs_create_post_lstat(s, vs, err);
                   2562:     return;
                   2563: 
                   2564: out:
                   2565:     complete_pdu(s, vs->pdu, err);
                   2566:     v9fs_string_free(&vs->name);
                   2567:     v9fs_string_free(&vs->extension);
                   2568:     qemu_free(vs);
                   2569: }
                   2570: 
1.1.1.2 ! root     2571: static void v9fs_post_symlink(V9fsState *s, V9fsSymlinkState *vs, int err)
1.1       root     2572: {
1.1.1.2 ! root     2573:     if (err == 0) {
        !          2574:         stat_to_qid(&vs->stbuf, &vs->qid);
        !          2575:         vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qid);
        !          2576:         err = vs->offset;
        !          2577:     } else {
        !          2578:         err = -errno;
        !          2579:     }
        !          2580:     complete_pdu(s, vs->pdu, err);
        !          2581:     v9fs_string_free(&vs->name);
        !          2582:     v9fs_string_free(&vs->symname);
        !          2583:     v9fs_string_free(&vs->fullname);
        !          2584:     qemu_free(vs);
1.1       root     2585: }
                   2586: 
1.1.1.2 ! root     2587: static void v9fs_symlink_post_do_symlink(V9fsState *s, V9fsSymlinkState *vs,
        !          2588:         int err)
1.1       root     2589: {
1.1.1.2 ! root     2590:     if (err) {
1.1       root     2591:         goto out;
                   2592:     }
1.1.1.2 ! root     2593:     err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
1.1       root     2594: out:
1.1.1.2 ! root     2595:     v9fs_post_symlink(s, vs, err);
1.1       root     2596: }
                   2597: 
1.1.1.2 ! root     2598: static void v9fs_symlink(V9fsState *s, V9fsPDU *pdu)
1.1       root     2599: {
1.1.1.2 ! root     2600:     int32_t dfid;
        !          2601:     V9fsSymlinkState *vs;
        !          2602:     int err = 0;
        !          2603:     gid_t gid;
        !          2604: 
        !          2605:     vs = qemu_malloc(sizeof(*vs));
        !          2606:     vs->pdu = pdu;
        !          2607:     vs->offset = 7;
        !          2608: 
        !          2609:     v9fs_string_init(&vs->fullname);
        !          2610: 
        !          2611:     pdu_unmarshal(vs->pdu, vs->offset, "dssd", &dfid, &vs->name,
        !          2612:             &vs->symname, &gid);
        !          2613: 
        !          2614:     vs->dfidp = lookup_fid(s, dfid);
        !          2615:     if (vs->dfidp == NULL) {
        !          2616:         err = -EINVAL;
        !          2617:         goto out;
        !          2618:     }
        !          2619: 
        !          2620:     v9fs_string_sprintf(&vs->fullname, "%s/%s", vs->dfidp->path.data,
        !          2621:             vs->name.data);
        !          2622:     err = v9fs_do_symlink(s, vs->dfidp, vs->symname.data,
        !          2623:             vs->fullname.data, gid);
        !          2624:     v9fs_symlink_post_do_symlink(s, vs, err);
        !          2625:     return;
        !          2626: 
        !          2627: out:
        !          2628:     complete_pdu(s, vs->pdu, err);
        !          2629:     v9fs_string_free(&vs->name);
        !          2630:     v9fs_string_free(&vs->symname);
        !          2631:     qemu_free(vs);
        !          2632: }
        !          2633: 
        !          2634: static void v9fs_flush(V9fsState *s, V9fsPDU *pdu)
        !          2635: {
        !          2636:     /* A nop call with no return */
        !          2637:     complete_pdu(s, pdu, 7);
        !          2638: }
        !          2639: 
        !          2640: static void v9fs_link(V9fsState *s, V9fsPDU *pdu)
        !          2641: {
        !          2642:     int32_t dfid, oldfid;
        !          2643:     V9fsFidState *dfidp, *oldfidp;
        !          2644:     V9fsString name, fullname;
        !          2645:     size_t offset = 7;
        !          2646:     int err = 0;
        !          2647: 
        !          2648:     v9fs_string_init(&fullname);
        !          2649: 
        !          2650:     pdu_unmarshal(pdu, offset, "dds", &dfid, &oldfid, &name);
        !          2651: 
        !          2652:     dfidp = lookup_fid(s, dfid);
        !          2653:     if (dfidp == NULL) {
        !          2654:         err = -errno;
        !          2655:         goto out;
        !          2656:     }
        !          2657: 
        !          2658:     oldfidp = lookup_fid(s, oldfid);
        !          2659:     if (oldfidp == NULL) {
        !          2660:         err = -errno;
        !          2661:         goto out;
        !          2662:     }
        !          2663: 
        !          2664:     v9fs_string_sprintf(&fullname, "%s/%s", dfidp->path.data, name.data);
        !          2665:     err = offset;
        !          2666:     err = v9fs_do_link(s, &oldfidp->path, &fullname);
        !          2667:     if (err) {
        !          2668:         err = -errno;
        !          2669:     }
        !          2670:     v9fs_string_free(&fullname);
        !          2671: 
        !          2672: out:
        !          2673:     v9fs_string_free(&name);
        !          2674:     complete_pdu(s, pdu, err);
        !          2675: }
        !          2676: 
        !          2677: static void v9fs_remove_post_remove(V9fsState *s, V9fsRemoveState *vs,
        !          2678:                                                                 int err)
        !          2679: {
        !          2680:     if (err < 0) {
        !          2681:         err = -errno;
        !          2682:     } else {
        !          2683:         err = vs->offset;
        !          2684:     }
        !          2685: 
        !          2686:     /* For TREMOVE we need to clunk the fid even on failed remove */
        !          2687:     free_fid(s, vs->fidp->fid);
        !          2688: 
        !          2689:     complete_pdu(s, vs->pdu, err);
        !          2690:     qemu_free(vs);
        !          2691: }
        !          2692: 
        !          2693: static void v9fs_remove(V9fsState *s, V9fsPDU *pdu)
        !          2694: {
        !          2695:     int32_t fid;
1.1       root     2696:     V9fsRemoveState *vs;
                   2697:     int err = 0;
                   2698: 
                   2699:     vs = qemu_malloc(sizeof(*vs));
                   2700:     vs->pdu = pdu;
                   2701:     vs->offset = 7;
                   2702: 
                   2703:     pdu_unmarshal(vs->pdu, vs->offset, "d", &fid);
                   2704: 
                   2705:     vs->fidp = lookup_fid(s, fid);
                   2706:     if (vs->fidp == NULL) {
                   2707:         err = -EINVAL;
                   2708:         goto out;
                   2709:     }
                   2710: 
                   2711:     err = v9fs_do_remove(s, &vs->fidp->path);
                   2712:     v9fs_remove_post_remove(s, vs, err);
                   2713:     return;
                   2714: 
                   2715: out:
                   2716:     complete_pdu(s, pdu, err);
                   2717:     qemu_free(vs);
                   2718: }
                   2719: 
                   2720: static void v9fs_wstat_post_truncate(V9fsState *s, V9fsWstatState *vs, int err)
                   2721: {
                   2722:     if (err < 0) {
                   2723:         goto out;
                   2724:     }
                   2725: 
                   2726:     err = vs->offset;
                   2727: 
                   2728: out:
                   2729:     v9fs_stat_free(&vs->v9stat);
                   2730:     complete_pdu(s, vs->pdu, err);
                   2731:     qemu_free(vs);
                   2732: }
                   2733: 
                   2734: static void v9fs_wstat_post_rename(V9fsState *s, V9fsWstatState *vs, int err)
                   2735: {
                   2736:     if (err < 0) {
                   2737:         goto out;
                   2738:     }
                   2739:     if (vs->v9stat.length != -1) {
                   2740:         if (v9fs_do_truncate(s, &vs->fidp->path, vs->v9stat.length) < 0) {
                   2741:             err = -errno;
                   2742:         }
                   2743:     }
                   2744:     v9fs_wstat_post_truncate(s, vs, err);
                   2745:     return;
                   2746: 
                   2747: out:
                   2748:     v9fs_stat_free(&vs->v9stat);
                   2749:     complete_pdu(s, vs->pdu, err);
                   2750:     qemu_free(vs);
                   2751: }
                   2752: 
1.1.1.2 ! root     2753: static int v9fs_complete_rename(V9fsState *s, V9fsRenameState *vs)
1.1       root     2754: {
1.1.1.2 ! root     2755:     int err = 0;
        !          2756:     char *old_name, *new_name;
        !          2757:     char *end;
1.1       root     2758: 
1.1.1.2 ! root     2759:     if (vs->newdirfid != -1) {
        !          2760:         V9fsFidState *dirfidp;
        !          2761:         dirfidp = lookup_fid(s, vs->newdirfid);
        !          2762: 
        !          2763:         if (dirfidp == NULL) {
        !          2764:             err = -ENOENT;
        !          2765:             goto out;
        !          2766:         }
        !          2767: 
        !          2768:         BUG_ON(dirfidp->fid_type != P9_FID_NONE);
1.1       root     2769: 
1.1.1.2 ! root     2770:         new_name = qemu_mallocz(dirfidp->path.size + vs->name.size + 2);
        !          2771: 
        !          2772:         strcpy(new_name, dirfidp->path.data);
        !          2773:         strcat(new_name, "/");
        !          2774:         strcat(new_name + dirfidp->path.size, vs->name.data);
        !          2775:     } else {
1.1       root     2776:         old_name = vs->fidp->path.data;
                   2777:         end = strrchr(old_name, '/');
                   2778:         if (end) {
                   2779:             end++;
                   2780:         } else {
                   2781:             end = old_name;
                   2782:         }
1.1.1.2 ! root     2783:         new_name = qemu_mallocz(end - old_name + vs->name.size + 1);
1.1       root     2784: 
1.1.1.2 ! root     2785:         strncat(new_name, old_name, end - old_name);
        !          2786:         strncat(new_name + (end - old_name), vs->name.data, vs->name.size);
        !          2787:     }
1.1       root     2788: 
1.1.1.2 ! root     2789:     v9fs_string_free(&vs->name);
        !          2790:     vs->name.data = qemu_strdup(new_name);
        !          2791:     vs->name.size = strlen(new_name);
        !          2792: 
        !          2793:     if (strcmp(new_name, vs->fidp->path.data) != 0) {
        !          2794:         if (v9fs_do_rename(s, &vs->fidp->path, &vs->name)) {
        !          2795:             err = -errno;
        !          2796:         } else {
        !          2797:             V9fsFidState *fidp;
        !          2798:             /*
        !          2799:             * Fixup fid's pointing to the old name to
        !          2800:             * start pointing to the new name
        !          2801:             */
        !          2802:             for (fidp = s->fid_list; fidp; fidp = fidp->next) {
        !          2803:                 if (vs->fidp == fidp) {
        !          2804:                     /*
        !          2805:                     * we replace name of this fid towards the end
        !          2806:                     * so that our below strcmp will work
        !          2807:                     */
        !          2808:                     continue;
        !          2809:                 }
        !          2810:                 if (!strncmp(vs->fidp->path.data, fidp->path.data,
        !          2811:                     strlen(vs->fidp->path.data))) {
        !          2812:                     /* replace the name */
        !          2813:                     v9fs_fix_path(&fidp->path, &vs->name,
        !          2814:                                   strlen(vs->fidp->path.data));
1.1       root     2815:                 }
                   2816:             }
1.1.1.2 ! root     2817:             v9fs_string_copy(&vs->fidp->path, &vs->name);
1.1       root     2818:         }
                   2819:     }
1.1.1.2 ! root     2820: out:
        !          2821:     v9fs_string_free(&vs->name);
        !          2822:     return err;
        !          2823: }
        !          2824: 
        !          2825: static void v9fs_rename_post_rename(V9fsState *s, V9fsRenameState *vs, int err)
        !          2826: {
        !          2827:     complete_pdu(s, vs->pdu, err);
        !          2828:     qemu_free(vs);
        !          2829: }
        !          2830: 
        !          2831: static void v9fs_wstat_post_chown(V9fsState *s, V9fsWstatState *vs, int err)
        !          2832: {
        !          2833:     if (err < 0) {
        !          2834:         goto out;
        !          2835:     }
        !          2836: 
        !          2837:     if (vs->v9stat.name.size != 0) {
        !          2838:         V9fsRenameState *vr;
        !          2839: 
        !          2840:         vr = qemu_mallocz(sizeof(V9fsRenameState));
        !          2841:         vr->newdirfid = -1;
        !          2842:         vr->pdu = vs->pdu;
        !          2843:         vr->fidp = vs->fidp;
        !          2844:         vr->offset = vs->offset;
        !          2845:         vr->name.size = vs->v9stat.name.size;
        !          2846:         vr->name.data = qemu_strdup(vs->v9stat.name.data);
        !          2847: 
        !          2848:         err = v9fs_complete_rename(s, vr);
        !          2849:         qemu_free(vr);
        !          2850:     }
1.1       root     2851:     v9fs_wstat_post_rename(s, vs, err);
                   2852:     return;
                   2853: 
                   2854: out:
                   2855:     v9fs_stat_free(&vs->v9stat);
                   2856:     complete_pdu(s, vs->pdu, err);
                   2857:     qemu_free(vs);
                   2858: }
                   2859: 
1.1.1.2 ! root     2860: static void v9fs_rename(V9fsState *s, V9fsPDU *pdu)
        !          2861: {
        !          2862:     int32_t fid;
        !          2863:     V9fsRenameState *vs;
        !          2864:     ssize_t err = 0;
        !          2865: 
        !          2866:     vs = qemu_malloc(sizeof(*vs));
        !          2867:     vs->pdu = pdu;
        !          2868:     vs->offset = 7;
        !          2869: 
        !          2870:     pdu_unmarshal(vs->pdu, vs->offset, "dds", &fid, &vs->newdirfid, &vs->name);
        !          2871: 
        !          2872:     vs->fidp = lookup_fid(s, fid);
        !          2873:     if (vs->fidp == NULL) {
        !          2874:         err = -ENOENT;
        !          2875:         goto out;
        !          2876:     }
        !          2877: 
        !          2878:     BUG_ON(vs->fidp->fid_type != P9_FID_NONE);
        !          2879: 
        !          2880:     err = v9fs_complete_rename(s, vs);
        !          2881:     v9fs_rename_post_rename(s, vs, err);
        !          2882:     return;
        !          2883: out:
        !          2884:     complete_pdu(s, vs->pdu, err);
        !          2885:     qemu_free(vs);
        !          2886: }
        !          2887: 
1.1       root     2888: static void v9fs_wstat_post_utime(V9fsState *s, V9fsWstatState *vs, int err)
                   2889: {
                   2890:     if (err < 0) {
                   2891:         goto out;
                   2892:     }
                   2893: 
                   2894:     if (vs->v9stat.n_gid != -1 || vs->v9stat.n_uid != -1) {
                   2895:         if (v9fs_do_chown(s, &vs->fidp->path, vs->v9stat.n_uid,
                   2896:                     vs->v9stat.n_gid)) {
                   2897:             err = -errno;
                   2898:         }
                   2899:     }
                   2900:     v9fs_wstat_post_chown(s, vs, err);
                   2901:     return;
                   2902: 
                   2903: out:
                   2904:     v9fs_stat_free(&vs->v9stat);
                   2905:     complete_pdu(s, vs->pdu, err);
                   2906:     qemu_free(vs);
                   2907: }
                   2908: 
                   2909: static void v9fs_wstat_post_chmod(V9fsState *s, V9fsWstatState *vs, int err)
                   2910: {
                   2911:     if (err < 0) {
                   2912:         goto out;
                   2913:     }
                   2914: 
1.1.1.2 ! root     2915:     if (vs->v9stat.mtime != -1 || vs->v9stat.atime != -1) {
        !          2916:         struct timespec times[2];
        !          2917:         if (vs->v9stat.atime != -1) {
        !          2918:             times[0].tv_sec = vs->v9stat.atime;
        !          2919:             times[0].tv_nsec = 0;
        !          2920:         } else {
        !          2921:             times[0].tv_nsec = UTIME_OMIT;
        !          2922:         }
        !          2923:         if (vs->v9stat.mtime != -1) {
        !          2924:             times[1].tv_sec = vs->v9stat.mtime;
        !          2925:             times[1].tv_nsec = 0;
        !          2926:         } else {
        !          2927:             times[1].tv_nsec = UTIME_OMIT;
        !          2928:         }
        !          2929: 
        !          2930:         if (v9fs_do_utimensat(s, &vs->fidp->path, times)) {
1.1       root     2931:             err = -errno;
                   2932:         }
                   2933:     }
                   2934: 
                   2935:     v9fs_wstat_post_utime(s, vs, err);
                   2936:     return;
                   2937: 
                   2938: out:
                   2939:     v9fs_stat_free(&vs->v9stat);
                   2940:     complete_pdu(s, vs->pdu, err);
                   2941:     qemu_free(vs);
                   2942: }
                   2943: 
                   2944: static void v9fs_wstat_post_fsync(V9fsState *s, V9fsWstatState *vs, int err)
                   2945: {
                   2946:     if (err == -1) {
                   2947:         err = -errno;
                   2948:     }
                   2949:     v9fs_stat_free(&vs->v9stat);
                   2950:     complete_pdu(s, vs->pdu, err);
                   2951:     qemu_free(vs);
                   2952: }
                   2953: 
                   2954: static void v9fs_wstat_post_lstat(V9fsState *s, V9fsWstatState *vs, int err)
                   2955: {
                   2956:     uint32_t v9_mode;
                   2957: 
                   2958:     if (err == -1) {
                   2959:         err = -errno;
                   2960:         goto out;
                   2961:     }
                   2962: 
                   2963:     v9_mode = stat_to_v9mode(&vs->stbuf);
                   2964: 
                   2965:     if ((vs->v9stat.mode & P9_STAT_MODE_TYPE_BITS) !=
                   2966:         (v9_mode & P9_STAT_MODE_TYPE_BITS)) {
                   2967:             /* Attempting to change the type */
                   2968:             err = -EIO;
                   2969:             goto out;
                   2970:     }
                   2971: 
                   2972:     if (v9fs_do_chmod(s, &vs->fidp->path, v9mode_to_mode(vs->v9stat.mode,
                   2973:                     &vs->v9stat.extension))) {
                   2974:             err = -errno;
                   2975:      }
                   2976:     v9fs_wstat_post_chmod(s, vs, err);
                   2977:     return;
                   2978: 
                   2979: out:
                   2980:     v9fs_stat_free(&vs->v9stat);
                   2981:     complete_pdu(s, vs->pdu, err);
                   2982:     qemu_free(vs);
                   2983: }
                   2984: 
                   2985: static void v9fs_wstat(V9fsState *s, V9fsPDU *pdu)
                   2986: {
                   2987:     int32_t fid;
                   2988:     V9fsWstatState *vs;
                   2989:     int err = 0;
                   2990: 
                   2991:     vs = qemu_malloc(sizeof(*vs));
                   2992:     vs->pdu = pdu;
                   2993:     vs->offset = 7;
                   2994: 
                   2995:     pdu_unmarshal(pdu, vs->offset, "dwS", &fid, &vs->unused, &vs->v9stat);
                   2996: 
                   2997:     vs->fidp = lookup_fid(s, fid);
                   2998:     if (vs->fidp == NULL) {
                   2999:         err = -EINVAL;
                   3000:         goto out;
                   3001:     }
                   3002: 
                   3003:     /* do we need to sync the file? */
                   3004:     if (donttouch_stat(&vs->v9stat)) {
1.1.1.2 ! root     3005:         err = v9fs_do_fsync(s, vs->fidp->fs.fd, 0);
1.1       root     3006:         v9fs_wstat_post_fsync(s, vs, err);
                   3007:         return;
                   3008:     }
                   3009: 
                   3010:     if (vs->v9stat.mode != -1) {
                   3011:         err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
                   3012:         v9fs_wstat_post_lstat(s, vs, err);
                   3013:         return;
                   3014:     }
                   3015: 
                   3016:     v9fs_wstat_post_chmod(s, vs, err);
                   3017:     return;
                   3018: 
                   3019: out:
                   3020:     v9fs_stat_free(&vs->v9stat);
                   3021:     complete_pdu(s, vs->pdu, err);
                   3022:     qemu_free(vs);
                   3023: }
                   3024: 
1.1.1.2 ! root     3025: static void v9fs_statfs_post_statfs(V9fsState *s, V9fsStatfsState *vs, int err)
        !          3026: {
        !          3027:     int32_t bsize_factor;
        !          3028: 
        !          3029:     if (err) {
        !          3030:         err = -errno;
        !          3031:         goto out;
        !          3032:     }
        !          3033: 
        !          3034:     /*
        !          3035:      * compute bsize factor based on host file system block size
        !          3036:      * and client msize
        !          3037:      */
        !          3038:     bsize_factor = (s->msize - P9_IOHDRSZ)/vs->stbuf.f_bsize;
        !          3039:     if (!bsize_factor) {
        !          3040:         bsize_factor = 1;
        !          3041:     }
        !          3042:     vs->v9statfs.f_type = vs->stbuf.f_type;
        !          3043:     vs->v9statfs.f_bsize = vs->stbuf.f_bsize;
        !          3044:     vs->v9statfs.f_bsize *= bsize_factor;
        !          3045:     /*
        !          3046:      * f_bsize is adjusted(multiplied) by bsize factor, so we need to
        !          3047:      * adjust(divide) the number of blocks, free blocks and available
        !          3048:      * blocks by bsize factor
        !          3049:      */
        !          3050:     vs->v9statfs.f_blocks = vs->stbuf.f_blocks/bsize_factor;
        !          3051:     vs->v9statfs.f_bfree = vs->stbuf.f_bfree/bsize_factor;
        !          3052:     vs->v9statfs.f_bavail = vs->stbuf.f_bavail/bsize_factor;
        !          3053:     vs->v9statfs.f_files = vs->stbuf.f_files;
        !          3054:     vs->v9statfs.f_ffree = vs->stbuf.f_ffree;
        !          3055:     vs->v9statfs.fsid_val = (unsigned int) vs->stbuf.f_fsid.__val[0] |
        !          3056:                        (unsigned long long)vs->stbuf.f_fsid.__val[1] << 32;
        !          3057:     vs->v9statfs.f_namelen = vs->stbuf.f_namelen;
        !          3058: 
        !          3059:     vs->offset += pdu_marshal(vs->pdu, vs->offset, "ddqqqqqqd",
        !          3060:          vs->v9statfs.f_type, vs->v9statfs.f_bsize, vs->v9statfs.f_blocks,
        !          3061:          vs->v9statfs.f_bfree, vs->v9statfs.f_bavail, vs->v9statfs.f_files,
        !          3062:          vs->v9statfs.f_ffree, vs->v9statfs.fsid_val,
        !          3063:          vs->v9statfs.f_namelen);
        !          3064: 
        !          3065: out:
        !          3066:     complete_pdu(s, vs->pdu, vs->offset);
        !          3067:     qemu_free(vs);
        !          3068: }
        !          3069: 
        !          3070: static void v9fs_statfs(V9fsState *s, V9fsPDU *pdu)
        !          3071: {
        !          3072:     V9fsStatfsState *vs;
        !          3073:     ssize_t err = 0;
        !          3074: 
        !          3075:     vs = qemu_malloc(sizeof(*vs));
        !          3076:     vs->pdu = pdu;
        !          3077:     vs->offset = 7;
        !          3078: 
        !          3079:     memset(&vs->v9statfs, 0, sizeof(vs->v9statfs));
        !          3080: 
        !          3081:     pdu_unmarshal(vs->pdu, vs->offset, "d", &vs->fid);
        !          3082: 
        !          3083:     vs->fidp = lookup_fid(s, vs->fid);
        !          3084:     if (vs->fidp == NULL) {
        !          3085:         err = -ENOENT;
        !          3086:         goto out;
        !          3087:     }
        !          3088: 
        !          3089:     err = v9fs_do_statfs(s, &vs->fidp->path, &vs->stbuf);
        !          3090:     v9fs_statfs_post_statfs(s, vs, err);
        !          3091:     return;
        !          3092: 
        !          3093: out:
        !          3094:     complete_pdu(s, vs->pdu, err);
        !          3095:     qemu_free(vs);
        !          3096: }
        !          3097: 
        !          3098: static void v9fs_mknod_post_lstat(V9fsState *s, V9fsMkState *vs, int err)
        !          3099: {
        !          3100:     if (err == -1) {
        !          3101:         err = -errno;
        !          3102:         goto out;
        !          3103:     }
        !          3104: 
        !          3105:     stat_to_qid(&vs->stbuf, &vs->qid);
        !          3106:     vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qid);
        !          3107:     err = vs->offset;
        !          3108: out:
        !          3109:     complete_pdu(s, vs->pdu, err);
        !          3110:     v9fs_string_free(&vs->fullname);
        !          3111:     v9fs_string_free(&vs->name);
        !          3112:     qemu_free(vs);
        !          3113: }
        !          3114: 
        !          3115: static void v9fs_mknod_post_mknod(V9fsState *s, V9fsMkState *vs, int err)
        !          3116: {
        !          3117:     if (err == -1) {
        !          3118:         err = -errno;
        !          3119:         goto out;
        !          3120:     }
        !          3121: 
        !          3122:     err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
        !          3123:     v9fs_mknod_post_lstat(s, vs, err);
        !          3124:     return;
        !          3125: out:
        !          3126:     complete_pdu(s, vs->pdu, err);
        !          3127:     v9fs_string_free(&vs->fullname);
        !          3128:     v9fs_string_free(&vs->name);
        !          3129:     qemu_free(vs);
        !          3130: }
        !          3131: 
        !          3132: static void v9fs_mknod(V9fsState *s, V9fsPDU *pdu)
        !          3133: {
        !          3134:     int32_t fid;
        !          3135:     V9fsMkState *vs;
        !          3136:     int err = 0;
        !          3137:     V9fsFidState *fidp;
        !          3138:     gid_t gid;
        !          3139:     int mode;
        !          3140:     int major, minor;
        !          3141: 
        !          3142:     vs = qemu_malloc(sizeof(*vs));
        !          3143:     vs->pdu = pdu;
        !          3144:     vs->offset = 7;
        !          3145: 
        !          3146:     v9fs_string_init(&vs->fullname);
        !          3147:     pdu_unmarshal(vs->pdu, vs->offset, "dsdddd", &fid, &vs->name, &mode,
        !          3148:         &major, &minor, &gid);
        !          3149: 
        !          3150:     fidp = lookup_fid(s, fid);
        !          3151:     if (fidp == NULL) {
        !          3152:         err = -ENOENT;
        !          3153:         goto out;
        !          3154:     }
        !          3155: 
        !          3156:     v9fs_string_sprintf(&vs->fullname, "%s/%s", fidp->path.data, vs->name.data);
        !          3157:     err = v9fs_do_mknod(s, vs->fullname.data, mode, makedev(major, minor),
        !          3158:         fidp->uid, gid);
        !          3159:     v9fs_mknod_post_mknod(s, vs, err);
        !          3160:     return;
        !          3161: 
        !          3162: out:
        !          3163:     complete_pdu(s, vs->pdu, err);
        !          3164:     v9fs_string_free(&vs->fullname);
        !          3165:     v9fs_string_free(&vs->name);
        !          3166:     qemu_free(vs);
        !          3167: }
        !          3168: 
        !          3169: /*
        !          3170:  * Implement posix byte range locking code
        !          3171:  * Server side handling of locking code is very simple, because 9p server in
        !          3172:  * QEMU can handle only one client. And most of the lock handling
        !          3173:  * (like conflict, merging) etc is done by the VFS layer itself, so no need to
        !          3174:  * do any thing in * qemu 9p server side lock code path.
        !          3175:  * So when a TLOCK request comes, always return success
        !          3176:  */
        !          3177: 
        !          3178: static void v9fs_lock(V9fsState *s, V9fsPDU *pdu)
        !          3179: {
        !          3180:     int32_t fid, err = 0;
        !          3181:     V9fsLockState *vs;
        !          3182: 
        !          3183:     vs = qemu_mallocz(sizeof(*vs));
        !          3184:     vs->pdu = pdu;
        !          3185:     vs->offset = 7;
        !          3186: 
        !          3187:     vs->flock = qemu_malloc(sizeof(*vs->flock));
        !          3188:     pdu_unmarshal(vs->pdu, vs->offset, "dbdqqds", &fid, &vs->flock->type,
        !          3189:                 &vs->flock->flags, &vs->flock->start, &vs->flock->length,
        !          3190:                             &vs->flock->proc_id, &vs->flock->client_id);
        !          3191: 
        !          3192:     vs->status = P9_LOCK_ERROR;
        !          3193: 
        !          3194:     /* We support only block flag now (that too ignored currently) */
        !          3195:     if (vs->flock->flags & ~P9_LOCK_FLAGS_BLOCK) {
        !          3196:         err = -EINVAL;
        !          3197:         goto out;
        !          3198:     }
        !          3199:     vs->fidp = lookup_fid(s, fid);
        !          3200:     if (vs->fidp == NULL) {
        !          3201:         err = -ENOENT;
        !          3202:         goto out;
        !          3203:     }
        !          3204: 
        !          3205:     err = v9fs_do_fstat(s, vs->fidp->fs.fd, &vs->stbuf);
        !          3206:     if (err < 0) {
        !          3207:         err = -errno;
        !          3208:         goto out;
        !          3209:     }
        !          3210:     vs->status = P9_LOCK_SUCCESS;
        !          3211: out:
        !          3212:     vs->offset += pdu_marshal(vs->pdu, vs->offset, "b", vs->status);
        !          3213:     complete_pdu(s, vs->pdu, err);
        !          3214:     qemu_free(vs->flock);
        !          3215:     qemu_free(vs);
        !          3216: }
        !          3217: 
        !          3218: /*
        !          3219:  * When a TGETLOCK request comes, always return success because all lock
        !          3220:  * handling is done by client's VFS layer.
        !          3221:  */
        !          3222: 
        !          3223: static void v9fs_getlock(V9fsState *s, V9fsPDU *pdu)
        !          3224: {
        !          3225:     int32_t fid, err = 0;
        !          3226:     V9fsGetlockState *vs;
        !          3227: 
        !          3228:     vs = qemu_mallocz(sizeof(*vs));
        !          3229:     vs->pdu = pdu;
        !          3230:     vs->offset = 7;
        !          3231: 
        !          3232:     vs->glock = qemu_malloc(sizeof(*vs->glock));
        !          3233:     pdu_unmarshal(vs->pdu, vs->offset, "dbqqds", &fid, &vs->glock->type,
        !          3234:                 &vs->glock->start, &vs->glock->length, &vs->glock->proc_id,
        !          3235:                &vs->glock->client_id);
        !          3236: 
        !          3237:     vs->fidp = lookup_fid(s, fid);
        !          3238:     if (vs->fidp == NULL) {
        !          3239:         err = -ENOENT;
        !          3240:         goto out;
        !          3241:     }
        !          3242: 
        !          3243:     err = v9fs_do_fstat(s, vs->fidp->fs.fd, &vs->stbuf);
        !          3244:     if (err < 0) {
        !          3245:         err = -errno;
        !          3246:         goto out;
        !          3247:     }
        !          3248:     vs->glock->type = F_UNLCK;
        !          3249:     vs->offset += pdu_marshal(vs->pdu, vs->offset, "bqqds", vs->glock->type,
        !          3250:                 vs->glock->start, vs->glock->length, vs->glock->proc_id,
        !          3251:                &vs->glock->client_id);
        !          3252: out:
        !          3253:     complete_pdu(s, vs->pdu, err);
        !          3254:     qemu_free(vs->glock);
        !          3255:     qemu_free(vs);
        !          3256: }
        !          3257: 
        !          3258: static void v9fs_mkdir_post_lstat(V9fsState *s, V9fsMkState *vs, int err)
        !          3259: {
        !          3260:     if (err == -1) {
        !          3261:         err = -errno;
        !          3262:         goto out;
        !          3263:     }
        !          3264: 
        !          3265:     stat_to_qid(&vs->stbuf, &vs->qid);
        !          3266:     vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qid);
        !          3267:     err = vs->offset;
        !          3268: out:
        !          3269:     complete_pdu(s, vs->pdu, err);
        !          3270:     v9fs_string_free(&vs->fullname);
        !          3271:     v9fs_string_free(&vs->name);
        !          3272:     qemu_free(vs);
        !          3273: }
        !          3274: 
        !          3275: static void v9fs_mkdir_post_mkdir(V9fsState *s, V9fsMkState *vs, int err)
        !          3276: {
        !          3277:     if (err == -1) {
        !          3278:         err = -errno;
        !          3279:         goto out;
        !          3280:     }
        !          3281: 
        !          3282:     err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
        !          3283:     v9fs_mkdir_post_lstat(s, vs, err);
        !          3284:     return;
        !          3285: out:
        !          3286:     complete_pdu(s, vs->pdu, err);
        !          3287:     v9fs_string_free(&vs->fullname);
        !          3288:     v9fs_string_free(&vs->name);
        !          3289:     qemu_free(vs);
        !          3290: }
        !          3291: 
        !          3292: static void v9fs_mkdir(V9fsState *s, V9fsPDU *pdu)
        !          3293: {
        !          3294:     int32_t fid;
        !          3295:     V9fsMkState *vs;
        !          3296:     int err = 0;
        !          3297:     V9fsFidState *fidp;
        !          3298:     gid_t gid;
        !          3299:     int mode;
        !          3300: 
        !          3301:     vs = qemu_malloc(sizeof(*vs));
        !          3302:     vs->pdu = pdu;
        !          3303:     vs->offset = 7;
        !          3304: 
        !          3305:     v9fs_string_init(&vs->fullname);
        !          3306:     pdu_unmarshal(vs->pdu, vs->offset, "dsdd", &fid, &vs->name, &mode,
        !          3307:         &gid);
        !          3308: 
        !          3309:     fidp = lookup_fid(s, fid);
        !          3310:     if (fidp == NULL) {
        !          3311:         err = -ENOENT;
        !          3312:         goto out;
        !          3313:     }
        !          3314: 
        !          3315:     v9fs_string_sprintf(&vs->fullname, "%s/%s", fidp->path.data, vs->name.data);
        !          3316:     err = v9fs_do_mkdir(s, vs->fullname.data, mode, fidp->uid, gid);
        !          3317:     v9fs_mkdir_post_mkdir(s, vs, err);
        !          3318:     return;
        !          3319: 
        !          3320: out:
        !          3321:     complete_pdu(s, vs->pdu, err);
        !          3322:     v9fs_string_free(&vs->fullname);
        !          3323:     v9fs_string_free(&vs->name);
        !          3324:     qemu_free(vs);
        !          3325: }
        !          3326: 
        !          3327: static void v9fs_post_xattr_getvalue(V9fsState *s, V9fsXattrState *vs, int err)
        !          3328: {
        !          3329: 
        !          3330:     if (err < 0) {
        !          3331:         err = -errno;
        !          3332:         free_fid(s, vs->xattr_fidp->fid);
        !          3333:         goto out;
        !          3334:     }
        !          3335:     vs->offset += pdu_marshal(vs->pdu, vs->offset, "q", vs->size);
        !          3336:     err = vs->offset;
        !          3337: out:
        !          3338:     complete_pdu(s, vs->pdu, err);
        !          3339:     v9fs_string_free(&vs->name);
        !          3340:     qemu_free(vs);
        !          3341:     return;
        !          3342: }
        !          3343: 
        !          3344: static void v9fs_post_xattr_check(V9fsState *s, V9fsXattrState *vs, ssize_t err)
        !          3345: {
        !          3346:     if (err < 0) {
        !          3347:         err = -errno;
        !          3348:         free_fid(s, vs->xattr_fidp->fid);
        !          3349:         goto out;
        !          3350:     }
        !          3351:     /*
        !          3352:      * Read the xattr value
        !          3353:      */
        !          3354:     vs->xattr_fidp->fs.xattr.len = vs->size;
        !          3355:     vs->xattr_fidp->fid_type = P9_FID_XATTR;
        !          3356:     vs->xattr_fidp->fs.xattr.copied_len = -1;
        !          3357:     if (vs->size) {
        !          3358:         vs->xattr_fidp->fs.xattr.value = qemu_malloc(vs->size);
        !          3359:         err = v9fs_do_lgetxattr(s, &vs->xattr_fidp->path,
        !          3360:                                 &vs->name, vs->xattr_fidp->fs.xattr.value,
        !          3361:                                 vs->xattr_fidp->fs.xattr.len);
        !          3362:     }
        !          3363:     v9fs_post_xattr_getvalue(s, vs, err);
        !          3364:     return;
        !          3365: out:
        !          3366:     complete_pdu(s, vs->pdu, err);
        !          3367:     v9fs_string_free(&vs->name);
        !          3368:     qemu_free(vs);
        !          3369: }
        !          3370: 
        !          3371: static void v9fs_post_lxattr_getvalue(V9fsState *s,
        !          3372:                                       V9fsXattrState *vs, int err)
        !          3373: {
        !          3374:     if (err < 0) {
        !          3375:         err = -errno;
        !          3376:         free_fid(s, vs->xattr_fidp->fid);
        !          3377:         goto out;
        !          3378:     }
        !          3379:     vs->offset += pdu_marshal(vs->pdu, vs->offset, "q", vs->size);
        !          3380:     err = vs->offset;
        !          3381: out:
        !          3382:     complete_pdu(s, vs->pdu, err);
        !          3383:     v9fs_string_free(&vs->name);
        !          3384:     qemu_free(vs);
        !          3385:     return;
        !          3386: }
        !          3387: 
        !          3388: static void v9fs_post_lxattr_check(V9fsState *s,
        !          3389:                                    V9fsXattrState *vs, ssize_t err)
        !          3390: {
        !          3391:     if (err < 0) {
        !          3392:         err = -errno;
        !          3393:         free_fid(s, vs->xattr_fidp->fid);
        !          3394:         goto out;
        !          3395:     }
        !          3396:     /*
        !          3397:      * Read the xattr value
        !          3398:      */
        !          3399:     vs->xattr_fidp->fs.xattr.len = vs->size;
        !          3400:     vs->xattr_fidp->fid_type = P9_FID_XATTR;
        !          3401:     vs->xattr_fidp->fs.xattr.copied_len = -1;
        !          3402:     if (vs->size) {
        !          3403:         vs->xattr_fidp->fs.xattr.value = qemu_malloc(vs->size);
        !          3404:         err = v9fs_do_llistxattr(s, &vs->xattr_fidp->path,
        !          3405:                                  vs->xattr_fidp->fs.xattr.value,
        !          3406:                                  vs->xattr_fidp->fs.xattr.len);
        !          3407:     }
        !          3408:     v9fs_post_lxattr_getvalue(s, vs, err);
        !          3409:     return;
        !          3410: out:
        !          3411:     complete_pdu(s, vs->pdu, err);
        !          3412:     v9fs_string_free(&vs->name);
        !          3413:     qemu_free(vs);
        !          3414: }
        !          3415: 
        !          3416: static void v9fs_xattrwalk(V9fsState *s, V9fsPDU *pdu)
        !          3417: {
        !          3418:     ssize_t err = 0;
        !          3419:     V9fsXattrState *vs;
        !          3420:     int32_t fid, newfid;
        !          3421: 
        !          3422:     vs = qemu_malloc(sizeof(*vs));
        !          3423:     vs->pdu = pdu;
        !          3424:     vs->offset = 7;
        !          3425: 
        !          3426:     pdu_unmarshal(vs->pdu, vs->offset, "dds", &fid, &newfid, &vs->name);
        !          3427:     vs->file_fidp = lookup_fid(s, fid);
        !          3428:     if (vs->file_fidp == NULL) {
        !          3429:         err = -ENOENT;
        !          3430:         goto out;
        !          3431:     }
        !          3432: 
        !          3433:     vs->xattr_fidp = alloc_fid(s, newfid);
        !          3434:     if (vs->xattr_fidp == NULL) {
        !          3435:         err = -EINVAL;
        !          3436:         goto out;
        !          3437:     }
        !          3438: 
        !          3439:     v9fs_string_copy(&vs->xattr_fidp->path, &vs->file_fidp->path);
        !          3440:     if (vs->name.data[0] == 0) {
        !          3441:         /*
        !          3442:          * listxattr request. Get the size first
        !          3443:          */
        !          3444:         vs->size = v9fs_do_llistxattr(s, &vs->xattr_fidp->path,
        !          3445:                                       NULL, 0);
        !          3446:         if (vs->size < 0) {
        !          3447:             err = vs->size;
        !          3448:         }
        !          3449:         v9fs_post_lxattr_check(s, vs, err);
        !          3450:         return;
        !          3451:     } else {
        !          3452:         /*
        !          3453:          * specific xattr fid. We check for xattr
        !          3454:          * presence also collect the xattr size
        !          3455:          */
        !          3456:         vs->size = v9fs_do_lgetxattr(s, &vs->xattr_fidp->path,
        !          3457:                                      &vs->name, NULL, 0);
        !          3458:         if (vs->size < 0) {
        !          3459:             err = vs->size;
        !          3460:         }
        !          3461:         v9fs_post_xattr_check(s, vs, err);
        !          3462:         return;
        !          3463:     }
        !          3464: out:
        !          3465:     complete_pdu(s, vs->pdu, err);
        !          3466:     v9fs_string_free(&vs->name);
        !          3467:     qemu_free(vs);
        !          3468: }
        !          3469: 
        !          3470: static void v9fs_xattrcreate(V9fsState *s, V9fsPDU *pdu)
        !          3471: {
        !          3472:     int flags;
        !          3473:     int32_t fid;
        !          3474:     ssize_t err = 0;
        !          3475:     V9fsXattrState *vs;
        !          3476: 
        !          3477:     vs = qemu_malloc(sizeof(*vs));
        !          3478:     vs->pdu = pdu;
        !          3479:     vs->offset = 7;
        !          3480: 
        !          3481:     pdu_unmarshal(vs->pdu, vs->offset, "dsqd",
        !          3482:                   &fid, &vs->name, &vs->size, &flags);
        !          3483: 
        !          3484:     vs->file_fidp = lookup_fid(s, fid);
        !          3485:     if (vs->file_fidp == NULL) {
        !          3486:         err = -EINVAL;
        !          3487:         goto out;
        !          3488:     }
        !          3489: 
        !          3490:     /* Make the file fid point to xattr */
        !          3491:     vs->xattr_fidp = vs->file_fidp;
        !          3492:     vs->xattr_fidp->fid_type = P9_FID_XATTR;
        !          3493:     vs->xattr_fidp->fs.xattr.copied_len = 0;
        !          3494:     vs->xattr_fidp->fs.xattr.len = vs->size;
        !          3495:     vs->xattr_fidp->fs.xattr.flags = flags;
        !          3496:     v9fs_string_init(&vs->xattr_fidp->fs.xattr.name);
        !          3497:     v9fs_string_copy(&vs->xattr_fidp->fs.xattr.name, &vs->name);
        !          3498:     if (vs->size)
        !          3499:         vs->xattr_fidp->fs.xattr.value = qemu_malloc(vs->size);
        !          3500:     else
        !          3501:         vs->xattr_fidp->fs.xattr.value = NULL;
        !          3502: 
        !          3503: out:
        !          3504:     complete_pdu(s, vs->pdu, err);
        !          3505:     v9fs_string_free(&vs->name);
        !          3506:     qemu_free(vs);
        !          3507: }
        !          3508: 
        !          3509: static void v9fs_readlink_post_readlink(V9fsState *s, V9fsReadLinkState *vs,
        !          3510:                                                     int err)
        !          3511: {
        !          3512:     if (err < 0) {
        !          3513:         err = -errno;
        !          3514:         goto out;
        !          3515:     }
        !          3516:     vs->offset += pdu_marshal(vs->pdu, vs->offset, "s", &vs->target);
        !          3517:     err = vs->offset;
        !          3518: out:
        !          3519:     complete_pdu(s, vs->pdu, err);
        !          3520:     v9fs_string_free(&vs->target);
        !          3521:     qemu_free(vs);
        !          3522: }
        !          3523: 
        !          3524: static void v9fs_readlink(V9fsState *s, V9fsPDU *pdu)
        !          3525: {
        !          3526:     int32_t fid;
        !          3527:     V9fsReadLinkState *vs;
        !          3528:     int err = 0;
        !          3529:     V9fsFidState *fidp;
        !          3530: 
        !          3531:     vs = qemu_malloc(sizeof(*vs));
        !          3532:     vs->pdu = pdu;
        !          3533:     vs->offset = 7;
        !          3534: 
        !          3535:     pdu_unmarshal(vs->pdu, vs->offset, "d", &fid);
        !          3536: 
        !          3537:     fidp = lookup_fid(s, fid);
        !          3538:     if (fidp == NULL) {
        !          3539:         err = -ENOENT;
        !          3540:         goto out;
        !          3541:     }
        !          3542: 
        !          3543:     v9fs_string_init(&vs->target);
        !          3544:     err = v9fs_do_readlink(s, &fidp->path, &vs->target);
        !          3545:     v9fs_readlink_post_readlink(s, vs, err);
        !          3546:     return;
        !          3547: out:
        !          3548:     complete_pdu(s, vs->pdu, err);
        !          3549:     qemu_free(vs);
        !          3550: }
        !          3551: 
1.1       root     3552: typedef void (pdu_handler_t)(V9fsState *s, V9fsPDU *pdu);
                   3553: 
                   3554: static pdu_handler_t *pdu_handlers[] = {
1.1.1.2 ! root     3555:     [P9_TREADDIR] = v9fs_readdir,
        !          3556:     [P9_TSTATFS] = v9fs_statfs,
        !          3557:     [P9_TGETATTR] = v9fs_getattr,
        !          3558:     [P9_TSETATTR] = v9fs_setattr,
        !          3559:     [P9_TXATTRWALK] = v9fs_xattrwalk,
        !          3560:     [P9_TXATTRCREATE] = v9fs_xattrcreate,
        !          3561:     [P9_TMKNOD] = v9fs_mknod,
        !          3562:     [P9_TRENAME] = v9fs_rename,
        !          3563:     [P9_TLOCK] = v9fs_lock,
        !          3564:     [P9_TGETLOCK] = v9fs_getlock,
        !          3565:     [P9_TREADLINK] = v9fs_readlink,
        !          3566:     [P9_TMKDIR] = v9fs_mkdir,
1.1       root     3567:     [P9_TVERSION] = v9fs_version,
1.1.1.2 ! root     3568:     [P9_TLOPEN] = v9fs_open,
1.1       root     3569:     [P9_TATTACH] = v9fs_attach,
                   3570:     [P9_TSTAT] = v9fs_stat,
                   3571:     [P9_TWALK] = v9fs_walk,
                   3572:     [P9_TCLUNK] = v9fs_clunk,
1.1.1.2 ! root     3573:     [P9_TFSYNC] = v9fs_fsync,
1.1       root     3574:     [P9_TOPEN] = v9fs_open,
                   3575:     [P9_TREAD] = v9fs_read,
                   3576: #if 0
                   3577:     [P9_TAUTH] = v9fs_auth,
                   3578: #endif
                   3579:     [P9_TFLUSH] = v9fs_flush,
1.1.1.2 ! root     3580:     [P9_TLINK] = v9fs_link,
        !          3581:     [P9_TSYMLINK] = v9fs_symlink,
1.1       root     3582:     [P9_TCREATE] = v9fs_create,
1.1.1.2 ! root     3583:     [P9_TLCREATE] = v9fs_lcreate,
1.1       root     3584:     [P9_TWRITE] = v9fs_write,
                   3585:     [P9_TWSTAT] = v9fs_wstat,
                   3586:     [P9_TREMOVE] = v9fs_remove,
                   3587: };
                   3588: 
                   3589: static void submit_pdu(V9fsState *s, V9fsPDU *pdu)
                   3590: {
                   3591:     pdu_handler_t *handler;
                   3592: 
                   3593:     if (debug_9p_pdu) {
                   3594:         pprint_pdu(pdu);
                   3595:     }
                   3596: 
                   3597:     BUG_ON(pdu->id >= ARRAY_SIZE(pdu_handlers));
                   3598: 
                   3599:     handler = pdu_handlers[pdu->id];
                   3600:     BUG_ON(handler == NULL);
                   3601: 
                   3602:     handler(s, pdu);
                   3603: }
                   3604: 
                   3605: static void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
                   3606: {
                   3607:     V9fsState *s = (V9fsState *)vdev;
                   3608:     V9fsPDU *pdu;
                   3609:     ssize_t len;
                   3610: 
                   3611:     while ((pdu = alloc_pdu(s)) &&
                   3612:             (len = virtqueue_pop(vq, &pdu->elem)) != 0) {
                   3613:         uint8_t *ptr;
                   3614: 
                   3615:         BUG_ON(pdu->elem.out_num == 0 || pdu->elem.in_num == 0);
                   3616:         BUG_ON(pdu->elem.out_sg[0].iov_len < 7);
                   3617: 
                   3618:         ptr = pdu->elem.out_sg[0].iov_base;
                   3619: 
                   3620:         memcpy(&pdu->size, ptr, 4);
                   3621:         pdu->id = ptr[4];
                   3622:         memcpy(&pdu->tag, ptr + 5, 2);
                   3623: 
                   3624:         submit_pdu(s, pdu);
                   3625:     }
                   3626: 
                   3627:     free_pdu(s, pdu);
                   3628: }
                   3629: 
                   3630: static uint32_t virtio_9p_get_features(VirtIODevice *vdev, uint32_t features)
                   3631: {
                   3632:     features |= 1 << VIRTIO_9P_MOUNT_TAG;
                   3633:     return features;
                   3634: }
                   3635: 
                   3636: static V9fsState *to_virtio_9p(VirtIODevice *vdev)
                   3637: {
                   3638:     return (V9fsState *)vdev;
                   3639: }
                   3640: 
                   3641: static void virtio_9p_get_config(VirtIODevice *vdev, uint8_t *config)
                   3642: {
                   3643:     struct virtio_9p_config *cfg;
                   3644:     V9fsState *s = to_virtio_9p(vdev);
                   3645: 
                   3646:     cfg = qemu_mallocz(sizeof(struct virtio_9p_config) +
                   3647:                         s->tag_len);
                   3648:     stw_raw(&cfg->tag_len, s->tag_len);
                   3649:     memcpy(cfg->tag, s->tag, s->tag_len);
                   3650:     memcpy(config, cfg, s->config_size);
                   3651:     qemu_free(cfg);
                   3652: }
                   3653: 
                   3654: VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
                   3655:  {
                   3656:     V9fsState *s;
                   3657:     int i, len;
                   3658:     struct stat stat;
                   3659:     FsTypeEntry *fse;
                   3660: 
                   3661: 
                   3662:     s = (V9fsState *)virtio_common_init("virtio-9p",
                   3663:                                     VIRTIO_ID_9P,
                   3664:                                     sizeof(struct virtio_9p_config)+
                   3665:                                     MAX_TAG_LEN,
                   3666:                                     sizeof(V9fsState));
                   3667: 
                   3668:     /* initialize pdu allocator */
                   3669:     QLIST_INIT(&s->free_list);
                   3670:     for (i = 0; i < (MAX_REQ - 1); i++) {
                   3671:        QLIST_INSERT_HEAD(&s->free_list, &s->pdus[i], next);
                   3672:     }
                   3673: 
                   3674:     s->vq = virtio_add_queue(&s->vdev, MAX_REQ, handle_9p_output);
                   3675: 
                   3676:     fse = get_fsdev_fsentry(conf->fsdev_id);
                   3677: 
                   3678:     if (!fse) {
                   3679:         /* We don't have a fsdev identified by fsdev_id */
1.1.1.2 ! root     3680:         fprintf(stderr, "Virtio-9p device couldn't find fsdev with the "
        !          3681:                 "id = %s\n", conf->fsdev_id ? conf->fsdev_id : "NULL");
1.1       root     3682:         exit(1);
                   3683:     }
                   3684: 
                   3685:     if (!fse->path || !conf->tag) {
                   3686:         /* we haven't specified a mount_tag or the path */
                   3687:         fprintf(stderr, "fsdev with id %s needs path "
                   3688:                 "and Virtio-9p device needs mount_tag arguments\n",
                   3689:                 conf->fsdev_id);
                   3690:         exit(1);
                   3691:     }
                   3692: 
                   3693:     if (!strcmp(fse->security_model, "passthrough")) {
                   3694:         /* Files on the Fileserver set to client user credentials */
                   3695:         s->ctx.fs_sm = SM_PASSTHROUGH;
1.1.1.2 ! root     3696:         s->ctx.xops = passthrough_xattr_ops;
1.1       root     3697:     } else if (!strcmp(fse->security_model, "mapped")) {
                   3698:         /* Files on the fileserver are set to QEMU credentials.
                   3699:          * Client user credentials are saved in extended attributes.
                   3700:          */
                   3701:         s->ctx.fs_sm = SM_MAPPED;
1.1.1.2 ! root     3702:         s->ctx.xops = mapped_xattr_ops;
        !          3703:     } else if (!strcmp(fse->security_model, "none")) {
        !          3704:         /*
        !          3705:          * Files on the fileserver are set to QEMU credentials.
        !          3706:          */
        !          3707:         s->ctx.fs_sm = SM_NONE;
        !          3708:         s->ctx.xops = none_xattr_ops;
1.1       root     3709:     } else {
1.1.1.2 ! root     3710:         fprintf(stderr, "Default to security_model=none. You may want"
        !          3711:                 " enable advanced security model using "
1.1       root     3712:                 "security option:\n\t security_model=passthrough \n\t "
                   3713:                 "security_model=mapped\n");
1.1.1.2 ! root     3714:         s->ctx.fs_sm = SM_NONE;
        !          3715:         s->ctx.xops = none_xattr_ops;
1.1       root     3716:     }
                   3717: 
                   3718:     if (lstat(fse->path, &stat)) {
                   3719:         fprintf(stderr, "share path %s does not exist\n", fse->path);
                   3720:         exit(1);
                   3721:     } else if (!S_ISDIR(stat.st_mode)) {
                   3722:         fprintf(stderr, "share path %s is not a directory \n", fse->path);
                   3723:         exit(1);
                   3724:     }
                   3725: 
                   3726:     s->ctx.fs_root = qemu_strdup(fse->path);
                   3727:     len = strlen(conf->tag);
                   3728:     if (len > MAX_TAG_LEN) {
                   3729:         len = MAX_TAG_LEN;
                   3730:     }
                   3731:     /* s->tag is non-NULL terminated string */
                   3732:     s->tag = qemu_malloc(len);
                   3733:     memcpy(s->tag, conf->tag, len);
                   3734:     s->tag_len = len;
                   3735:     s->ctx.uid = -1;
                   3736: 
                   3737:     s->ops = fse->ops;
                   3738:     s->vdev.get_features = virtio_9p_get_features;
                   3739:     s->config_size = sizeof(struct virtio_9p_config) +
                   3740:                         s->tag_len;
                   3741:     s->vdev.get_config = virtio_9p_get_config;
                   3742: 
                   3743:     return &s->vdev;
                   3744: }

unix.superglobalmegacorp.com

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