This gets file and directory creation to work Signed-off-by: Anthony Liguori <aligu...@us.ibm.com> Signed-off-by: Gautham R Shenoy <e...@in.ibm.com> Signed-off-by: Aneesh Kumar K.V <aneesh.ku...@linux.vnet.ibm.com> --- hw/virtio-9p-local.c | 42 +++++++++ hw/virtio-9p.c | 236 +++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 274 insertions(+), 4 deletions(-)
diff --git a/hw/virtio-9p-local.c b/hw/virtio-9p-local.c index 606f5be..0a9f111 100644 --- a/hw/virtio-9p-local.c +++ b/hw/virtio-9p-local.c @@ -207,6 +207,44 @@ static int local_link(void *opaque, const char *oldpath, const char *newpath) return err; } +static int local_truncate(void *opaque, const char *path, off_t size) +{ + return truncate(rpath(path), size); +} + +static int local_rename(void *opaque, const char *oldpath, + const char *newpath) +{ + char *tmp; + int err; + + tmp = strdup(rpath(oldpath)); + if (tmp == NULL) + return -1; + + err = rename(tmp, rpath(newpath)); + if (err == -1) { + int serrno = errno; + free(tmp); + errno = serrno; + } else + free(tmp); + + return err; + +} + +static int local_chown(void *opaque, const char *path, uid_t uid, gid_t gid) +{ + return chown(rpath(path), uid, gid); +} + +static int local_utime(void *opaque, const char *path, + const struct utimbuf *buf) +{ + return utime(rpath(path), buf); +} + static V9fsPosixFileOperations ops = { .lstat = local_lstat, .setuid = local_setuid, @@ -230,6 +268,10 @@ static V9fsPosixFileOperations ops = { .open2 = local_open2, .symlink = local_symlink, .link = local_link, + .truncate = local_truncate, + .rename = local_rename, + .chown = local_chown, + .utime = local_utime, }; V9fsPosixFileOperations *virtio_9p_init_local(const char *path) diff --git a/hw/virtio-9p.c b/hw/virtio-9p.c index 841fcde..836d65b 100644 --- a/hw/virtio-9p.c +++ b/hw/virtio-9p.c @@ -215,6 +215,28 @@ static int posix_link(V9fsState *s, V9fsString *oldpath, V9fsString *newpath) return s->ops->link(s->ops->opaque, oldpath->data, newpath->data); } +static int posix_truncate(V9fsState *s, V9fsString *path, off_t size) +{ + return s->ops->truncate(s->ops->opaque, path->data, size); +} + +static int posix_rename(V9fsState *s, V9fsString *oldpath, + V9fsString *newpath) +{ + return s->ops->rename(s->ops->opaque, oldpath->data, newpath->data); +} + +static int posix_chown(V9fsState *s, V9fsString *path, uid_t uid, gid_t gid) +{ + return s->ops->chown(s->ops->opaque, path->data, uid, gid); +} + +static int posix_utime(V9fsState *s, V9fsString *path, + const struct utimbuf *buf) +{ + return s->ops->utime(s->ops->opaque, path->data, buf); +} + static void v9fs_string_init(V9fsString *str) { str->data = NULL; @@ -398,7 +420,8 @@ static size_t pdu_unpack(void *dst, V9fsPDU *pdu, size_t offset, size_t size) } /* FIXME i can do this with less variables */ -static size_t pdu_pack(V9fsPDU *pdu, size_t offset, const void *src, size_t size) +static size_t pdu_pack(V9fsPDU *pdu, size_t offset, const void *src, + size_t size) { struct iovec *sg = pdu->elem.in_sg; size_t off = 0; @@ -1615,7 +1638,8 @@ static void v9fs_create_post_lstat(V9fsState *s, V9fsCreateState *vs, int err) uint32_t major, minor; mode_t nmode = 0; - if (sscanf(vs->extension.data, "%c %u %u", &ctype, &major, &minor) != 3) { + if (sscanf(vs->extension.data, "%c %u %u", &ctype, &major, + &minor) != 3) { err = -errno; v9fs_post_create(s, vs, err); } @@ -1701,10 +1725,214 @@ static void v9fs_remove(V9fsState *s, V9fsPDU *pdu) pprint_pdu(pdu); } +static mode_t v9mode_to_mode(uint32_t mode, V9fsString *extension) +{ + mode_t ret; + + ret = mode & 0777; + if (mode & P9_STAT_MODE_DIR) + ret |= S_IFDIR; + + if (dotu) { + if (mode & P9_STAT_MODE_SYMLINK) + ret |= S_IFLNK; + if (mode & P9_STAT_MODE_SOCKET) + ret |= S_IFSOCK; + if (mode & P9_STAT_MODE_NAMED_PIPE) + ret |= S_IFIFO; + if (mode & P9_STAT_MODE_DEVICE) { + if (extension && extension->data[0] == 'c') + ret |= S_IFCHR; + else + ret |= S_IFBLK; + } + } + + if (!(ret&~0777)) + ret |= S_IFREG; + + if (mode & P9_STAT_MODE_SETUID) + ret |= S_ISUID; + if (mode & P9_STAT_MODE_SETGID) + ret |= S_ISGID; + if (mode & P9_STAT_MODE_SETVTX) + ret |= S_ISVTX; + + return ret; +} + +typedef struct V9fsWstatState +{ + V9fsPDU *pdu; + size_t offset; + int32_t fid; + int16_t unused; + V9fsStat v9stat; + V9fsFidState *fidp; + V9fsString nname; +} V9fsWstatState; + +static void v9fs_wstat_post_truncate(V9fsState *s, V9fsWstatState *vs, int err) +{ + if (err < 0) { + goto out; + } + + err = vs->offset; + +out: + v9fs_stat_free(&vs->v9stat); + complete_pdu(s, vs->pdu, err); + qemu_free(vs); +} + +static void v9fs_wstat_post_rename(V9fsState *s, V9fsWstatState *vs, int err) +{ + if (err < 0) { + goto out; + } + + if (vs->v9stat.name.size != 0) { + v9fs_string_free(&vs->nname); + } + + if (vs->v9stat.length != -1) { + if (posix_truncate(s, &vs->fidp->path, vs->v9stat.length) < 0) { + err = -errno; + } + } + v9fs_wstat_post_truncate(s, vs, err); + return; + +out: + v9fs_stat_free(&vs->v9stat); + complete_pdu(s, vs->pdu, err); + qemu_free(vs); +} + +static void v9fs_wstat_post_chown(V9fsState *s, V9fsWstatState *vs, int err) +{ + if (err < 0) { + goto out; + } + + if (vs->v9stat.name.size != 0) { + char *old_name, *new_name; + char *end; + + old_name = vs->fidp->path.data; + if ((end = strrchr(old_name, '/'))) + end++; + else + end = old_name; + + new_name = qemu_malloc(end - old_name + vs->v9stat.name.size + 1); + BUG_ON(new_name == NULL); + + memset(new_name, 0, end - old_name + vs->v9stat.name.size + 1); + memcpy(new_name, old_name, end - old_name); + memcpy(new_name + (end - old_name), vs->v9stat.name.data, + vs->v9stat.name.size); + vs->nname.data = new_name; + vs->nname.size = strlen(new_name); + + if (strcmp(new_name, vs->fidp->path.data) != 0) { + if (posix_rename(s, &vs->fidp->path, &vs->nname)) { + err = -errno; + } + } + } + v9fs_wstat_post_rename(s, vs, err); + return; + +out: + v9fs_stat_free(&vs->v9stat); + complete_pdu(s, vs->pdu, err); + qemu_free(vs); +} + +static void v9fs_wstat_post_utime(V9fsState *s, V9fsWstatState *vs, int err) +{ + if (err < 0) { + goto out; + } + + if (vs->v9stat.n_gid != -1) { + if (posix_chown(s, &vs->fidp->path, vs->v9stat.n_uid, + vs->v9stat.n_gid)) { + err = -errno; + } + } + v9fs_wstat_post_chown(s, vs, err); + return; + +out: + v9fs_stat_free(&vs->v9stat); + complete_pdu(s, vs->pdu, err); + qemu_free(vs); +} + +static void v9fs_wstat_post_chmod(V9fsState *s, V9fsWstatState *vs, int err) +{ + if (err < 0) { + goto out; + } + + if (vs->v9stat.mtime != -1) { + struct utimbuf tb; + tb.actime = 0; + tb.modtime = vs->v9stat.mtime; + if (posix_utime(s, &vs->fidp->path, &tb)) { + err = -errno; + } + } + + v9fs_wstat_post_utime(s, vs, err); + return; + +out: + v9fs_stat_free(&vs->v9stat); + complete_pdu(s, vs->pdu, err); + qemu_free(vs); +} + static void v9fs_wstat(V9fsState *s, V9fsPDU *pdu) { - if (debug_9p_pdu) - pprint_pdu(pdu); + V9fsWstatState *vs; + int err = 0; + + vs = qemu_malloc(sizeof(*vs)); + vs->pdu = pdu; + vs->offset = 7; + + pdu_unmarshal(pdu, vs->offset, "dwS", &vs->fid, &vs->unused, &vs->v9stat); + + vs->fidp = lookup_fid(s, vs->fid); + if (vs->fidp == NULL) { + err = -EINVAL; + goto out; + } + + if (vs->v9stat.mode != -1) { + if (vs->v9stat.mode & P9_STAT_MODE_DIR && vs->fidp->dir == NULL) { + err = -EIO; + goto out; + } + + if (posix_chmod(s, &vs->fidp->path, + v9mode_to_mode(vs->v9stat.mode, + &vs->v9stat.extension))) { + err = -errno; + } + } + + v9fs_wstat_post_chmod(s, vs, err); + return; + +out: + v9fs_stat_free(&vs->v9stat); + complete_pdu(s, vs->pdu, err); + qemu_free(vs); } typedef void (pdu_handler_t)(V9fsState *s, V9fsPDU *pdu); -- 1.6.5.2