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