diff --git a/fsdev/virtfs-proxy-helper.c b/fsdev/virtfs-proxy-helper.c index 204bb4a540..703ac8567f 100644 --- a/fsdev/virtfs-proxy-helper.c +++ b/fsdev/virtfs-proxy-helper.c @@ -27,6 +27,7 @@ #include #include #include +#include #include "qemu-common.h" #include "virtio-9p-marshal.h" #include "hw/9pfs/virtio-9p-proxy.h" @@ -329,6 +330,62 @@ static int send_response(int sock, struct iovec *iovec, int size) return 0; } +static int do_getxattr(int type, struct iovec *iovec, struct iovec *out_iovec) +{ + int size = 0, offset, retval; + V9fsString path, name, xattr; + + v9fs_string_init(&xattr); + v9fs_string_init(&path); + retval = proxy_unmarshal(iovec, PROXY_HDR_SZ, "ds", &size, &path); + if (retval < 0) { + return retval; + } + offset = PROXY_HDR_SZ + retval; + + if (size) { + xattr.data = g_malloc(size); + xattr.size = size; + } + switch (type) { + case T_LGETXATTR: + v9fs_string_init(&name); + retval = proxy_unmarshal(iovec, offset, "s", &name); + if (retval > 0) { + retval = lgetxattr(path.data, name.data, xattr.data, size); + if (retval < 0) { + retval = -errno; + } else { + xattr.size = retval; + } + } + v9fs_string_free(&name); + break; + case T_LLISTXATTR: + retval = llistxattr(path.data, xattr.data, size); + if (retval < 0) { + retval = -errno; + } else { + xattr.size = retval; + } + break; + } + if (retval < 0) { + goto err_out; + } + + if (!size) { + proxy_marshal(out_iovec, PROXY_HDR_SZ, "d", retval); + retval = sizeof(retval); + } else { + retval = proxy_marshal(out_iovec, PROXY_HDR_SZ, "s", &xattr); + } +err_out: + v9fs_string_free(&xattr); + v9fs_string_free(&path); + return retval; +} + static void stat_to_prstat(ProxyStat *pr_stat, struct stat *stat) { memset(pr_stat, 0, sizeof(*pr_stat)); @@ -605,6 +662,8 @@ static int process_reply(int sock, int type, case T_UTIME: case T_RENAME: case T_REMOVE: + case T_LSETXATTR: + case T_LREMOVEXATTR: if (send_status(sock, out_iovec, retval) < 0) { return -1; } @@ -612,6 +671,8 @@ static int process_reply(int sock, int type, case T_LSTAT: case T_STATFS: case T_READLINK: + case T_LGETXATTR: + case T_LLISTXATTR: if (send_response(sock, out_iovec, retval) < 0) { return -1; } @@ -625,10 +686,13 @@ static int process_reply(int sock, int type, static int process_requests(int sock) { + int flags; + int size = 0; int retval = 0; uint64_t offset; ProxyHeader header; int mode, uid, gid; + V9fsString name, value; struct timespec spec[2]; V9fsString oldpath, path; struct iovec in_iovec, out_iovec; @@ -756,6 +820,41 @@ static int process_requests(int sock) } v9fs_string_free(&path); break; + case T_LGETXATTR: + case T_LLISTXATTR: + retval = do_getxattr(header.type, &in_iovec, &out_iovec); + break; + case T_LSETXATTR: + v9fs_string_init(&path); + v9fs_string_init(&name); + v9fs_string_init(&value); + retval = proxy_unmarshal(&in_iovec, PROXY_HDR_SZ, "sssdd", &path, + &name, &value, &size, &flags); + if (retval > 0) { + retval = lsetxattr(path.data, + name.data, value.data, size, flags); + if (retval < 0) { + retval = -errno; + } + } + v9fs_string_free(&path); + v9fs_string_free(&name); + v9fs_string_free(&value); + break; + case T_LREMOVEXATTR: + v9fs_string_init(&path); + v9fs_string_init(&name); + retval = proxy_unmarshal(&in_iovec, + PROXY_HDR_SZ, "ss", &path, &name); + if (retval > 0) { + retval = lremovexattr(path.data, name.data); + if (retval < 0) { + retval = -errno; + } + } + v9fs_string_free(&path); + v9fs_string_free(&name); + break; default: goto err_out; break; diff --git a/hw/9pfs/virtio-9p-proxy.c b/hw/9pfs/virtio-9p-proxy.c index ef118ff690..22e9b68342 100644 --- a/hw/9pfs/virtio-9p-proxy.c +++ b/hw/9pfs/virtio-9p-proxy.c @@ -234,6 +234,15 @@ static int v9fs_receive_response(V9fsProxy *proxy, int type, v9fs_string_free(&target); break; } + case T_LGETXATTR: + case T_LLISTXATTR: { + V9fsString xattr; + v9fs_string_init(&xattr); + retval = proxy_unmarshal(reply, PROXY_HDR_SZ, "s", &xattr); + memcpy(response, xattr.data, xattr.size); + v9fs_string_free(&xattr); + break; + } default: return -1; } @@ -291,6 +300,7 @@ static int v9fs_request(V9fsProxy *proxy, int type, ProxyHeader header = { 0, 0}; struct timespec spec[2]; int flags, mode, uid, gid; + V9fsString *name, *value; V9fsString *path, *oldpath; struct iovec *iovec = NULL, *reply = NULL; @@ -457,6 +467,48 @@ static int v9fs_request(V9fsProxy *proxy, int type, header.type = T_REMOVE; } break; + case T_LGETXATTR: + size = va_arg(ap, int); + path = va_arg(ap, V9fsString *); + name = va_arg(ap, V9fsString *); + retval = proxy_marshal(iovec, PROXY_HDR_SZ, + "dss", size, path, name); + if (retval > 0) { + header.size = retval; + header.type = T_LGETXATTR; + } + break; + case T_LLISTXATTR: + size = va_arg(ap, int); + path = va_arg(ap, V9fsString *); + retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ds", size, path); + if (retval > 0) { + header.size = retval; + header.type = T_LLISTXATTR; + } + break; + case T_LSETXATTR: + path = va_arg(ap, V9fsString *); + name = va_arg(ap, V9fsString *); + value = va_arg(ap, V9fsString *); + size = va_arg(ap, int); + flags = va_arg(ap, int); + retval = proxy_marshal(iovec, PROXY_HDR_SZ, "sssdd", + path, name, value, size, flags); + if (retval > 0) { + header.size = retval; + header.type = T_LSETXATTR; + } + break; + case T_LREMOVEXATTR: + path = va_arg(ap, V9fsString *); + name = va_arg(ap, V9fsString *); + retval = proxy_marshal(iovec, PROXY_HDR_SZ, "ss", path, name); + if (retval > 0) { + header.size = retval; + header.type = T_LREMOVEXATTR; + } + break; default: error_report("Invalid type %d\n", type); retval = -EINVAL; @@ -498,6 +550,8 @@ static int v9fs_request(V9fsProxy *proxy, int type, case T_TRUNCATE: case T_UTIME: case T_REMOVE: + case T_LSETXATTR: + case T_LREMOVEXATTR: if (v9fs_receive_status(proxy, reply, &retval) < 0) { goto close_error; } @@ -509,6 +563,18 @@ static int v9fs_request(V9fsProxy *proxy, int type, goto close_error; } break; + case T_LGETXATTR: + case T_LLISTXATTR: + if (!size) { + if (v9fs_receive_status(proxy, reply, &retval) < 0) { + goto close_error; + } + } else { + if (v9fs_receive_response(proxy, type, &retval, response) < 0) { + goto close_error; + } + } + break; } err_out: @@ -884,29 +950,71 @@ static int proxy_statfs(FsContext *s, V9fsPath *fs_path, struct statfs *stbuf) static ssize_t proxy_lgetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name, void *value, size_t size) { - errno = EOPNOTSUPP; - return -1; + int retval; + V9fsString xname; + + v9fs_string_init(&xname); + v9fs_string_sprintf(&xname, "%s", name); + retval = v9fs_request(ctx->private, T_LGETXATTR, value, "dss", size, + fs_path, &xname); + v9fs_string_free(&xname); + if (retval < 0) { + errno = -retval; + } + return retval; } static ssize_t proxy_llistxattr(FsContext *ctx, V9fsPath *fs_path, void *value, size_t size) { - errno = EOPNOTSUPP; - return -1; + int retval; + retval = v9fs_request(ctx->private, T_LLISTXATTR, value, "ds", size, + fs_path); + if (retval < 0) { + errno = -retval; + } + return retval; } static int proxy_lsetxattr(FsContext *ctx, V9fsPath *fs_path, const char *name, void *value, size_t size, int flags) { - errno = EOPNOTSUPP; - return -1; + int retval; + V9fsString xname, xvalue; + + v9fs_string_init(&xname); + v9fs_string_sprintf(&xname, "%s", name); + + v9fs_string_init(&xvalue); + xvalue.size = size; + xvalue.data = g_malloc(size); + memcpy(xvalue.data, value, size); + + retval = v9fs_request(ctx->private, T_LSETXATTR, value, "sssdd", + fs_path, &xname, &xvalue, size, flags); + v9fs_string_free(&xname); + v9fs_string_free(&xvalue); + if (retval < 0) { + errno = -retval; + } + return retval; } static int proxy_lremovexattr(FsContext *ctx, V9fsPath *fs_path, const char *name) { - errno = EOPNOTSUPP; - return -1; + int retval; + V9fsString xname; + + v9fs_string_init(&xname); + v9fs_string_sprintf(&xname, "%s", name); + retval = v9fs_request(ctx->private, T_LREMOVEXATTR, NULL, "ss", + fs_path, &xname); + v9fs_string_free(&xname); + if (retval < 0) { + errno = -retval; + } + return retval; } static int proxy_name_to_path(FsContext *ctx, V9fsPath *dir_path, diff --git a/hw/9pfs/virtio-9p-proxy.h b/hw/9pfs/virtio-9p-proxy.h index bc5ba739bf..7b3b0a9a39 100644 --- a/hw/9pfs/virtio-9p-proxy.h +++ b/hw/9pfs/virtio-9p-proxy.h @@ -54,6 +54,10 @@ enum { T_UTIME, T_RENAME, T_REMOVE, + T_LGETXATTR, + T_LLISTXATTR, + T_LSETXATTR, + T_LREMOVEXATTR, }; typedef struct {