diff options
-rw-r--r-- | hw/file-op-9p.h | 1 | ||||
-rw-r--r-- | hw/virtio-9p-local.c | 6 | ||||
-rw-r--r-- | hw/virtio-9p.c | 50 |
3 files changed, 55 insertions, 2 deletions
diff --git a/hw/file-op-9p.h b/hw/file-op-9p.h index 8ba1927fbc..f84767f989 100644 --- a/hw/file-op-9p.h +++ b/hw/file-op-9p.h @@ -34,6 +34,7 @@ typedef struct FileOperations int (*mknod)(FsContext *, const char *, mode_t, dev_t); int (*mksock)(FsContext *, const char *); int (*utime)(FsContext *, const char *, const struct utimbuf *); + int (*remove)(FsContext *, const char *); int (*symlink)(FsContext *, const char *, const char *); int (*link)(FsContext *, const char *, const char *); int (*setuid)(FsContext *, uid_t); diff --git a/hw/virtio-9p-local.c b/hw/virtio-9p-local.c index 5a011f35e8..1afb731548 100644 --- a/hw/virtio-9p-local.c +++ b/hw/virtio-9p-local.c @@ -252,6 +252,11 @@ static int local_utime(FsContext *ctx, const char *path, return utime(rpath(ctx, path), buf); } +static int local_remove(FsContext *ctx, const char *path) +{ + return remove(rpath(ctx, path)); +} + static int local_fsync(FsContext *ctx, int fd) { return fsync(fd); @@ -284,5 +289,6 @@ FileOperations local_ops = { .rename = local_rename, .chown = local_chown, .utime = local_utime, + .remove = local_remove, .fsync = local_fsync, }; diff --git a/hw/virtio-9p.c b/hw/virtio-9p.c index 3288142d7b..ca8cf6e4bd 100644 --- a/hw/virtio-9p.c +++ b/hw/virtio-9p.c @@ -166,6 +166,11 @@ static int v9fs_do_utime(V9fsState *s, V9fsString *path, return s->ops->utime(&s->ctx, path->data, buf); } +static int v9fs_do_remove(V9fsState *s, V9fsString *path) +{ + return s->ops->remove(&s->ctx, path->data); +} + static int v9fs_do_fsync(V9fsState *s, int fd) { return s->ops->fsync(&s->ctx, fd); @@ -1960,11 +1965,52 @@ static void v9fs_flush(V9fsState *s, V9fsPDU *pdu) } } +typedef struct V9fsRemoveState { + V9fsPDU *pdu; + size_t offset; + V9fsFidState *fidp; +} V9fsRemoveState; + +static void v9fs_remove_post_remove(V9fsState *s, V9fsRemoveState *vs, + int err) +{ + /* For TREMOVE we need to clunk the fid even on failed remove */ + err = free_fid(s, vs->fidp->fid); + if (err < 0) { + goto out; + } + + err = vs->offset; +out: + complete_pdu(s, vs->pdu, err); + qemu_free(vs); +} + static void v9fs_remove(V9fsState *s, V9fsPDU *pdu) { - if (debug_9p_pdu) { - pprint_pdu(pdu); + int32_t fid; + V9fsRemoveState *vs; + int err = 0; + + vs = qemu_malloc(sizeof(*vs)); + vs->pdu = pdu; + vs->offset = 7; + + pdu_unmarshal(vs->pdu, vs->offset, "d", &fid); + + vs->fidp = lookup_fid(s, fid); + if (vs->fidp == NULL) { + err = -EINVAL; + goto out; } + + err = v9fs_do_remove(s, &vs->fidp->path); + v9fs_remove_post_remove(s, vs, err); + return; + +out: + complete_pdu(s, pdu, err); + qemu_free(vs); } typedef struct V9fsWstatState |