From patchwork Wed Mar 3 19:01:08 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anthony Liguori X-Patchwork-Id: 46866 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.gnu.org (lists.gnu.org [199.232.76.165]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (Client did not present a certificate) by ozlabs.org (Postfix) with ESMTPS id EB7E4B7C09 for ; Thu, 4 Mar 2010 06:27:21 +1100 (EST) Received: from localhost ([127.0.0.1]:54728 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NmuE2-0008Bk-As for incoming@patchwork.ozlabs.org; Wed, 03 Mar 2010 14:27:18 -0500 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1NmtpR-0007UV-4k for qemu-devel@nongnu.org; Wed, 03 Mar 2010 14:01:53 -0500 Received: from [199.232.76.173] (port=60470 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1NmtpQ-0007To-JK for qemu-devel@nongnu.org; Wed, 03 Mar 2010 14:01:52 -0500 Received: from Debian-exim by monty-python.gnu.org with spam-scanned (Exim 4.60) (envelope-from ) id 1NmtpO-0001bI-Qt for qemu-devel@nongnu.org; Wed, 03 Mar 2010 14:01:52 -0500 Received: from e4.ny.us.ibm.com ([32.97.182.144]:39310) by monty-python.gnu.org with esmtps (TLS-1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.60) (envelope-from ) id 1NmtpN-0001ay-Sa for qemu-devel@nongnu.org; Wed, 03 Mar 2010 14:01:50 -0500 Received: from d01relay05.pok.ibm.com (d01relay05.pok.ibm.com [9.56.227.237]) by e4.ny.us.ibm.com (8.14.3/8.13.1) with ESMTP id o23IowOs024466 for ; Wed, 3 Mar 2010 13:50:58 -0500 Received: from d03av06.boulder.ibm.com (d03av06.boulder.ibm.com [9.17.195.245]) by d01relay05.pok.ibm.com (8.13.8/8.13.8/NCO v10.0) with ESMTP id o23J1lJS144278 for ; Wed, 3 Mar 2010 14:01:48 -0500 Received: from d03av06.boulder.ibm.com (loopback [127.0.0.1]) by d03av06.boulder.ibm.com (8.14.3/8.13.1/NCO v10.0 AVout) with ESMTP id o23J3kC0010225 for ; Wed, 3 Mar 2010 12:03:46 -0700 Received: from localhost.localdomain (sig-9-76-214-227.mts.ibm.com [9.76.214.227]) by d03av06.boulder.ibm.com (8.14.3/8.13.1/NCO v10.0 AVin) with ESMTP id o23J3daK009640; Wed, 3 Mar 2010 12:03:45 -0700 From: Anthony Liguori To: qemu-devel@nongnu.org Date: Wed, 3 Mar 2010 13:01:08 -0600 Message-Id: <1267642874-15001-13-git-send-email-aliguori@us.ibm.com> X-Mailer: git-send-email 1.6.5.2 In-Reply-To: <1267642874-15001-1-git-send-email-aliguori@us.ibm.com> References: <1267642874-15001-1-git-send-email-aliguori@us.ibm.com> X-detected-operating-system: by monty-python.gnu.org: GNU/Linux 2.6, seldom 2.4 (older, 4) Cc: Anthony Liguori , "Aneesh Kumar K.V" , Gautham R Shenoy Subject: [Qemu-devel] [PATCH 11/17] virtio-9p: Implement P9_TWSTAT X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.5 Precedence: list List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org Errors-To: qemu-devel-bounces+incoming=patchwork.ozlabs.org@nongnu.org This gets file and directory creation to work Signed-off-by: Anthony Liguori Signed-off-by: Gautham R Shenoy Signed-off-by: Aneesh Kumar K.V --- 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);