Revision c79ce737

b/hw/virtio-9p-local.c
442 442

  
443 443
static int local_chown(FsContext *fs_ctx, const char *path, FsCred *credp)
444 444
{
445
    if (fs_ctx->fs_sm == SM_MAPPED) {
445
    if ((credp->fc_uid == -1 && credp->fc_gid == -1) ||
446
            (fs_ctx->fs_sm == SM_PASSTHROUGH)) {
447
        return lchown(rpath(fs_ctx, path), credp->fc_uid, credp->fc_gid);
448
    } else if (fs_ctx->fs_sm == SM_MAPPED) {
446 449
        return local_set_xattr(rpath(fs_ctx, path), credp);
447 450
    } else if (fs_ctx->fs_sm == SM_PASSTHROUGH) {
448 451
        return lchown(rpath(fs_ctx, path), credp->fc_uid, credp->fc_gid);
b/hw/virtio-9p.c
665 665
                        &statp->n_muid);
666 666
            break;
667 667
        }
668
        case 'I': {
669
            V9fsIattr *iattr = va_arg(ap, V9fsIattr *);
670
            offset += pdu_unmarshal(pdu, offset, "ddddqqqqq",
671
                        &iattr->valid, &iattr->mode,
672
                        &iattr->uid, &iattr->gid, &iattr->size,
673
                        &iattr->atime_sec, &iattr->atime_nsec,
674
                        &iattr->mtime_sec, &iattr->mtime_nsec);
675
            break;
676
        }
668 677
        default:
669 678
            break;
670 679
        }
......
1240 1249
    qemu_free(vs);
1241 1250
}
1242 1251

  
1252
/* From Linux kernel code */
1253
#define ATTR_MODE    (1 << 0)
1254
#define ATTR_UID     (1 << 1)
1255
#define ATTR_GID     (1 << 2)
1256
#define ATTR_SIZE    (1 << 3)
1257
#define ATTR_ATIME   (1 << 4)
1258
#define ATTR_MTIME   (1 << 5)
1259
#define ATTR_CTIME   (1 << 6)
1260
#define ATTR_MASK    127
1261
#define ATTR_ATIME_SET  (1 << 7)
1262
#define ATTR_MTIME_SET  (1 << 8)
1263

  
1264
static void v9fs_setattr_post_truncate(V9fsState *s, V9fsSetattrState *vs,
1265
                                                                  int err)
1266
{
1267
    if (err == -1) {
1268
        err = -errno;
1269
        goto out;
1270
    }
1271
    err = vs->offset;
1272

  
1273
out:
1274
    complete_pdu(s, vs->pdu, err);
1275
    qemu_free(vs);
1276
}
1277

  
1278
static void v9fs_setattr_post_chown(V9fsState *s, V9fsSetattrState *vs, int err)
1279
{
1280
    if (err == -1) {
1281
        err = -errno;
1282
        goto out;
1283
    }
1284

  
1285
    if (vs->v9iattr.valid & (ATTR_SIZE)) {
1286
        err = v9fs_do_truncate(s, &vs->fidp->path, vs->v9iattr.size);
1287
    }
1288
    v9fs_setattr_post_truncate(s, vs, err);
1289
    return;
1290

  
1291
out:
1292
    complete_pdu(s, vs->pdu, err);
1293
    qemu_free(vs);
1294
}
1295

  
1296
static void v9fs_setattr_post_utimensat(V9fsState *s, V9fsSetattrState *vs,
1297
                                                                   int err)
1298
{
1299
    if (err == -1) {
1300
        err = -errno;
1301
        goto out;
1302
    }
1303

  
1304
    /* If the only valid entry in iattr is ctime we can call
1305
     * chown(-1,-1) to update the ctime of the file
1306
     */
1307
    if ((vs->v9iattr.valid & (ATTR_UID | ATTR_GID)) ||
1308
            ((vs->v9iattr.valid & ATTR_CTIME)
1309
            && !((vs->v9iattr.valid & ATTR_MASK) & ~ATTR_CTIME))) {
1310
        if (!(vs->v9iattr.valid & ATTR_UID)) {
1311
            vs->v9iattr.uid = -1;
1312
        }
1313
        if (!(vs->v9iattr.valid & ATTR_GID)) {
1314
            vs->v9iattr.gid = -1;
1315
        }
1316
        err = v9fs_do_chown(s, &vs->fidp->path, vs->v9iattr.uid,
1317
                                                vs->v9iattr.gid);
1318
    }
1319
    v9fs_setattr_post_chown(s, vs, err);
1320
    return;
1321

  
1322
out:
1323
    complete_pdu(s, vs->pdu, err);
1324
    qemu_free(vs);
1325
}
1326

  
1327
static void v9fs_setattr_post_chmod(V9fsState *s, V9fsSetattrState *vs, int err)
1328
{
1329
    if (err == -1) {
1330
        err = -errno;
1331
        goto out;
1332
    }
1333

  
1334
    if (vs->v9iattr.valid & (ATTR_ATIME | ATTR_MTIME)) {
1335
        struct timespec times[2];
1336
        if (vs->v9iattr.valid & ATTR_ATIME) {
1337
            if (vs->v9iattr.valid & ATTR_ATIME_SET) {
1338
                times[0].tv_sec = vs->v9iattr.atime_sec;
1339
                times[0].tv_nsec = vs->v9iattr.atime_nsec;
1340
            } else {
1341
                times[0].tv_nsec = UTIME_NOW;
1342
            }
1343
        } else {
1344
            times[0].tv_nsec = UTIME_OMIT;
1345
        }
1346

  
1347
        if (vs->v9iattr.valid & ATTR_MTIME) {
1348
            if (vs->v9iattr.valid & ATTR_MTIME_SET) {
1349
                times[1].tv_sec = vs->v9iattr.mtime_sec;
1350
                times[1].tv_nsec = vs->v9iattr.mtime_nsec;
1351
            } else {
1352
                times[1].tv_nsec = UTIME_NOW;
1353
            }
1354
        } else {
1355
            times[1].tv_nsec = UTIME_OMIT;
1356
        }
1357
        err = v9fs_do_utimensat(s, &vs->fidp->path, times);
1358
    }
1359
    v9fs_setattr_post_utimensat(s, vs, err);
1360
    return;
1361

  
1362
out:
1363
    complete_pdu(s, vs->pdu, err);
1364
    qemu_free(vs);
1365
}
1366

  
1367
static void v9fs_setattr(V9fsState *s, V9fsPDU *pdu)
1368
{
1369
    int32_t fid;
1370
    V9fsSetattrState *vs;
1371
    int err = 0;
1372

  
1373
    vs = qemu_malloc(sizeof(*vs));
1374
    vs->pdu = pdu;
1375
    vs->offset = 7;
1376

  
1377
    pdu_unmarshal(pdu, vs->offset, "dI", &fid, &vs->v9iattr);
1378

  
1379
    vs->fidp = lookup_fid(s, fid);
1380
    if (vs->fidp == NULL) {
1381
        err = -EINVAL;
1382
        goto out;
1383
    }
1384

  
1385
    if (vs->v9iattr.valid & ATTR_MODE) {
1386
        err = v9fs_do_chmod(s, &vs->fidp->path, vs->v9iattr.mode);
1387
    }
1388

  
1389
    v9fs_setattr_post_chmod(s, vs, err);
1390
    return;
1391

  
1392
out:
1393
    complete_pdu(s, vs->pdu, err);
1394
    qemu_free(vs);
1395
}
1396

  
1243 1397
static void v9fs_walk_complete(V9fsState *s, V9fsWalkState *vs, int err)
1244 1398
{
1245 1399
    complete_pdu(s, vs->pdu, err);
......
2514 2668
    [P9_TREADDIR] = v9fs_readdir,
2515 2669
    [P9_TSTATFS] = v9fs_statfs,
2516 2670
    [P9_TGETATTR] = v9fs_getattr,
2671
    [P9_TSETATTR] = v9fs_setattr,
2517 2672
    [P9_TVERSION] = v9fs_version,
2518 2673
    [P9_TATTACH] = v9fs_attach,
2519 2674
    [P9_TSTAT] = v9fs_stat,
b/hw/virtio-9p.h
17 17
    P9_RSTATFS,
18 18
    P9_TGETATTR = 24,
19 19
    P9_RGETATTR,
20
    P9_TSETATTR = 26,
21
    P9_RSETATTR,
20 22
    P9_TREADDIR = 40,
21 23
    P9_RREADDIR,
22 24
    P9_TVERSION = 100,
......
290 292
    V9fsString nname;
291 293
} V9fsWstatState;
292 294

  
295
typedef struct V9fsIattr
296
{
297
    int32_t valid;
298
    int32_t mode;
299
    int32_t uid;
300
    int32_t gid;
301
    int64_t size;
302
    int64_t atime_sec;
303
    int64_t atime_nsec;
304
    int64_t mtime_sec;
305
    int64_t mtime_nsec;
306
} V9fsIattr;
307

  
308
typedef struct V9fsSetattrState
309
{
310
    V9fsPDU *pdu;
311
    size_t offset;
312
    V9fsIattr v9iattr;
313
    V9fsFidState *fidp;
314
} V9fsSetattrState;
315

  
293 316
struct virtio_9p_config
294 317
{
295 318
    /* number of characters in tag */

Also available in: Unified diff