Revision c18e2f94

b/hw/virtio-9p-debug.c
330 330
    BUG_ON(!llogfile);
331 331

  
332 332
    switch (pdu->id) {
333
    case P9_TREADDIR:
334
        fprintf(llogfile, "TREADDIR: (");
335
        pprint_int32(pdu, 0, &offset, "fid");
336
        pprint_int64(pdu, 0, &offset, ", initial offset");
337
        pprint_int32(pdu, 0, &offset, ", max count");
338
        break;
339
    case P9_RREADDIR:
340
        fprintf(llogfile, "RREADDIR: (");
341
        pprint_int32(pdu, 1, &offset, "count");
342
#ifdef DEBUG_DATA
343
        pprint_data(pdu, 1, &offset, ", data");
344
#endif
345
        break;
333 346
    case P9_TVERSION:
334 347
        fprintf(llogfile, "TVERSION: (");
335 348
        pprint_int32(pdu, 0, &offset, "msize");
b/hw/virtio-9p.c
1577 1577
    qemu_free(vs);
1578 1578
}
1579 1579

  
1580
typedef struct V9fsReadDirState {
1581
    V9fsPDU *pdu;
1582
    V9fsFidState *fidp;
1583
    V9fsQID qid;
1584
    off_t saved_dir_pos;
1585
    struct dirent *dent;
1586
    int32_t count;
1587
    int32_t max_count;
1588
    size_t offset;
1589
    int64_t initial_offset;
1590
    V9fsString name;
1591
} V9fsReadDirState;
1592

  
1593
static void v9fs_readdir_post_seekdir(V9fsState *s, V9fsReadDirState *vs)
1594
{
1595
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
1596
    vs->offset += vs->count;
1597
    complete_pdu(s, vs->pdu, vs->offset);
1598
    qemu_free(vs);
1599
    return;
1600
}
1601

  
1602
/* Size of each dirent on the wire: size of qid (13) + size of offset (8)
1603
 * size of type (1) + size of name.size (2) + strlen(name.data)
1604
 */
1605
#define V9_READDIR_DATA_SZ (24 + strlen(vs->name.data))
1606

  
1607
static void v9fs_readdir_post_readdir(V9fsState *s, V9fsReadDirState *vs)
1608
{
1609
    int len;
1610
    size_t size;
1611

  
1612
    if (vs->dent) {
1613
        v9fs_string_init(&vs->name);
1614
        v9fs_string_sprintf(&vs->name, "%s", vs->dent->d_name);
1615

  
1616
        if ((vs->count + V9_READDIR_DATA_SZ) > vs->max_count) {
1617
            /* Ran out of buffer. Set dir back to old position and return */
1618
            v9fs_do_seekdir(s, vs->fidp->dir, vs->saved_dir_pos);
1619
            v9fs_readdir_post_seekdir(s, vs);
1620
            return;
1621
        }
1622

  
1623
        /* Fill up just the path field of qid because the client uses
1624
         * only that. To fill the entire qid structure we will have
1625
         * to stat each dirent found, which is expensive
1626
         */
1627
        size = MIN(sizeof(vs->dent->d_ino), sizeof(vs->qid.path));
1628
        memcpy(&vs->qid.path, &vs->dent->d_ino, size);
1629
        /* Fill the other fields with dummy values */
1630
        vs->qid.type = 0;
1631
        vs->qid.version = 0;
1632

  
1633
        len = pdu_marshal(vs->pdu, vs->offset+4+vs->count, "Qqbs",
1634
                              &vs->qid, vs->dent->d_off,
1635
                              vs->dent->d_type, &vs->name);
1636
        vs->count += len;
1637
        v9fs_string_free(&vs->name);
1638
        vs->saved_dir_pos = vs->dent->d_off;
1639
        vs->dent = v9fs_do_readdir(s, vs->fidp->dir);
1640
        v9fs_readdir_post_readdir(s, vs);
1641
        return;
1642
    }
1643

  
1644
    vs->offset += pdu_marshal(vs->pdu, vs->offset, "d", vs->count);
1645
    vs->offset += vs->count;
1646
    complete_pdu(s, vs->pdu, vs->offset);
1647
    qemu_free(vs);
1648
    return;
1649
}
1650

  
1651
static void v9fs_readdir_post_telldir(V9fsState *s, V9fsReadDirState *vs)
1652
{
1653
    vs->dent = v9fs_do_readdir(s, vs->fidp->dir);
1654
    v9fs_readdir_post_readdir(s, vs);
1655
    return;
1656
}
1657

  
1658
static void v9fs_readdir_post_setdir(V9fsState *s, V9fsReadDirState *vs)
1659
{
1660
    vs->saved_dir_pos = v9fs_do_telldir(s, vs->fidp->dir);
1661
    v9fs_readdir_post_telldir(s, vs);
1662
    return;
1663
}
1664

  
1665
static void v9fs_readdir(V9fsState *s, V9fsPDU *pdu)
1666
{
1667
    int32_t fid;
1668
    V9fsReadDirState *vs;
1669
    ssize_t err = 0;
1670
    size_t offset = 7;
1671

  
1672
    vs = qemu_malloc(sizeof(*vs));
1673
    vs->pdu = pdu;
1674
    vs->offset = 7;
1675
    vs->count = 0;
1676

  
1677
    pdu_unmarshal(vs->pdu, offset, "dqd", &fid, &vs->initial_offset,
1678
                                                        &vs->max_count);
1679

  
1680
    vs->fidp = lookup_fid(s, fid);
1681
    if (vs->fidp == NULL || !(vs->fidp->dir)) {
1682
        err = -EINVAL;
1683
        goto out;
1684
    }
1685

  
1686
    if (vs->initial_offset == 0) {
1687
        v9fs_do_rewinddir(s, vs->fidp->dir);
1688
    } else {
1689
        v9fs_do_seekdir(s, vs->fidp->dir, vs->initial_offset);
1690
    }
1691

  
1692
    v9fs_readdir_post_setdir(s, vs);
1693
    return;
1694

  
1695
out:
1696
    complete_pdu(s, pdu, err);
1697
    qemu_free(vs);
1698
    return;
1699
}
1700

  
1580 1701
static void v9fs_write_post_writev(V9fsState *s, V9fsWriteState *vs,
1581 1702
                                   ssize_t err)
1582 1703
{
......
2210 2331
typedef void (pdu_handler_t)(V9fsState *s, V9fsPDU *pdu);
2211 2332

  
2212 2333
static pdu_handler_t *pdu_handlers[] = {
2334
    [P9_TREADDIR] = v9fs_readdir,
2213 2335
    [P9_TSTATFS] = v9fs_statfs,
2214 2336
    [P9_TVERSION] = v9fs_version,
2215 2337
    [P9_TATTACH] = v9fs_attach,
b/hw/virtio-9p.h
15 15
enum {
16 16
    P9_TSTATFS = 8,
17 17
    P9_RSTATFS,
18
    P9_TREADDIR = 40,
19
    P9_RREADDIR,
18 20
    P9_TVERSION = 100,
19 21
    P9_RVERSION,
20 22
    P9_TAUTH = 102,

Also available in: Unified diff