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