Statistics
| Branch: | Revision:

root / hw / virtio-9p.c @ 758e8e38

History | View | Annotate | Download (55.3 kB)

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
enum {
25
    Oread   = 0x00,
26
    Owrite  = 0x01,
27
    Ordwr   = 0x02,
28
    Oexec   = 0x03,
29
    Oexcl   = 0x04,
30
    Otrunc  = 0x10,
31
    Orexec  = 0x20,
32
    Orclose = 0x40,
33
    Oappend = 0x80,
34
};
35

    
36
static int omode_to_uflags(int8_t mode)
37
{
38
    int ret = 0;
39

    
40
    switch (mode & 3) {
41
    case Oread:
42
        ret = O_RDONLY;
43
        break;
44
    case Ordwr:
45
        ret = O_RDWR;
46
        break;
47
    case Owrite:
48
        ret = O_WRONLY;
49
        break;
50
    case Oexec:
51
        ret = O_RDONLY;
52
        break;
53
    }
54

    
55
    if (mode & Otrunc) {
56
        ret |= O_TRUNC;
57
    }
58

    
59
    if (mode & Oappend) {
60
        ret |= O_APPEND;
61
    }
62

    
63
    if (mode & Oexcl) {
64
        ret |= O_EXCL;
65
    }
66

    
67
    return ret;
68
}
69

    
70
void cred_init(FsCred *credp)
71
{
72
    credp->fc_uid = -1;
73
    credp->fc_gid = -1;
74
    credp->fc_mode = -1;
75
    credp->fc_rdev = -1;
76
}
77

    
78
static int v9fs_do_lstat(V9fsState *s, V9fsString *path, struct stat *stbuf)
79
{
80
    return s->ops->lstat(&s->ctx, path->data, stbuf);
81
}
82

    
83
static ssize_t v9fs_do_readlink(V9fsState *s, V9fsString *path, V9fsString *buf)
84
{
85
    ssize_t len;
86

    
87
    buf->data = qemu_malloc(1024);
88

    
89
    len = s->ops->readlink(&s->ctx, path->data, buf->data, 1024 - 1);
90
    if (len > -1) {
91
        buf->size = len;
92
        buf->data[len] = 0;
93
    }
94

    
95
    return len;
96
}
97

    
98
static int v9fs_do_close(V9fsState *s, int fd)
99
{
100
    return s->ops->close(&s->ctx, fd);
101
}
102

    
103
static int v9fs_do_closedir(V9fsState *s, DIR *dir)
104
{
105
    return s->ops->closedir(&s->ctx, dir);
106
}
107

    
108
static int v9fs_do_open(V9fsState *s, V9fsString *path, int flags)
109
{
110
    return s->ops->open(&s->ctx, path->data, flags);
111
}
112

    
113
static DIR *v9fs_do_opendir(V9fsState *s, V9fsString *path)
114
{
115
    return s->ops->opendir(&s->ctx, path->data);
116
}
117

    
118
static void v9fs_do_rewinddir(V9fsState *s, DIR *dir)
119
{
120
    return s->ops->rewinddir(&s->ctx, dir);
121
}
122

    
123
static off_t v9fs_do_telldir(V9fsState *s, DIR *dir)
124
{
125
    return s->ops->telldir(&s->ctx, dir);
126
}
127

    
128
static struct dirent *v9fs_do_readdir(V9fsState *s, DIR *dir)
129
{
130
    return s->ops->readdir(&s->ctx, dir);
131
}
132

    
133
static void v9fs_do_seekdir(V9fsState *s, DIR *dir, off_t off)
134
{
135
    return s->ops->seekdir(&s->ctx, dir, off);
136
}
137

    
138
static int v9fs_do_readv(V9fsState *s, int fd, const struct iovec *iov,
139
                            int iovcnt)
140
{
141
    return s->ops->readv(&s->ctx, fd, iov, iovcnt);
142
}
143

    
144
static off_t v9fs_do_lseek(V9fsState *s, int fd, off_t offset, int whence)
145
{
146
    return s->ops->lseek(&s->ctx, fd, offset, whence);
147
}
148

    
149
static int v9fs_do_writev(V9fsState *s, int fd, const struct iovec *iov,
150
                       int iovcnt)
151
{
152
    return s->ops->writev(&s->ctx, fd, iov, iovcnt);
153
}
154

    
155
static int v9fs_do_chmod(V9fsState *s, V9fsString *path, mode_t mode)
156
{
157
    return s->ops->chmod(&s->ctx, path->data, mode);
158
}
159

    
160
static int v9fs_do_mknod(V9fsState *s, V9fsString *path, mode_t mode, dev_t dev)
161
{
162
    return s->ops->mknod(&s->ctx, path->data, mode, dev);
163
}
164

    
165
static int v9fs_do_mksock(V9fsState *s, V9fsString *path)
166
{
167
    return s->ops->mksock(&s->ctx, path->data);
168
}
169

    
170
static int v9fs_do_mkdir(V9fsState *s, V9fsString *path, mode_t mode)
171
{
172
    return s->ops->mkdir(&s->ctx, path->data, mode);
173
}
174

    
175
static int v9fs_do_fstat(V9fsState *s, int fd, struct stat *stbuf)
176
{
177
    return s->ops->fstat(&s->ctx, fd, stbuf);
178
}
179

    
180
static int v9fs_do_open2(V9fsState *s, V9fsString *path, int flags, mode_t mode)
181
{
182
    return s->ops->open2(&s->ctx, path->data, flags, mode);
183
}
184

    
185
static int v9fs_do_symlink(V9fsState *s, V9fsString *oldpath,
186
                            V9fsString *newpath)
187
{
188
    return s->ops->symlink(&s->ctx, oldpath->data, newpath->data);
189
}
190

    
191
static int v9fs_do_link(V9fsState *s, V9fsString *oldpath, V9fsString *newpath)
192
{
193
    return s->ops->link(&s->ctx, oldpath->data, newpath->data);
194
}
195

    
196
static int v9fs_do_truncate(V9fsState *s, V9fsString *path, off_t size)
197
{
198
    return s->ops->truncate(&s->ctx, path->data, size);
199
}
200

    
201
static int v9fs_do_rename(V9fsState *s, V9fsString *oldpath,
202
                            V9fsString *newpath)
203
{
204
    return s->ops->rename(&s->ctx, oldpath->data, newpath->data);
205
}
206

    
207
static int v9fs_do_chown(V9fsState *s, V9fsString *path, uid_t uid, gid_t gid)
208
{
209
    return s->ops->chown(&s->ctx, path->data, uid, gid);
210
}
211

    
212
static int v9fs_do_utime(V9fsState *s, V9fsString *path,
213
                            const struct utimbuf *buf)
214
{
215
    return s->ops->utime(&s->ctx, path->data, buf);
216
}
217

    
218
static int v9fs_do_remove(V9fsState *s, V9fsString *path)
219
{
220
    return s->ops->remove(&s->ctx, path->data);
221
}
222

    
223
static int v9fs_do_fsync(V9fsState *s, int fd)
224
{
225
    return s->ops->fsync(&s->ctx, fd);
226
}
227

    
228
static void v9fs_string_init(V9fsString *str)
229
{
230
    str->data = NULL;
231
    str->size = 0;
232
}
233

    
234
static void v9fs_string_free(V9fsString *str)
235
{
236
    qemu_free(str->data);
237
    str->data = NULL;
238
    str->size = 0;
239
}
240

    
241
static void v9fs_string_null(V9fsString *str)
242
{
243
    v9fs_string_free(str);
244
}
245

    
246
static int number_to_string(void *arg, char type)
247
{
248
    unsigned int ret = 0;
249

    
250
    switch (type) {
251
    case 'u': {
252
        unsigned int num = *(unsigned int *)arg;
253

    
254
        do {
255
            ret++;
256
            num = num/10;
257
        } while (num);
258
        break;
259
    }
260
    default:
261
        printf("Number_to_string: Unknown number format\n");
262
        return -1;
263
    }
264

    
265
    return ret;
266
}
267

    
268
static int v9fs_string_alloc_printf(char **strp, const char *fmt, va_list ap)
269
{
270
    va_list ap2;
271
    char *iter = (char *)fmt;
272
    int len = 0;
273
    int nr_args = 0;
274
    char *arg_char_ptr;
275
    unsigned int arg_uint;
276

    
277
    /* Find the number of %'s that denotes an argument */
278
    for (iter = strstr(iter, "%"); iter; iter = strstr(iter, "%")) {
279
        nr_args++;
280
        iter++;
281
    }
282

    
283
    len = strlen(fmt) - 2*nr_args;
284

    
285
    if (!nr_args) {
286
        goto alloc_print;
287
    }
288

    
289
    va_copy(ap2, ap);
290

    
291
    iter = (char *)fmt;
292

    
293
    /* Now parse the format string */
294
    for (iter = strstr(iter, "%"); iter; iter = strstr(iter, "%")) {
295
        iter++;
296
        switch (*iter) {
297
        case 'u':
298
            arg_uint = va_arg(ap2, unsigned int);
299
            len += number_to_string((void *)&arg_uint, 'u');
300
            break;
301
        case 's':
302
            arg_char_ptr = va_arg(ap2, char *);
303
            len += strlen(arg_char_ptr);
304
            break;
305
        case 'c':
306
            len += 1;
307
            break;
308
        default:
309
            fprintf(stderr,
310
                    "v9fs_string_alloc_printf:Incorrect format %c", *iter);
311
            return -1;
312
        }
313
        iter++;
314
    }
315

    
316
alloc_print:
317
    *strp = qemu_malloc((len + 1) * sizeof(**strp));
318

    
319
    return vsprintf(*strp, fmt, ap);
320
}
321

    
322
static void v9fs_string_sprintf(V9fsString *str, const char *fmt, ...)
323
{
324
    va_list ap;
325
    int err;
326

    
327
    v9fs_string_free(str);
328

    
329
    va_start(ap, fmt);
330
    err = v9fs_string_alloc_printf(&str->data, fmt, ap);
331
    BUG_ON(err == -1);
332
    va_end(ap);
333

    
334
    str->size = err;
335
}
336

    
337
static void v9fs_string_copy(V9fsString *lhs, V9fsString *rhs)
338
{
339
    v9fs_string_free(lhs);
340
    v9fs_string_sprintf(lhs, "%s", rhs->data);
341
}
342

    
343
static size_t v9fs_string_size(V9fsString *str)
344
{
345
    return str->size;
346
}
347

    
348
static V9fsFidState *lookup_fid(V9fsState *s, int32_t fid)
349
{
350
    V9fsFidState *f;
351

    
352
    for (f = s->fid_list; f; f = f->next) {
353
        if (f->fid == fid) {
354
            return f;
355
        }
356
    }
357

    
358
    return NULL;
359
}
360

    
361
static V9fsFidState *alloc_fid(V9fsState *s, int32_t fid)
362
{
363
    V9fsFidState *f;
364

    
365
    f = lookup_fid(s, fid);
366
    if (f) {
367
        return NULL;
368
    }
369

    
370
    f = qemu_mallocz(sizeof(V9fsFidState));
371

    
372
    f->fid = fid;
373
    f->fd = -1;
374
    f->dir = NULL;
375

    
376
    f->next = s->fid_list;
377
    s->fid_list = f;
378

    
379
    return f;
380
}
381

    
382
static int free_fid(V9fsState *s, int32_t fid)
383
{
384
    V9fsFidState **fidpp, *fidp;
385

    
386
    for (fidpp = &s->fid_list; *fidpp; fidpp = &(*fidpp)->next) {
387
        if ((*fidpp)->fid == fid) {
388
            break;
389
        }
390
    }
391

    
392
    if (*fidpp == NULL) {
393
        return -ENOENT;
394
    }
395

    
396
    fidp = *fidpp;
397
    *fidpp = fidp->next;
398

    
399
    if (fidp->fd != -1) {
400
        v9fs_do_close(s, fidp->fd);
401
    }
402
    if (fidp->dir) {
403
        v9fs_do_closedir(s, fidp->dir);
404
    }
405
    v9fs_string_free(&fidp->path);
406
    qemu_free(fidp);
407

    
408
    return 0;
409
}
410

    
411
#define P9_QID_TYPE_DIR         0x80
412
#define P9_QID_TYPE_SYMLINK     0x02
413

    
414
#define P9_STAT_MODE_DIR        0x80000000
415
#define P9_STAT_MODE_APPEND     0x40000000
416
#define P9_STAT_MODE_EXCL       0x20000000
417
#define P9_STAT_MODE_MOUNT      0x10000000
418
#define P9_STAT_MODE_AUTH       0x08000000
419
#define P9_STAT_MODE_TMP        0x04000000
420
#define P9_STAT_MODE_SYMLINK    0x02000000
421
#define P9_STAT_MODE_LINK       0x01000000
422
#define P9_STAT_MODE_DEVICE     0x00800000
423
#define P9_STAT_MODE_NAMED_PIPE 0x00200000
424
#define P9_STAT_MODE_SOCKET     0x00100000
425
#define P9_STAT_MODE_SETUID     0x00080000
426
#define P9_STAT_MODE_SETGID     0x00040000
427
#define P9_STAT_MODE_SETVTX     0x00010000
428

    
429
#define P9_STAT_MODE_TYPE_BITS (P9_STAT_MODE_DIR |          \
430
                                P9_STAT_MODE_SYMLINK |      \
431
                                P9_STAT_MODE_LINK |         \
432
                                P9_STAT_MODE_DEVICE |       \
433
                                P9_STAT_MODE_NAMED_PIPE |   \
434
                                P9_STAT_MODE_SOCKET)
435

    
436
/* This is the algorithm from ufs in spfs */
437
static void stat_to_qid(const struct stat *stbuf, V9fsQID *qidp)
438
{
439
    size_t size;
440

    
441
    size = MIN(sizeof(stbuf->st_ino), sizeof(qidp->path));
442
    memcpy(&qidp->path, &stbuf->st_ino, size);
443
    qidp->version = stbuf->st_mtime ^ (stbuf->st_size << 8);
444
    qidp->type = 0;
445
    if (S_ISDIR(stbuf->st_mode)) {
446
        qidp->type |= P9_QID_TYPE_DIR;
447
    }
448
    if (S_ISLNK(stbuf->st_mode)) {
449
        qidp->type |= P9_QID_TYPE_SYMLINK;
450
    }
451
}
452

    
453
static int fid_to_qid(V9fsState *s, V9fsFidState *fidp, V9fsQID *qidp)
454
{
455
    struct stat stbuf;
456
    int err;
457

    
458
    err = v9fs_do_lstat(s, &fidp->path, &stbuf);
459
    if (err) {
460
        return err;
461
    }
462

    
463
    stat_to_qid(&stbuf, qidp);
464
    return 0;
465
}
466

    
467
static V9fsPDU *alloc_pdu(V9fsState *s)
468
{
469
    V9fsPDU *pdu = NULL;
470

    
471
    if (!QLIST_EMPTY(&s->free_list)) {
472
        pdu = QLIST_FIRST(&s->free_list);
473
        QLIST_REMOVE(pdu, next);
474
    }
475
    return pdu;
476
}
477

    
478
static void free_pdu(V9fsState *s, V9fsPDU *pdu)
479
{
480
    if (pdu) {
481
        QLIST_INSERT_HEAD(&s->free_list, pdu, next);
482
    }
483
}
484

    
485
size_t pdu_packunpack(void *addr, struct iovec *sg, int sg_count,
486
                        size_t offset, size_t size, int pack)
487
{
488
    int i = 0;
489
    size_t copied = 0;
490

    
491
    for (i = 0; size && i < sg_count; i++) {
492
        size_t len;
493
        if (offset >= sg[i].iov_len) {
494
            /* skip this sg */
495
            offset -= sg[i].iov_len;
496
            continue;
497
        } else {
498
            len = MIN(sg[i].iov_len - offset, size);
499
            if (pack) {
500
                memcpy(sg[i].iov_base + offset, addr, len);
501
            } else {
502
                memcpy(addr, sg[i].iov_base + offset, len);
503
            }
504
            size -= len;
505
            copied += len;
506
            addr += len;
507
            if (size) {
508
                offset = 0;
509
                continue;
510
            }
511
        }
512
    }
513

    
514
    return copied;
515
}
516

    
517
static size_t pdu_unpack(void *dst, V9fsPDU *pdu, size_t offset, size_t size)
518
{
519
    return pdu_packunpack(dst, pdu->elem.out_sg, pdu->elem.out_num,
520
                         offset, size, 0);
521
}
522

    
523
static size_t pdu_pack(V9fsPDU *pdu, size_t offset, const void *src,
524
                        size_t size)
525
{
526
    return pdu_packunpack((void *)src, pdu->elem.in_sg, pdu->elem.in_num,
527
                             offset, size, 1);
528
}
529

    
530
static int pdu_copy_sg(V9fsPDU *pdu, size_t offset, int rx, struct iovec *sg)
531
{
532
    size_t pos = 0;
533
    int i, j;
534
    struct iovec *src_sg;
535
    unsigned int num;
536

    
537
    if (rx) {
538
        src_sg = pdu->elem.in_sg;
539
        num = pdu->elem.in_num;
540
    } else {
541
        src_sg = pdu->elem.out_sg;
542
        num = pdu->elem.out_num;
543
    }
544

    
545
    j = 0;
546
    for (i = 0; i < num; i++) {
547
        if (offset <= pos) {
548
            sg[j].iov_base = src_sg[i].iov_base;
549
            sg[j].iov_len = src_sg[i].iov_len;
550
            j++;
551
        } else if (offset < (src_sg[i].iov_len + pos)) {
552
            sg[j].iov_base = src_sg[i].iov_base;
553
            sg[j].iov_len = src_sg[i].iov_len;
554
            sg[j].iov_base += (offset - pos);
555
            sg[j].iov_len -= (offset - pos);
556
            j++;
557
        }
558
        pos += src_sg[i].iov_len;
559
    }
560

    
561
    return j;
562
}
563

    
564
static size_t pdu_unmarshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
565
{
566
    size_t old_offset = offset;
567
    va_list ap;
568
    int i;
569

    
570
    va_start(ap, fmt);
571
    for (i = 0; fmt[i]; i++) {
572
        switch (fmt[i]) {
573
        case 'b': {
574
            uint8_t *valp = va_arg(ap, uint8_t *);
575
            offset += pdu_unpack(valp, pdu, offset, sizeof(*valp));
576
            break;
577
        }
578
        case 'w': {
579
            uint16_t val, *valp;
580
            valp = va_arg(ap, uint16_t *);
581
            val = le16_to_cpupu(valp);
582
            offset += pdu_unpack(&val, pdu, offset, sizeof(val));
583
            *valp = val;
584
            break;
585
        }
586
        case 'd': {
587
            uint32_t val, *valp;
588
            valp = va_arg(ap, uint32_t *);
589
            val = le32_to_cpupu(valp);
590
            offset += pdu_unpack(&val, pdu, offset, sizeof(val));
591
            *valp = val;
592
            break;
593
        }
594
        case 'q': {
595
            uint64_t val, *valp;
596
            valp = va_arg(ap, uint64_t *);
597
            val = le64_to_cpup(valp);
598
            offset += pdu_unpack(&val, pdu, offset, sizeof(val));
599
            *valp = val;
600
            break;
601
        }
602
        case 'v': {
603
            struct iovec *iov = va_arg(ap, struct iovec *);
604
            int *iovcnt = va_arg(ap, int *);
605
            *iovcnt = pdu_copy_sg(pdu, offset, 0, iov);
606
            break;
607
        }
608
        case 's': {
609
            V9fsString *str = va_arg(ap, V9fsString *);
610
            offset += pdu_unmarshal(pdu, offset, "w", &str->size);
611
            /* FIXME: sanity check str->size */
612
            str->data = qemu_malloc(str->size + 1);
613
            offset += pdu_unpack(str->data, pdu, offset, str->size);
614
            str->data[str->size] = 0;
615
            break;
616
        }
617
        case 'Q': {
618
            V9fsQID *qidp = va_arg(ap, V9fsQID *);
619
            offset += pdu_unmarshal(pdu, offset, "bdq",
620
                        &qidp->type, &qidp->version, &qidp->path);
621
            break;
622
        }
623
        case 'S': {
624
            V9fsStat *statp = va_arg(ap, V9fsStat *);
625
            offset += pdu_unmarshal(pdu, offset, "wwdQdddqsssssddd",
626
                        &statp->size, &statp->type, &statp->dev,
627
                        &statp->qid, &statp->mode, &statp->atime,
628
                        &statp->mtime, &statp->length,
629
                        &statp->name, &statp->uid, &statp->gid,
630
                        &statp->muid, &statp->extension,
631
                        &statp->n_uid, &statp->n_gid,
632
                        &statp->n_muid);
633
            break;
634
        }
635
        default:
636
            break;
637
        }
638
    }
639

    
640
    va_end(ap);
641

    
642
    return offset - old_offset;
643
}
644

    
645
static size_t pdu_marshal(V9fsPDU *pdu, size_t offset, const char *fmt, ...)
646
{
647
    size_t old_offset = offset;
648
    va_list ap;
649
    int i;
650

    
651
    va_start(ap, fmt);
652
    for (i = 0; fmt[i]; i++) {
653
        switch (fmt[i]) {
654
        case 'b': {
655
            uint8_t val = va_arg(ap, int);
656
            offset += pdu_pack(pdu, offset, &val, sizeof(val));
657
            break;
658
        }
659
        case 'w': {
660
            uint16_t val;
661
            cpu_to_le16w(&val, va_arg(ap, int));
662
            offset += pdu_pack(pdu, offset, &val, sizeof(val));
663
            break;
664
        }
665
        case 'd': {
666
            uint32_t val;
667
            cpu_to_le32w(&val, va_arg(ap, uint32_t));
668
            offset += pdu_pack(pdu, offset, &val, sizeof(val));
669
            break;
670
        }
671
        case 'q': {
672
            uint64_t val;
673
            cpu_to_le64w(&val, va_arg(ap, uint64_t));
674
            offset += pdu_pack(pdu, offset, &val, sizeof(val));
675
            break;
676
        }
677
        case 'v': {
678
            struct iovec *iov = va_arg(ap, struct iovec *);
679
            int *iovcnt = va_arg(ap, int *);
680
            *iovcnt = pdu_copy_sg(pdu, offset, 1, iov);
681
            break;
682
        }
683
        case 's': {
684
            V9fsString *str = va_arg(ap, V9fsString *);
685
            offset += pdu_marshal(pdu, offset, "w", str->size);
686
            offset += pdu_pack(pdu, offset, str->data, str->size);
687
            break;
688
        }
689
        case 'Q': {
690
            V9fsQID *qidp = va_arg(ap, V9fsQID *);
691
            offset += pdu_marshal(pdu, offset, "bdq",
692
                        qidp->type, qidp->version, qidp->path);
693
            break;
694
        }
695
        case 'S': {
696
            V9fsStat *statp = va_arg(ap, V9fsStat *);
697
            offset += pdu_marshal(pdu, offset, "wwdQdddqsssssddd",
698
                        statp->size, statp->type, statp->dev,
699
                        &statp->qid, statp->mode, statp->atime,
700
                        statp->mtime, statp->length, &statp->name,
701
                        &statp->uid, &statp->gid, &statp->muid,
702
                        &statp->extension, statp->n_uid,
703
                        statp->n_gid, statp->n_muid);
704
            break;
705
        }
706
        default:
707
            break;
708
        }
709
    }
710
    va_end(ap);
711

    
712
    return offset - old_offset;
713
}
714

    
715
static void complete_pdu(V9fsState *s, V9fsPDU *pdu, ssize_t len)
716
{
717
    int8_t id = pdu->id + 1; /* Response */
718

    
719
    if (len < 0) {
720
        V9fsString str;
721
        int err = -len;
722

    
723
        str.data = strerror(err);
724
        str.size = strlen(str.data);
725

    
726
        len = 7;
727
        len += pdu_marshal(pdu, len, "s", &str);
728
        if (dotu) {
729
            len += pdu_marshal(pdu, len, "d", err);
730
        }
731

    
732
        id = P9_RERROR;
733
    }
734

    
735
    /* fill out the header */
736
    pdu_marshal(pdu, 0, "dbw", (int32_t)len, id, pdu->tag);
737

    
738
    /* keep these in sync */
739
    pdu->size = len;
740
    pdu->id = id;
741

    
742
    /* push onto queue and notify */
743
    virtqueue_push(s->vq, &pdu->elem, len);
744

    
745
    /* FIXME: we should batch these completions */
746
    virtio_notify(&s->vdev, s->vq);
747

    
748
    free_pdu(s, pdu);
749
}
750

    
751
static mode_t v9mode_to_mode(uint32_t mode, V9fsString *extension)
752
{
753
    mode_t ret;
754

    
755
    ret = mode & 0777;
756
    if (mode & P9_STAT_MODE_DIR) {
757
        ret |= S_IFDIR;
758
    }
759

    
760
    if (dotu) {
761
        if (mode & P9_STAT_MODE_SYMLINK) {
762
            ret |= S_IFLNK;
763
        }
764
        if (mode & P9_STAT_MODE_SOCKET) {
765
            ret |= S_IFSOCK;
766
        }
767
        if (mode & P9_STAT_MODE_NAMED_PIPE) {
768
            ret |= S_IFIFO;
769
        }
770
        if (mode & P9_STAT_MODE_DEVICE) {
771
            if (extension && extension->data[0] == 'c') {
772
                ret |= S_IFCHR;
773
            } else {
774
                ret |= S_IFBLK;
775
            }
776
        }
777
    }
778

    
779
    if (!(ret&~0777)) {
780
        ret |= S_IFREG;
781
    }
782

    
783
    if (mode & P9_STAT_MODE_SETUID) {
784
        ret |= S_ISUID;
785
    }
786
    if (mode & P9_STAT_MODE_SETGID) {
787
        ret |= S_ISGID;
788
    }
789
    if (mode & P9_STAT_MODE_SETVTX) {
790
        ret |= S_ISVTX;
791
    }
792

    
793
    return ret;
794
}
795

    
796
static int donttouch_stat(V9fsStat *stat)
797
{
798
    if (stat->type == -1 &&
799
        stat->dev == -1 &&
800
        stat->qid.type == -1 &&
801
        stat->qid.version == -1 &&
802
        stat->qid.path == -1 &&
803
        stat->mode == -1 &&
804
        stat->atime == -1 &&
805
        stat->mtime == -1 &&
806
        stat->length == -1 &&
807
        !stat->name.size &&
808
        !stat->uid.size &&
809
        !stat->gid.size &&
810
        !stat->muid.size &&
811
        stat->n_uid == -1 &&
812
        stat->n_gid == -1 &&
813
        stat->n_muid == -1) {
814
        return 1;
815
    }
816

    
817
    return 0;
818
}
819

    
820
static void v9fs_stat_free(V9fsStat *stat)
821
{
822
    v9fs_string_free(&stat->name);
823
    v9fs_string_free(&stat->uid);
824
    v9fs_string_free(&stat->gid);
825
    v9fs_string_free(&stat->muid);
826
    v9fs_string_free(&stat->extension);
827
}
828

    
829
static uint32_t stat_to_v9mode(const struct stat *stbuf)
830
{
831
    uint32_t mode;
832

    
833
    mode = stbuf->st_mode & 0777;
834
    if (S_ISDIR(stbuf->st_mode)) {
835
        mode |= P9_STAT_MODE_DIR;
836
    }
837

    
838
    if (dotu) {
839
        if (S_ISLNK(stbuf->st_mode)) {
840
            mode |= P9_STAT_MODE_SYMLINK;
841
        }
842

    
843
        if (S_ISSOCK(stbuf->st_mode)) {
844
            mode |= P9_STAT_MODE_SOCKET;
845
        }
846

    
847
        if (S_ISFIFO(stbuf->st_mode)) {
848
            mode |= P9_STAT_MODE_NAMED_PIPE;
849
        }
850

    
851
        if (S_ISBLK(stbuf->st_mode) || S_ISCHR(stbuf->st_mode)) {
852
            mode |= P9_STAT_MODE_DEVICE;
853
        }
854

    
855
        if (stbuf->st_mode & S_ISUID) {
856
            mode |= P9_STAT_MODE_SETUID;
857
        }
858

    
859
        if (stbuf->st_mode & S_ISGID) {
860
            mode |= P9_STAT_MODE_SETGID;
861
        }
862

    
863
        if (stbuf->st_mode & S_ISVTX) {
864
            mode |= P9_STAT_MODE_SETVTX;
865
        }
866
    }
867

    
868
    return mode;
869
}
870

    
871
static int stat_to_v9stat(V9fsState *s, V9fsString *name,
872
                            const struct stat *stbuf,
873
                            V9fsStat *v9stat)
874
{
875
    int err;
876
    const char *str;
877

    
878
    memset(v9stat, 0, sizeof(*v9stat));
879

    
880
    stat_to_qid(stbuf, &v9stat->qid);
881
    v9stat->mode = stat_to_v9mode(stbuf);
882
    v9stat->atime = stbuf->st_atime;
883
    v9stat->mtime = stbuf->st_mtime;
884
    v9stat->length = stbuf->st_size;
885

    
886
    v9fs_string_null(&v9stat->uid);
887
    v9fs_string_null(&v9stat->gid);
888
    v9fs_string_null(&v9stat->muid);
889

    
890
    if (dotu) {
891
        v9stat->n_uid = stbuf->st_uid;
892
        v9stat->n_gid = stbuf->st_gid;
893
        v9stat->n_muid = 0;
894

    
895
        v9fs_string_null(&v9stat->extension);
896

    
897
        if (v9stat->mode & P9_STAT_MODE_SYMLINK) {
898
            err = v9fs_do_readlink(s, name, &v9stat->extension);
899
            if (err == -1) {
900
                err = -errno;
901
                return err;
902
            }
903
            v9stat->extension.data[err] = 0;
904
            v9stat->extension.size = err;
905
        } else if (v9stat->mode & P9_STAT_MODE_DEVICE) {
906
            v9fs_string_sprintf(&v9stat->extension, "%c %u %u",
907
                    S_ISCHR(stbuf->st_mode) ? 'c' : 'b',
908
                    major(stbuf->st_rdev), minor(stbuf->st_rdev));
909
        } else if (S_ISDIR(stbuf->st_mode) || S_ISREG(stbuf->st_mode)) {
910
            v9fs_string_sprintf(&v9stat->extension, "%s %u",
911
                    "HARDLINKCOUNT", stbuf->st_nlink);
912
        }
913
    }
914

    
915
    str = strrchr(name->data, '/');
916
    if (str) {
917
        str += 1;
918
    } else {
919
        str = name->data;
920
    }
921

    
922
    v9fs_string_sprintf(&v9stat->name, "%s", str);
923

    
924
    v9stat->size = 61 +
925
        v9fs_string_size(&v9stat->name) +
926
        v9fs_string_size(&v9stat->uid) +
927
        v9fs_string_size(&v9stat->gid) +
928
        v9fs_string_size(&v9stat->muid) +
929
        v9fs_string_size(&v9stat->extension);
930
    return 0;
931
}
932

    
933
static struct iovec *adjust_sg(struct iovec *sg, int len, int *iovcnt)
934
{
935
    while (len && *iovcnt) {
936
        if (len < sg->iov_len) {
937
            sg->iov_len -= len;
938
            sg->iov_base += len;
939
            len = 0;
940
        } else {
941
            len -= sg->iov_len;
942
            sg++;
943
            *iovcnt -= 1;
944
        }
945
    }
946

    
947
    return sg;
948
}
949

    
950
static struct iovec *cap_sg(struct iovec *sg, int cap, int *cnt)
951
{
952
    int i;
953
    int total = 0;
954

    
955
    for (i = 0; i < *cnt; i++) {
956
        if ((total + sg[i].iov_len) > cap) {
957
            sg[i].iov_len -= ((total + sg[i].iov_len) - cap);
958
            i++;
959
            break;
960
        }
961
        total += sg[i].iov_len;
962
    }
963

    
964
    *cnt = i;
965

    
966
    return sg;
967
}
968

    
969
static void print_sg(struct iovec *sg, int cnt)
970
{
971
    int i;
972

    
973
    printf("sg[%d]: {", cnt);
974
    for (i = 0; i < cnt; i++) {
975
        if (i) {
976
            printf(", ");
977
        }
978
        printf("(%p, %zd)", sg[i].iov_base, sg[i].iov_len);
979
    }
980
    printf("}\n");
981
}
982

    
983
static void v9fs_fix_path(V9fsString *dst, V9fsString *src, int len)
984
{
985
    V9fsString str;
986
    v9fs_string_init(&str);
987
    v9fs_string_copy(&str, dst);
988
    v9fs_string_sprintf(dst, "%s%s", src->data, str.data+len);
989
    v9fs_string_free(&str);
990
}
991

    
992
static void v9fs_version(V9fsState *s, V9fsPDU *pdu)
993
{
994
    int32_t msize;
995
    V9fsString version;
996
    size_t offset = 7;
997

    
998
    pdu_unmarshal(pdu, offset, "ds", &msize, &version);
999

    
1000
    if (strcmp(version.data, "9P2000.u")) {
1001
        v9fs_string_sprintf(&version, "unknown");
1002
    }
1003

    
1004
    offset += pdu_marshal(pdu, offset, "ds", msize, &version);
1005
    complete_pdu(s, pdu, offset);
1006

    
1007
    v9fs_string_free(&version);
1008
}
1009

    
1010
static void v9fs_attach(V9fsState *s, V9fsPDU *pdu)
1011
{
1012
    int32_t fid, afid, n_uname;
1013
    V9fsString uname, aname;
1014
    V9fsFidState *fidp;
1015
    V9fsQID qid;
1016
    size_t offset = 7;
1017
    ssize_t err;
1018

    
1019
    pdu_unmarshal(pdu, offset, "ddssd", &fid, &afid, &uname, &aname, &n_uname);
1020

    
1021
    fidp = alloc_fid(s, fid);
1022
    if (fidp == NULL) {
1023
        err = -EINVAL;
1024
        goto out;
1025
    }
1026

    
1027
    fidp->uid = n_uname;
1028

    
1029
    v9fs_string_sprintf(&fidp->path, "%s", "/");
1030
    err = fid_to_qid(s, fidp, &qid);
1031
    if (err) {
1032
        err = -EINVAL;
1033
        free_fid(s, fid);
1034
        goto out;
1035
    }
1036

    
1037
    offset += pdu_marshal(pdu, offset, "Q", &qid);
1038

    
1039
    err = offset;
1040
out:
1041
    complete_pdu(s, pdu, err);
1042
    v9fs_string_free(&uname);
1043
    v9fs_string_free(&aname);
1044
}
1045

    
1046
static void v9fs_stat_post_lstat(V9fsState *s, V9fsStatState *vs, int err)
1047
{
1048
    if (err == -1) {
1049
        err = -errno;
1050
        goto out;
1051
    }
1052

    
1053
    err = stat_to_v9stat(s, &vs->fidp->path, &vs->stbuf, &vs->v9stat);
1054
    if (err) {
1055
        goto out;
1056
    }
1057
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "wS", 0, &vs->v9stat);
1058
    err = vs->offset;
1059

    
1060
out:
1061
    complete_pdu(s, vs->pdu, err);
1062
    v9fs_stat_free(&vs->v9stat);
1063
    qemu_free(vs);
1064
}
1065

    
1066
static void v9fs_stat(V9fsState *s, V9fsPDU *pdu)
1067
{
1068
    int32_t fid;
1069
    V9fsStatState *vs;
1070
    ssize_t err = 0;
1071

    
1072
    vs = qemu_malloc(sizeof(*vs));
1073
    vs->pdu = pdu;
1074
    vs->offset = 7;
1075

    
1076
    memset(&vs->v9stat, 0, sizeof(vs->v9stat));
1077

    
1078
    pdu_unmarshal(vs->pdu, vs->offset, "d", &fid);
1079

    
1080
    vs->fidp = lookup_fid(s, fid);
1081
    if (vs->fidp == NULL) {
1082
        err = -ENOENT;
1083
        goto out;
1084
    }
1085

    
1086
    err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
1087
    v9fs_stat_post_lstat(s, vs, err);
1088
    return;
1089

    
1090
out:
1091
    complete_pdu(s, vs->pdu, err);
1092
    v9fs_stat_free(&vs->v9stat);
1093
    qemu_free(vs);
1094
}
1095

    
1096
static void v9fs_walk_complete(V9fsState *s, V9fsWalkState *vs, int err)
1097
{
1098
    complete_pdu(s, vs->pdu, err);
1099

    
1100
    if (vs->nwnames) {
1101
        for (vs->name_idx = 0; vs->name_idx < vs->nwnames; vs->name_idx++) {
1102
            v9fs_string_free(&vs->wnames[vs->name_idx]);
1103
        }
1104

    
1105
        qemu_free(vs->wnames);
1106
        qemu_free(vs->qids);
1107
    }
1108
}
1109

    
1110
static void v9fs_walk_marshal(V9fsWalkState *vs)
1111
{
1112
    int i;
1113
    vs->offset = 7;
1114
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "w", vs->nwnames);
1115

    
1116
    for (i = 0; i < vs->nwnames; i++) {
1117
        vs->offset += pdu_marshal(vs->pdu, vs->offset, "Q", &vs->qids[i]);
1118
    }
1119
}
1120

    
1121
static void v9fs_walk_post_newfid_lstat(V9fsState *s, V9fsWalkState *vs,
1122
                                                                int err)
1123
{
1124
    if (err == -1) {
1125
        free_fid(s, vs->newfidp->fid);
1126
        v9fs_string_free(&vs->path);
1127
        err = -ENOENT;
1128
        goto out;
1129
    }
1130

    
1131
    stat_to_qid(&vs->stbuf, &vs->qids[vs->name_idx]);
1132

    
1133
    vs->name_idx++;
1134
    if (vs->name_idx < vs->nwnames) {
1135
        v9fs_string_sprintf(&vs->path, "%s/%s", vs->newfidp->path.data,
1136
                                            vs->wnames[vs->name_idx].data);
1137
        v9fs_string_copy(&vs->newfidp->path, &vs->path);
1138

    
1139
        err = v9fs_do_lstat(s, &vs->newfidp->path, &vs->stbuf);
1140
        v9fs_walk_post_newfid_lstat(s, vs, err);
1141
        return;
1142
    }
1143

    
1144
    v9fs_string_free(&vs->path);
1145
    v9fs_walk_marshal(vs);
1146
    err = vs->offset;
1147
out:
1148
    v9fs_walk_complete(s, vs, err);
1149
}
1150

    
1151
static void v9fs_walk_post_oldfid_lstat(V9fsState *s, V9fsWalkState *vs,
1152
        int err)
1153
{
1154
    if (err == -1) {
1155
        v9fs_string_free(&vs->path);
1156
        err = -ENOENT;
1157
        goto out;
1158
    }
1159

    
1160
    stat_to_qid(&vs->stbuf, &vs->qids[vs->name_idx]);
1161
    vs->name_idx++;
1162
    if (vs->name_idx < vs->nwnames) {
1163

    
1164
        v9fs_string_sprintf(&vs->path, "%s/%s",
1165
                vs->fidp->path.data, vs->wnames[vs->name_idx].data);
1166
        v9fs_string_copy(&vs->fidp->path, &vs->path);
1167

    
1168
        err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
1169
        v9fs_walk_post_oldfid_lstat(s, vs, err);
1170
        return;
1171
    }
1172

    
1173
    v9fs_string_free(&vs->path);
1174
    v9fs_walk_marshal(vs);
1175
    err = vs->offset;
1176
out:
1177
    v9fs_walk_complete(s, vs, err);
1178
}
1179

    
1180
static void v9fs_walk(V9fsState *s, V9fsPDU *pdu)
1181
{
1182
    int32_t fid, newfid;
1183
    V9fsWalkState *vs;
1184
    int err = 0;
1185
    int i;
1186

    
1187
    vs = qemu_malloc(sizeof(*vs));
1188
    vs->pdu = pdu;
1189
    vs->wnames = NULL;
1190
    vs->qids = NULL;
1191
    vs->offset = 7;
1192

    
1193
    vs->offset += pdu_unmarshal(vs->pdu, vs->offset, "ddw", &fid,
1194
                                            &newfid, &vs->nwnames);
1195

    
1196
    if (vs->nwnames) {
1197
        vs->wnames = qemu_mallocz(sizeof(vs->wnames[0]) * vs->nwnames);
1198

    
1199
        vs->qids = qemu_mallocz(sizeof(vs->qids[0]) * vs->nwnames);
1200

    
1201
        for (i = 0; i < vs->nwnames; i++) {
1202
            vs->offset += pdu_unmarshal(vs->pdu, vs->offset, "s",
1203
                                            &vs->wnames[i]);
1204
        }
1205
    }
1206

    
1207
    vs->fidp = lookup_fid(s, fid);
1208
    if (vs->fidp == NULL) {
1209
        err = -ENOENT;
1210
        goto out;
1211
    }
1212

    
1213
    /* FIXME: is this really valid? */
1214
    if (fid == newfid) {
1215

    
1216
        BUG_ON(vs->fidp->fd != -1);
1217
        BUG_ON(vs->fidp->dir);
1218
        v9fs_string_init(&vs->path);
1219
        vs->name_idx = 0;
1220

    
1221
        if (vs->name_idx < vs->nwnames) {
1222
            v9fs_string_sprintf(&vs->path, "%s/%s",
1223
                vs->fidp->path.data, vs->wnames[vs->name_idx].data);
1224
            v9fs_string_copy(&vs->fidp->path, &vs->path);
1225

    
1226
            err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
1227
            v9fs_walk_post_oldfid_lstat(s, vs, err);
1228
            return;
1229
        }
1230
    } else {
1231
        vs->newfidp = alloc_fid(s, newfid);
1232
        if (vs->newfidp == NULL) {
1233
            err = -EINVAL;
1234
            goto out;
1235
        }
1236

    
1237
        vs->newfidp->uid = vs->fidp->uid;
1238
        v9fs_string_init(&vs->path);
1239
        vs->name_idx = 0;
1240
        v9fs_string_copy(&vs->newfidp->path, &vs->fidp->path);
1241

    
1242
        if (vs->name_idx < vs->nwnames) {
1243
            v9fs_string_sprintf(&vs->path, "%s/%s", vs->newfidp->path.data,
1244
                                vs->wnames[vs->name_idx].data);
1245
            v9fs_string_copy(&vs->newfidp->path, &vs->path);
1246

    
1247
            err = v9fs_do_lstat(s, &vs->newfidp->path, &vs->stbuf);
1248
            v9fs_walk_post_newfid_lstat(s, vs, err);
1249
            return;
1250
        }
1251
    }
1252

    
1253
    v9fs_walk_marshal(vs);
1254
    err = vs->offset;
1255
out:
1256
    v9fs_walk_complete(s, vs, err);
1257
}
1258

    
1259
static void v9fs_open_post_opendir(V9fsState *s, V9fsOpenState *vs, int err)
1260
{
1261
    if (vs->fidp->dir == NULL) {
1262
        err = -errno;
1263
        goto out;
1264
    }
1265

    
1266
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, 0);
1267
    err = vs->offset;
1268
out:
1269
    complete_pdu(s, vs->pdu, err);
1270
    qemu_free(vs);
1271

    
1272
}
1273

    
1274
static void v9fs_open_post_open(V9fsState *s, V9fsOpenState *vs, int err)
1275
{
1276
    if (vs->fidp->fd == -1) {
1277
        err = -errno;
1278
        goto out;
1279
    }
1280

    
1281
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, 0);
1282
    err = vs->offset;
1283
out:
1284
    complete_pdu(s, vs->pdu, err);
1285
    qemu_free(vs);
1286
}
1287

    
1288
static void v9fs_open_post_lstat(V9fsState *s, V9fsOpenState *vs, int err)
1289
{
1290
    if (err) {
1291
        err = -errno;
1292
        goto out;
1293
    }
1294

    
1295
    stat_to_qid(&vs->stbuf, &vs->qid);
1296

    
1297
    if (S_ISDIR(vs->stbuf.st_mode)) {
1298
        vs->fidp->dir = v9fs_do_opendir(s, &vs->fidp->path);
1299
        v9fs_open_post_opendir(s, vs, err);
1300
    } else {
1301
        vs->fidp->fd = v9fs_do_open(s, &vs->fidp->path,
1302
                                    omode_to_uflags(vs->mode));
1303
        v9fs_open_post_open(s, vs, err);
1304
    }
1305
    return;
1306
out:
1307
    complete_pdu(s, vs->pdu, err);
1308
    qemu_free(vs);
1309
}
1310

    
1311
static void v9fs_open(V9fsState *s, V9fsPDU *pdu)
1312
{
1313
    int32_t fid;
1314
    V9fsOpenState *vs;
1315
    ssize_t err = 0;
1316

    
1317

    
1318
    vs = qemu_malloc(sizeof(*vs));
1319
    vs->pdu = pdu;
1320
    vs->offset = 7;
1321

    
1322
    pdu_unmarshal(vs->pdu, vs->offset, "db", &fid, &vs->mode);
1323

    
1324
    vs->fidp = lookup_fid(s, fid);
1325
    if (vs->fidp == NULL) {
1326
        err = -ENOENT;
1327
        goto out;
1328
    }
1329

    
1330
    BUG_ON(vs->fidp->fd != -1);
1331
    BUG_ON(vs->fidp->dir);
1332

    
1333
    err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
1334

    
1335
    v9fs_open_post_lstat(s, vs, err);
1336
    return;
1337
out:
1338
    complete_pdu(s, pdu, err);
1339
    qemu_free(vs);
1340
}
1341

    
1342
static void v9fs_clunk(V9fsState *s, V9fsPDU *pdu)
1343
{
1344
    int32_t fid;
1345
    size_t offset = 7;
1346
    int err;
1347

    
1348
    pdu_unmarshal(pdu, offset, "d", &fid);
1349

    
1350
    err = free_fid(s, fid);
1351
    if (err < 0) {
1352
        goto out;
1353
    }
1354

    
1355
    offset = 7;
1356
    err = offset;
1357
out:
1358
    complete_pdu(s, pdu, err);
1359
}
1360

    
1361
static void v9fs_read_post_readdir(V9fsState *, V9fsReadState *, ssize_t);
1362

    
1363
static void v9fs_read_post_seekdir(V9fsState *s, V9fsReadState *vs, ssize_t err)
1364
{
1365
    if (err) {
1366
        goto out;
1367
    }
1368
    v9fs_stat_free(&vs->v9stat);
1369
    v9fs_string_free(&vs->name);
1370
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
1371
    vs->offset += vs->count;
1372
    err = vs->offset;
1373
out:
1374
    complete_pdu(s, vs->pdu, err);
1375
    qemu_free(vs);
1376
    return;
1377
}
1378

    
1379
static void v9fs_read_post_dir_lstat(V9fsState *s, V9fsReadState *vs,
1380
                                    ssize_t err)
1381
{
1382
    if (err) {
1383
        err = -errno;
1384
        goto out;
1385
    }
1386
    err = stat_to_v9stat(s, &vs->name, &vs->stbuf, &vs->v9stat);
1387
    if (err) {
1388
        goto out;
1389
    }
1390

    
1391
    vs->len = pdu_marshal(vs->pdu, vs->offset + 4 + vs->count, "S",
1392
                            &vs->v9stat);
1393
    if ((vs->len != (vs->v9stat.size + 2)) ||
1394
            ((vs->count + vs->len) > vs->max_count)) {
1395
        v9fs_do_seekdir(s, vs->fidp->dir, vs->dir_pos);
1396
        v9fs_read_post_seekdir(s, vs, err);
1397
        return;
1398
    }
1399
    vs->count += vs->len;
1400
    v9fs_stat_free(&vs->v9stat);
1401
    v9fs_string_free(&vs->name);
1402
    vs->dir_pos = vs->dent->d_off;
1403
    vs->dent = v9fs_do_readdir(s, vs->fidp->dir);
1404
    v9fs_read_post_readdir(s, vs, err);
1405
    return;
1406
out:
1407
    v9fs_do_seekdir(s, vs->fidp->dir, vs->dir_pos);
1408
    v9fs_read_post_seekdir(s, vs, err);
1409
    return;
1410

    
1411
}
1412

    
1413
static void v9fs_read_post_readdir(V9fsState *s, V9fsReadState *vs, ssize_t err)
1414
{
1415
    if (vs->dent) {
1416
        memset(&vs->v9stat, 0, sizeof(vs->v9stat));
1417
        v9fs_string_init(&vs->name);
1418
        v9fs_string_sprintf(&vs->name, "%s/%s", vs->fidp->path.data,
1419
                            vs->dent->d_name);
1420
        err = v9fs_do_lstat(s, &vs->name, &vs->stbuf);
1421
        v9fs_read_post_dir_lstat(s, vs, err);
1422
        return;
1423
    }
1424

    
1425
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
1426
    vs->offset += vs->count;
1427
    err = vs->offset;
1428
    complete_pdu(s, vs->pdu, err);
1429
    qemu_free(vs);
1430
    return;
1431
}
1432

    
1433
static void v9fs_read_post_telldir(V9fsState *s, V9fsReadState *vs, ssize_t err)
1434
{
1435
    vs->dent = v9fs_do_readdir(s, vs->fidp->dir);
1436
    v9fs_read_post_readdir(s, vs, err);
1437
    return;
1438
}
1439

    
1440
static void v9fs_read_post_rewinddir(V9fsState *s, V9fsReadState *vs,
1441
                                       ssize_t err)
1442
{
1443
    vs->dir_pos = v9fs_do_telldir(s, vs->fidp->dir);
1444
    v9fs_read_post_telldir(s, vs, err);
1445
    return;
1446
}
1447

    
1448
static void v9fs_read_post_readv(V9fsState *s, V9fsReadState *vs, ssize_t err)
1449
{
1450
    if (err  < 0) {
1451
        /* IO error return the error */
1452
        err = -errno;
1453
        goto out;
1454
    }
1455
    vs->total += vs->len;
1456
    vs->sg = adjust_sg(vs->sg, vs->len, &vs->cnt);
1457
    if (vs->total < vs->count && vs->len > 0) {
1458
        do {
1459
            if (0) {
1460
                print_sg(vs->sg, vs->cnt);
1461
            }
1462
            vs->len = v9fs_do_readv(s, vs->fidp->fd, vs->sg, vs->cnt);
1463
        } while (vs->len == -1 && errno == EINTR);
1464
        if (vs->len == -1) {
1465
            err  = -errno;
1466
        }
1467
        v9fs_read_post_readv(s, vs, err);
1468
        return;
1469
    }
1470
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->total);
1471
    vs->offset += vs->count;
1472
    err = vs->offset;
1473

    
1474
out:
1475
    complete_pdu(s, vs->pdu, err);
1476
    qemu_free(vs);
1477
}
1478

    
1479
static void v9fs_read_post_lseek(V9fsState *s, V9fsReadState *vs, ssize_t err)
1480
{
1481
    if (err == -1) {
1482
        err = -errno;
1483
        goto out;
1484
    }
1485
    vs->sg = cap_sg(vs->sg, vs->count, &vs->cnt);
1486

    
1487
    if (vs->total < vs->count) {
1488
        do {
1489
            if (0) {
1490
                print_sg(vs->sg, vs->cnt);
1491
            }
1492
            vs->len = v9fs_do_readv(s, vs->fidp->fd, vs->sg, vs->cnt);
1493
        } while (vs->len == -1 && errno == EINTR);
1494
        if (vs->len == -1) {
1495
            err  = -errno;
1496
        }
1497
        v9fs_read_post_readv(s, vs, err);
1498
        return;
1499
    }
1500
out:
1501
    complete_pdu(s, vs->pdu, err);
1502
    qemu_free(vs);
1503
}
1504

    
1505
static void v9fs_read(V9fsState *s, V9fsPDU *pdu)
1506
{
1507
    int32_t fid;
1508
    V9fsReadState *vs;
1509
    ssize_t err = 0;
1510

    
1511
    vs = qemu_malloc(sizeof(*vs));
1512
    vs->pdu = pdu;
1513
    vs->offset = 7;
1514
    vs->total = 0;
1515
    vs->len = 0;
1516
    vs->count = 0;
1517

    
1518
    pdu_unmarshal(vs->pdu, vs->offset, "dqd", &fid, &vs->off, &vs->count);
1519

    
1520
    vs->fidp = lookup_fid(s, fid);
1521
    if (vs->fidp == NULL) {
1522
        err = -EINVAL;
1523
        goto out;
1524
    }
1525

    
1526
    if (vs->fidp->dir) {
1527
        vs->max_count = vs->count;
1528
        vs->count = 0;
1529
        if (vs->off == 0) {
1530
            v9fs_do_rewinddir(s, vs->fidp->dir);
1531
        }
1532
        v9fs_read_post_rewinddir(s, vs, err);
1533
        return;
1534
    } else if (vs->fidp->fd != -1) {
1535
        vs->sg = vs->iov;
1536
        pdu_marshal(vs->pdu, vs->offset + 4, "v", vs->sg, &vs->cnt);
1537
        err = v9fs_do_lseek(s, vs->fidp->fd, vs->off, SEEK_SET);
1538
        v9fs_read_post_lseek(s, vs, err);
1539
        return;
1540
    } else {
1541
        err = -EINVAL;
1542
    }
1543
out:
1544
    complete_pdu(s, pdu, err);
1545
    qemu_free(vs);
1546
}
1547

    
1548
static void v9fs_write_post_writev(V9fsState *s, V9fsWriteState *vs,
1549
                                   ssize_t err)
1550
{
1551
    if (err  < 0) {
1552
        /* IO error return the error */
1553
        err = -errno;
1554
        goto out;
1555
    }
1556
    vs->total += vs->len;
1557
    vs->sg = adjust_sg(vs->sg, vs->len, &vs->cnt);
1558
    if (vs->total < vs->count && vs->len > 0) {
1559
        do {
1560
            if (0) {
1561
                print_sg(vs->sg, vs->cnt);
1562
            }
1563
            vs->len =  v9fs_do_writev(s, vs->fidp->fd, vs->sg, vs->cnt);
1564
        } while (vs->len == -1 && errno == EINTR);
1565
        if (vs->len == -1) {
1566
            err  = -errno;
1567
        }
1568
        v9fs_write_post_writev(s, vs, err);
1569
        return;
1570
    }
1571
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->total);
1572

    
1573
    err = vs->offset;
1574
out:
1575
    complete_pdu(s, vs->pdu, err);
1576
    qemu_free(vs);
1577
}
1578

    
1579
static void v9fs_write_post_lseek(V9fsState *s, V9fsWriteState *vs, ssize_t err)
1580
{
1581
    if (err == -1) {
1582
        err = -errno;
1583
        goto out;
1584
    }
1585
    vs->sg = cap_sg(vs->sg, vs->count, &vs->cnt);
1586

    
1587
    if (vs->total < vs->count) {
1588
        do {
1589
            if (0) {
1590
                print_sg(vs->sg, vs->cnt);
1591
            }
1592
            vs->len = v9fs_do_writev(s, vs->fidp->fd, vs->sg, vs->cnt);
1593
        } while (vs->len == -1 && errno == EINTR);
1594
        if (vs->len == -1) {
1595
            err  = -errno;
1596
        }
1597
        v9fs_write_post_writev(s, vs, err);
1598
        return;
1599
    }
1600

    
1601
out:
1602
    complete_pdu(s, vs->pdu, err);
1603
    qemu_free(vs);
1604
}
1605

    
1606
static void v9fs_write(V9fsState *s, V9fsPDU *pdu)
1607
{
1608
    int32_t fid;
1609
    V9fsWriteState *vs;
1610
    ssize_t err;
1611

    
1612
    vs = qemu_malloc(sizeof(*vs));
1613

    
1614
    vs->pdu = pdu;
1615
    vs->offset = 7;
1616
    vs->sg = vs->iov;
1617
    vs->total = 0;
1618
    vs->len = 0;
1619

    
1620
    pdu_unmarshal(vs->pdu, vs->offset, "dqdv", &fid, &vs->off, &vs->count,
1621
                    vs->sg, &vs->cnt);
1622

    
1623
    vs->fidp = lookup_fid(s, fid);
1624
    if (vs->fidp == NULL) {
1625
        err = -EINVAL;
1626
        goto out;
1627
    }
1628

    
1629
    if (vs->fidp->fd == -1) {
1630
        err = -EINVAL;
1631
        goto out;
1632
    }
1633

    
1634
    err = v9fs_do_lseek(s, vs->fidp->fd, vs->off, SEEK_SET);
1635

    
1636
    v9fs_write_post_lseek(s, vs, err);
1637
    return;
1638

    
1639
out:
1640
    complete_pdu(s, vs->pdu, err);
1641
    qemu_free(vs);
1642
}
1643

    
1644
static void v9fs_post_create(V9fsState *s, V9fsCreateState *vs, int err)
1645
{
1646
    if (err == 0) {
1647
        v9fs_string_copy(&vs->fidp->path, &vs->fullname);
1648
        stat_to_qid(&vs->stbuf, &vs->qid);
1649

    
1650
        vs->offset += pdu_marshal(vs->pdu, vs->offset, "Qd", &vs->qid, 0);
1651

    
1652
        err = vs->offset;
1653
    }
1654

    
1655
    complete_pdu(s, vs->pdu, err);
1656
    v9fs_string_free(&vs->name);
1657
    v9fs_string_free(&vs->extension);
1658
    v9fs_string_free(&vs->fullname);
1659
    qemu_free(vs);
1660
}
1661

    
1662
static void v9fs_create_post_perms(V9fsState *s, V9fsCreateState *vs, int err)
1663
{
1664
    if (err) {
1665
        err = -errno;
1666
    }
1667
    v9fs_post_create(s, vs, err);
1668
}
1669

    
1670
static void v9fs_create_post_opendir(V9fsState *s, V9fsCreateState *vs,
1671
                                                                    int err)
1672
{
1673
    if (!vs->fidp->dir) {
1674
        err = -errno;
1675
    }
1676
    v9fs_post_create(s, vs, err);
1677
}
1678

    
1679
static void v9fs_create_post_dir_lstat(V9fsState *s, V9fsCreateState *vs,
1680
                                                                    int err)
1681
{
1682
    if (err) {
1683
        err = -errno;
1684
        goto out;
1685
    }
1686

    
1687
    vs->fidp->dir = v9fs_do_opendir(s, &vs->fullname);
1688
    v9fs_create_post_opendir(s, vs, err);
1689
    return;
1690

    
1691
out:
1692
    v9fs_post_create(s, vs, err);
1693
}
1694

    
1695
static void v9fs_create_post_mkdir(V9fsState *s, V9fsCreateState *vs, int err)
1696
{
1697
    if (err) {
1698
        err = -errno;
1699
        goto out;
1700
    }
1701

    
1702
    err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
1703
    v9fs_create_post_dir_lstat(s, vs, err);
1704
    return;
1705

    
1706
out:
1707
    v9fs_post_create(s, vs, err);
1708
}
1709

    
1710
static void v9fs_create_post_mksock(V9fsState *s, V9fsCreateState *vs,
1711
                                                                int err)
1712
{
1713
    if (err) {
1714
        err = -errno;
1715
        goto out;
1716
    }
1717

    
1718
    err = v9fs_do_chmod(s, &vs->fullname, vs->perm & 0777);
1719
    v9fs_create_post_perms(s, vs, err);
1720
    return;
1721

    
1722
out:
1723
    v9fs_post_create(s, vs, err);
1724
}
1725

    
1726
static void v9fs_create_post_fstat(V9fsState *s, V9fsCreateState *vs, int err)
1727
{
1728
    if (err) {
1729
        vs->fidp->fd = -1;
1730
        err = -errno;
1731
    }
1732

    
1733
    v9fs_post_create(s, vs, err);
1734
    return;
1735
}
1736

    
1737
static void v9fs_create_post_open2(V9fsState *s, V9fsCreateState *vs, int err)
1738
{
1739
    if (vs->fidp->fd == -1) {
1740
        err = -errno;
1741
        goto out;
1742
    }
1743

    
1744
    err = v9fs_do_fstat(s, vs->fidp->fd, &vs->stbuf);
1745
    v9fs_create_post_fstat(s, vs, err);
1746

    
1747
    return;
1748

    
1749
out:
1750
    v9fs_post_create(s, vs, err);
1751

    
1752
}
1753

    
1754
static void v9fs_create_post_lstat(V9fsState *s, V9fsCreateState *vs, int err)
1755
{
1756

    
1757
    if (err == 0 || errno != ENOENT) {
1758
        err = -errno;
1759
        goto out;
1760
    }
1761

    
1762
    if (vs->perm & P9_STAT_MODE_DIR) {
1763
        err = v9fs_do_mkdir(s, &vs->fullname, vs->perm & 0777);
1764
        v9fs_create_post_mkdir(s, vs, err);
1765
    } else if (vs->perm & P9_STAT_MODE_SYMLINK) {
1766
        err = v9fs_do_symlink(s, &vs->extension, &vs->fullname);
1767
        v9fs_create_post_perms(s, vs, err);
1768
    } else if (vs->perm & P9_STAT_MODE_LINK) {
1769
        int32_t nfid = atoi(vs->extension.data);
1770
        V9fsFidState *nfidp = lookup_fid(s, nfid);
1771
        if (nfidp == NULL) {
1772
            err = -errno;
1773
            v9fs_post_create(s, vs, err);
1774
        }
1775
        err = v9fs_do_link(s, &nfidp->path, &vs->fullname);
1776
        v9fs_create_post_perms(s, vs, err);
1777
    } else if (vs->perm & P9_STAT_MODE_DEVICE) {
1778
        char ctype;
1779
        uint32_t major, minor;
1780
        mode_t nmode = 0;
1781

    
1782
        if (sscanf(vs->extension.data, "%c %u %u", &ctype, &major,
1783
                                        &minor) != 3) {
1784
            err = -errno;
1785
            v9fs_post_create(s, vs, err);
1786
        }
1787

    
1788
        switch (ctype) {
1789
        case 'c':
1790
            nmode = S_IFCHR;
1791
            break;
1792
        case 'b':
1793
            nmode = S_IFBLK;
1794
            break;
1795
        default:
1796
            err = -EIO;
1797
            v9fs_post_create(s, vs, err);
1798
        }
1799

    
1800
        nmode |= vs->perm & 0777;
1801
        err = v9fs_do_mknod(s, &vs->fullname, nmode, makedev(major, minor));
1802
        v9fs_create_post_perms(s, vs, err);
1803
    } else if (vs->perm & P9_STAT_MODE_NAMED_PIPE) {
1804
        err = v9fs_do_mknod(s, &vs->fullname, S_IFIFO | (vs->mode & 0777), 0);
1805
        v9fs_post_create(s, vs, err);
1806
    } else if (vs->perm & P9_STAT_MODE_SOCKET) {
1807
        err = v9fs_do_mksock(s, &vs->fullname);
1808
        v9fs_create_post_mksock(s, vs, err);
1809
    } else {
1810
        vs->fidp->fd = v9fs_do_open2(s, &vs->fullname,
1811
                                omode_to_uflags(vs->mode) | O_CREAT,
1812
                                vs->perm & 0777);
1813
        v9fs_create_post_open2(s, vs, err);
1814
    }
1815

    
1816
    return;
1817

    
1818
out:
1819
    v9fs_post_create(s, vs, err);
1820
}
1821

    
1822
static void v9fs_create(V9fsState *s, V9fsPDU *pdu)
1823
{
1824
    int32_t fid;
1825
    V9fsCreateState *vs;
1826
    int err = 0;
1827

    
1828
    vs = qemu_malloc(sizeof(*vs));
1829
    vs->pdu = pdu;
1830
    vs->offset = 7;
1831

    
1832
    v9fs_string_init(&vs->fullname);
1833

    
1834
    pdu_unmarshal(vs->pdu, vs->offset, "dsdbs", &fid, &vs->name,
1835
                                &vs->perm, &vs->mode, &vs->extension);
1836

    
1837
    vs->fidp = lookup_fid(s, fid);
1838
    if (vs->fidp == NULL) {
1839
        err = -EINVAL;
1840
        goto out;
1841
    }
1842

    
1843
    v9fs_string_sprintf(&vs->fullname, "%s/%s", vs->fidp->path.data,
1844
                                                        vs->name.data);
1845

    
1846
    err = v9fs_do_lstat(s, &vs->fullname, &vs->stbuf);
1847
    v9fs_create_post_lstat(s, vs, err);
1848
    return;
1849

    
1850
out:
1851
    complete_pdu(s, vs->pdu, err);
1852
    v9fs_string_free(&vs->name);
1853
    v9fs_string_free(&vs->extension);
1854
    qemu_free(vs);
1855
}
1856

    
1857
static void v9fs_flush(V9fsState *s, V9fsPDU *pdu)
1858
{
1859
    /* A nop call with no return */
1860
    complete_pdu(s, pdu, 7);
1861
}
1862

    
1863
static void v9fs_remove_post_remove(V9fsState *s, V9fsRemoveState *vs,
1864
                                                                int err)
1865
{
1866
    /* For TREMOVE we need to clunk the fid even on failed remove */
1867
    err = free_fid(s, vs->fidp->fid);
1868
    if (err < 0) {
1869
        goto out;
1870
    }
1871

    
1872
    err = vs->offset;
1873
out:
1874
    complete_pdu(s, vs->pdu, err);
1875
    qemu_free(vs);
1876
}
1877

    
1878
static void v9fs_remove(V9fsState *s, V9fsPDU *pdu)
1879
{
1880
    int32_t fid;
1881
    V9fsRemoveState *vs;
1882
    int err = 0;
1883

    
1884
    vs = qemu_malloc(sizeof(*vs));
1885
    vs->pdu = pdu;
1886
    vs->offset = 7;
1887

    
1888
    pdu_unmarshal(vs->pdu, vs->offset, "d", &fid);
1889

    
1890
    vs->fidp = lookup_fid(s, fid);
1891
    if (vs->fidp == NULL) {
1892
        err = -EINVAL;
1893
        goto out;
1894
    }
1895

    
1896
    err = v9fs_do_remove(s, &vs->fidp->path);
1897
    v9fs_remove_post_remove(s, vs, err);
1898
    return;
1899

    
1900
out:
1901
    complete_pdu(s, pdu, err);
1902
    qemu_free(vs);
1903
}
1904

    
1905
static void v9fs_wstat_post_truncate(V9fsState *s, V9fsWstatState *vs, int err)
1906
{
1907
    if (err < 0) {
1908
        goto out;
1909
    }
1910

    
1911
    err = vs->offset;
1912

    
1913
out:
1914
    v9fs_stat_free(&vs->v9stat);
1915
    complete_pdu(s, vs->pdu, err);
1916
    qemu_free(vs);
1917
}
1918

    
1919
static void v9fs_wstat_post_rename(V9fsState *s, V9fsWstatState *vs, int err)
1920
{
1921
    if (err < 0) {
1922
        goto out;
1923
    }
1924

    
1925
    if (vs->v9stat.name.size != 0) {
1926
        v9fs_string_free(&vs->nname);
1927
    }
1928

    
1929
    if (vs->v9stat.length != -1) {
1930
        if (v9fs_do_truncate(s, &vs->fidp->path, vs->v9stat.length) < 0) {
1931
            err = -errno;
1932
        }
1933
    }
1934
    v9fs_wstat_post_truncate(s, vs, err);
1935
    return;
1936

    
1937
out:
1938
    v9fs_stat_free(&vs->v9stat);
1939
    complete_pdu(s, vs->pdu, err);
1940
    qemu_free(vs);
1941
}
1942

    
1943
static void v9fs_wstat_post_chown(V9fsState *s, V9fsWstatState *vs, int err)
1944
{
1945
    V9fsFidState *fidp;
1946
    if (err < 0) {
1947
        goto out;
1948
    }
1949

    
1950
    if (vs->v9stat.name.size != 0) {
1951
        char *old_name, *new_name;
1952
        char *end;
1953

    
1954
        old_name = vs->fidp->path.data;
1955
        end = strrchr(old_name, '/');
1956
        if (end) {
1957
            end++;
1958
        } else {
1959
            end = old_name;
1960
        }
1961

    
1962
        new_name = qemu_malloc(end - old_name + vs->v9stat.name.size + 1);
1963

    
1964
        memset(new_name, 0, end - old_name + vs->v9stat.name.size + 1);
1965
        memcpy(new_name, old_name, end - old_name);
1966
        memcpy(new_name + (end - old_name), vs->v9stat.name.data,
1967
                vs->v9stat.name.size);
1968
        vs->nname.data = new_name;
1969
        vs->nname.size = strlen(new_name);
1970

    
1971
        if (strcmp(new_name, vs->fidp->path.data) != 0) {
1972
            if (v9fs_do_rename(s, &vs->fidp->path, &vs->nname)) {
1973
                err = -errno;
1974
            } else {
1975
                /*
1976
                 * Fixup fid's pointing to the old name to
1977
                 * start pointing to the new name
1978
                 */
1979
                for (fidp = s->fid_list; fidp; fidp = fidp->next) {
1980

    
1981
                    if (vs->fidp == fidp) {
1982
                        /*
1983
                         * we replace name of this fid towards the end
1984
                         * so that our below strcmp will work
1985
                         */
1986
                        continue;
1987
                    }
1988
                    if (!strncmp(vs->fidp->path.data, fidp->path.data,
1989
                                 strlen(vs->fidp->path.data))) {
1990
                        /* replace the name */
1991
                        v9fs_fix_path(&fidp->path, &vs->nname,
1992
                                      strlen(vs->fidp->path.data));
1993
                    }
1994
                }
1995
                v9fs_string_copy(&vs->fidp->path, &vs->nname);
1996
            }
1997
        }
1998
    }
1999
    v9fs_wstat_post_rename(s, vs, err);
2000
    return;
2001

    
2002
out:
2003
    v9fs_stat_free(&vs->v9stat);
2004
    complete_pdu(s, vs->pdu, err);
2005
    qemu_free(vs);
2006
}
2007

    
2008
static void v9fs_wstat_post_utime(V9fsState *s, V9fsWstatState *vs, int err)
2009
{
2010
    if (err < 0) {
2011
        goto out;
2012
    }
2013

    
2014
    if (vs->v9stat.n_gid != -1) {
2015
        if (v9fs_do_chown(s, &vs->fidp->path, vs->v9stat.n_uid,
2016
                    vs->v9stat.n_gid)) {
2017
            err = -errno;
2018
        }
2019
    }
2020
    v9fs_wstat_post_chown(s, vs, err);
2021
    return;
2022

    
2023
out:
2024
    v9fs_stat_free(&vs->v9stat);
2025
    complete_pdu(s, vs->pdu, err);
2026
    qemu_free(vs);
2027
}
2028

    
2029
static void v9fs_wstat_post_chmod(V9fsState *s, V9fsWstatState *vs, int err)
2030
{
2031
    if (err < 0) {
2032
        goto out;
2033
    }
2034

    
2035
    if (vs->v9stat.mtime != -1) {
2036
        struct utimbuf tb;
2037
        tb.actime = 0;
2038
        tb.modtime = vs->v9stat.mtime;
2039
        if (v9fs_do_utime(s, &vs->fidp->path, &tb)) {
2040
            err = -errno;
2041
        }
2042
    }
2043

    
2044
    v9fs_wstat_post_utime(s, vs, err);
2045
    return;
2046

    
2047
out:
2048
    v9fs_stat_free(&vs->v9stat);
2049
    complete_pdu(s, vs->pdu, err);
2050
    qemu_free(vs);
2051
}
2052

    
2053
static void v9fs_wstat_post_fsync(V9fsState *s, V9fsWstatState *vs, int err)
2054
{
2055
    if (err == -1) {
2056
        err = -errno;
2057
    }
2058
    v9fs_stat_free(&vs->v9stat);
2059
    complete_pdu(s, vs->pdu, err);
2060
    qemu_free(vs);
2061
}
2062

    
2063
static void v9fs_wstat_post_lstat(V9fsState *s, V9fsWstatState *vs, int err)
2064
{
2065
    uint32_t v9_mode;
2066

    
2067
    if (err == -1) {
2068
        err = -errno;
2069
        goto out;
2070
    }
2071

    
2072
    v9_mode = stat_to_v9mode(&vs->stbuf);
2073

    
2074
    if ((vs->v9stat.mode & P9_STAT_MODE_TYPE_BITS) !=
2075
        (v9_mode & P9_STAT_MODE_TYPE_BITS)) {
2076
            /* Attempting to change the type */
2077
            err = -EIO;
2078
            goto out;
2079
    }
2080

    
2081
    if (v9fs_do_chmod(s, &vs->fidp->path, v9mode_to_mode(vs->v9stat.mode,
2082
                    &vs->v9stat.extension))) {
2083
            err = -errno;
2084
     }
2085
    v9fs_wstat_post_chmod(s, vs, err);
2086
    return;
2087

    
2088
out:
2089
    v9fs_stat_free(&vs->v9stat);
2090
    complete_pdu(s, vs->pdu, err);
2091
    qemu_free(vs);
2092
}
2093

    
2094
static void v9fs_wstat(V9fsState *s, V9fsPDU *pdu)
2095
{
2096
    int32_t fid;
2097
    V9fsWstatState *vs;
2098
    int err = 0;
2099

    
2100
    vs = qemu_malloc(sizeof(*vs));
2101
    vs->pdu = pdu;
2102
    vs->offset = 7;
2103

    
2104
    pdu_unmarshal(pdu, vs->offset, "dwS", &fid, &vs->unused, &vs->v9stat);
2105

    
2106
    vs->fidp = lookup_fid(s, fid);
2107
    if (vs->fidp == NULL) {
2108
        err = -EINVAL;
2109
        goto out;
2110
    }
2111

    
2112
    /* do we need to sync the file? */
2113
    if (donttouch_stat(&vs->v9stat)) {
2114
        err = v9fs_do_fsync(s, vs->fidp->fd);
2115
        v9fs_wstat_post_fsync(s, vs, err);
2116
        return;
2117
    }
2118

    
2119
    if (vs->v9stat.mode != -1) {
2120
        err = v9fs_do_lstat(s, &vs->fidp->path, &vs->stbuf);
2121
        v9fs_wstat_post_lstat(s, vs, err);
2122
        return;
2123
    }
2124

    
2125
    v9fs_wstat_post_chmod(s, vs, err);
2126
    return;
2127

    
2128
out:
2129
    v9fs_stat_free(&vs->v9stat);
2130
    complete_pdu(s, vs->pdu, err);
2131
    qemu_free(vs);
2132
}
2133

    
2134
typedef void (pdu_handler_t)(V9fsState *s, V9fsPDU *pdu);
2135

    
2136
static pdu_handler_t *pdu_handlers[] = {
2137
    [P9_TVERSION] = v9fs_version,
2138
    [P9_TATTACH] = v9fs_attach,
2139
    [P9_TSTAT] = v9fs_stat,
2140
    [P9_TWALK] = v9fs_walk,
2141
    [P9_TCLUNK] = v9fs_clunk,
2142
    [P9_TOPEN] = v9fs_open,
2143
    [P9_TREAD] = v9fs_read,
2144
#if 0
2145
    [P9_TAUTH] = v9fs_auth,
2146
#endif
2147
    [P9_TFLUSH] = v9fs_flush,
2148
    [P9_TCREATE] = v9fs_create,
2149
    [P9_TWRITE] = v9fs_write,
2150
    [P9_TWSTAT] = v9fs_wstat,
2151
    [P9_TREMOVE] = v9fs_remove,
2152
};
2153

    
2154
static void submit_pdu(V9fsState *s, V9fsPDU *pdu)
2155
{
2156
    pdu_handler_t *handler;
2157

    
2158
    if (debug_9p_pdu) {
2159
        pprint_pdu(pdu);
2160
    }
2161

    
2162
    BUG_ON(pdu->id >= ARRAY_SIZE(pdu_handlers));
2163

    
2164
    handler = pdu_handlers[pdu->id];
2165
    BUG_ON(handler == NULL);
2166

    
2167
    handler(s, pdu);
2168
}
2169

    
2170
static void handle_9p_output(VirtIODevice *vdev, VirtQueue *vq)
2171
{
2172
    V9fsState *s = (V9fsState *)vdev;
2173
    V9fsPDU *pdu;
2174
    ssize_t len;
2175

    
2176
    while ((pdu = alloc_pdu(s)) &&
2177
            (len = virtqueue_pop(vq, &pdu->elem)) != 0) {
2178
        uint8_t *ptr;
2179

    
2180
        BUG_ON(pdu->elem.out_num == 0 || pdu->elem.in_num == 0);
2181
        BUG_ON(pdu->elem.out_sg[0].iov_len < 7);
2182

    
2183
        ptr = pdu->elem.out_sg[0].iov_base;
2184

    
2185
        memcpy(&pdu->size, ptr, 4);
2186
        pdu->id = ptr[4];
2187
        memcpy(&pdu->tag, ptr + 5, 2);
2188

    
2189
        submit_pdu(s, pdu);
2190
    }
2191

    
2192
    free_pdu(s, pdu);
2193
}
2194

    
2195
static uint32_t virtio_9p_get_features(VirtIODevice *vdev, uint32_t features)
2196
{
2197
    features |= 1 << VIRTIO_9P_MOUNT_TAG;
2198
    return features;
2199
}
2200

    
2201
static V9fsState *to_virtio_9p(VirtIODevice *vdev)
2202
{
2203
    return (V9fsState *)vdev;
2204
}
2205

    
2206
static void virtio_9p_get_config(VirtIODevice *vdev, uint8_t *config)
2207
{
2208
    struct virtio_9p_config *cfg;
2209
    V9fsState *s = to_virtio_9p(vdev);
2210

    
2211
    cfg = qemu_mallocz(sizeof(struct virtio_9p_config) +
2212
                        s->tag_len);
2213
    stw_raw(&cfg->tag_len, s->tag_len);
2214
    memcpy(cfg->tag, s->tag, s->tag_len);
2215
    memcpy(config, cfg, s->config_size);
2216
    qemu_free(cfg);
2217
}
2218

    
2219
VirtIODevice *virtio_9p_init(DeviceState *dev, V9fsConf *conf)
2220
 {
2221
    V9fsState *s;
2222
    int i, len;
2223
    struct stat stat;
2224
    FsTypeEntry *fse;
2225

    
2226

    
2227
    s = (V9fsState *)virtio_common_init("virtio-9p",
2228
                                    VIRTIO_ID_9P,
2229
                                    sizeof(struct virtio_9p_config)+
2230
                                    MAX_TAG_LEN,
2231
                                    sizeof(V9fsState));
2232

    
2233
    /* initialize pdu allocator */
2234
    QLIST_INIT(&s->free_list);
2235
    for (i = 0; i < (MAX_REQ - 1); i++) {
2236
        QLIST_INSERT_HEAD(&s->free_list, &s->pdus[i], next);
2237
    }
2238

    
2239
    s->vq = virtio_add_queue(&s->vdev, MAX_REQ, handle_9p_output);
2240

    
2241
    fse = get_fsdev_fsentry(conf->fsdev_id);
2242

    
2243
    if (!fse) {
2244
        /* We don't have a fsdev identified by fsdev_id */
2245
        fprintf(stderr, "Virtio-9p device couldn't find fsdev "
2246
                    "with the id %s\n", conf->fsdev_id);
2247
        exit(1);
2248
    }
2249

    
2250
    if (!fse->path || !conf->tag) {
2251
        /* we haven't specified a mount_tag or the path */
2252
        fprintf(stderr, "fsdev with id %s needs path "
2253
                "and Virtio-9p device needs mount_tag arguments\n",
2254
                conf->fsdev_id);
2255
        exit(1);
2256
    }
2257

    
2258
    if (!strcmp(fse->security_model, "passthrough")) {
2259
        /* Files on the Fileserver set to client user credentials */
2260
        s->ctx.fs_sm = SM_PASSTHROUGH;
2261
    } else if (!strcmp(fse->security_model, "mapped")) {
2262
        /* Files on the fileserver are set to QEMU credentials.
2263
         * Client user credentials are saved in extended attributes.
2264
         */
2265
        s->ctx.fs_sm = SM_MAPPED;
2266
    } else {
2267
        /* user haven't specified a correct security option */
2268
        fprintf(stderr, "one of the following must be specified as the"
2269
                "security option:\n\t security_model=passthrough \n\t "
2270
                "security_model=mapped\n");
2271
        return NULL;
2272
    }
2273

    
2274
    if (lstat(fse->path, &stat)) {
2275
        fprintf(stderr, "share path %s does not exist\n", fse->path);
2276
        exit(1);
2277
    } else if (!S_ISDIR(stat.st_mode)) {
2278
        fprintf(stderr, "share path %s is not a directory \n", fse->path);
2279
        exit(1);
2280
    }
2281

    
2282
    s->ctx.fs_root = qemu_strdup(fse->path);
2283
    len = strlen(conf->tag);
2284
    if (len > MAX_TAG_LEN) {
2285
        len = MAX_TAG_LEN;
2286
    }
2287
    /* s->tag is non-NULL terminated string */
2288
    s->tag = qemu_malloc(len);
2289
    memcpy(s->tag, conf->tag, len);
2290
    s->tag_len = len;
2291
    s->ctx.uid = -1;
2292

    
2293
    s->ops = fse->ops;
2294
    s->vdev.get_features = virtio_9p_get_features;
2295
    s->config_size = sizeof(struct virtio_9p_config) +
2296
                        s->tag_len;
2297
    s->vdev.get_config = virtio_9p_get_config;
2298

    
2299
    return &s->vdev;
2300
}