|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.