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