/* * Virtio 9p xattr callback * * Copyright IBM, Corp. 2010 * * Authors: * Aneesh Kumar K.V * * This work is licensed under the terms of the GNU GPL, version 2. See * the COPYING file in the top-level directory. * */ #include "hw/virtio.h" #include "virtio-9p.h" #include "fsdev/file-op-9p.h" #include "virtio-9p-xattr.h" static XattrOperations *get_xattr_operations(XattrOperations **h, const char *name) { XattrOperations *xops; for (xops = *(h)++; xops != NULL; xops = *(h)++) { if (!strncmp(name, xops->name, strlen(xops->name))) { return xops; } } return NULL; } ssize_t v9fs_get_xattr(FsContext *ctx, const char *path, const char *name, void *value, size_t size) { XattrOperations *xops = get_xattr_operations(ctx->xops, name); if (xops) { return xops->getxattr(ctx, path, name, value, size); } errno = -EOPNOTSUPP; return -1; } ssize_t pt_listxattr(FsContext *ctx, const char *path, char *name, void *value, size_t size) { int name_size = strlen(name) + 1; if (!value) { return name_size; } if (size < name_size) { errno = ERANGE; return -1; } strncpy(value, name, name_size); return name_size; } /* * Get the list and pass to each layer to find out whether * to send the data or not */ ssize_t v9fs_list_xattr(FsContext *ctx, const char *path, void *value, size_t vsize) { ssize_t size = 0; char buffer[PATH_MAX]; void *ovalue = value; XattrOperations *xops; char *orig_value, *orig_value_start; ssize_t xattr_len, parsed_len = 0, attr_len; /* Get the actual len */ xattr_len = llistxattr(rpath(ctx, path, buffer), value, 0); if (xattr_len <= 0) { return xattr_len; } /* Now fetch the xattr and find the actual size */ orig_value = qemu_malloc(xattr_len); xattr_len = llistxattr(rpath(ctx, path, buffer), orig_value, xattr_len); /* store the orig pointer */ orig_value_start = orig_value; while (xattr_len > parsed_len) { xops = get_xattr_operations(ctx->xops, orig_value); if (!xops) { goto next_entry; } if (!value) { size += xops->listxattr(ctx, path, orig_value, value, vsize); } else { size = xops->listxattr(ctx, path, orig_value, value, vsize); if (size < 0) { goto err_out; } value += size; vsize -= size; } next_entry: /* Got the next entry */ attr_len = strlen(orig_value) + 1; parsed_len += attr_len; orig_value += attr_len; } if (value) { size = value - ovalue; } err_out: qemu_free(orig_value_start); return size; } int v9fs_set_xattr(FsContext *ctx, const char *path, const char *name, void *value, size_t size, int flags) { XattrOperations *xops = get_xattr_operations(ctx->xops, name); if (xops) { return xops->setxattr(ctx, path, name, value, size, flags); } errno = -EOPNOTSUPP; return -1; } int v9fs_remove_xattr(FsContext *ctx, const char *path, const char *name) { XattrOperations *xops = get_xattr_operations(ctx->xops, name); if (xops) { return xops->removexattr(ctx, path, name); } errno = -EOPNOTSUPP; return -1; } XattrOperations *mapped_xattr_ops[] = { &mapped_user_xattr, &mapped_pacl_xattr, &mapped_dacl_xattr, NULL, }; XattrOperations *passthrough_xattr_ops[] = { &passthrough_user_xattr, &passthrough_acl_xattr, NULL, }; /* for .user none model should be same as passthrough */ XattrOperations *none_xattr_ops[] = { &passthrough_user_xattr, &none_acl_xattr, NULL, };