1267ae092SWei Liu /* 2267ae092SWei Liu * 9p xattr callback 3267ae092SWei Liu * 4267ae092SWei Liu * Copyright IBM, Corp. 2010 5267ae092SWei Liu * 6267ae092SWei Liu * Authors: 7267ae092SWei Liu * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> 8267ae092SWei Liu * 9267ae092SWei Liu * This work is licensed under the terms of the GNU GPL, version 2. See 10267ae092SWei Liu * the COPYING file in the top-level directory. 11267ae092SWei Liu * 12267ae092SWei Liu */ 13267ae092SWei Liu 14fbc04127SPeter Maydell #include "qemu/osdep.h" 15ebe74f8bSWei Liu #include "9p.h" 16267ae092SWei Liu #include "fsdev/file-op-9p.h" 17267ae092SWei Liu #include "9p-xattr.h" 18*56ad3e54SGreg Kurz #include "9p-util.h" 19*56ad3e54SGreg Kurz #include "9p-local.h" 20267ae092SWei Liu 21267ae092SWei Liu 22267ae092SWei Liu static XattrOperations *get_xattr_operations(XattrOperations **h, 23267ae092SWei Liu const char *name) 24267ae092SWei Liu { 25267ae092SWei Liu XattrOperations *xops; 26267ae092SWei Liu for (xops = *(h)++; xops != NULL; xops = *(h)++) { 27267ae092SWei Liu if (!strncmp(name, xops->name, strlen(xops->name))) { 28267ae092SWei Liu return xops; 29267ae092SWei Liu } 30267ae092SWei Liu } 31267ae092SWei Liu return NULL; 32267ae092SWei Liu } 33267ae092SWei Liu 34267ae092SWei Liu ssize_t v9fs_get_xattr(FsContext *ctx, const char *path, 35267ae092SWei Liu const char *name, void *value, size_t size) 36267ae092SWei Liu { 37267ae092SWei Liu XattrOperations *xops = get_xattr_operations(ctx->xops, name); 38267ae092SWei Liu if (xops) { 39267ae092SWei Liu return xops->getxattr(ctx, path, name, value, size); 40267ae092SWei Liu } 41267ae092SWei Liu errno = EOPNOTSUPP; 42267ae092SWei Liu return -1; 43267ae092SWei Liu } 44267ae092SWei Liu 45267ae092SWei Liu ssize_t pt_listxattr(FsContext *ctx, const char *path, 46267ae092SWei Liu char *name, void *value, size_t size) 47267ae092SWei Liu { 48267ae092SWei Liu int name_size = strlen(name) + 1; 49267ae092SWei Liu if (!value) { 50267ae092SWei Liu return name_size; 51267ae092SWei Liu } 52267ae092SWei Liu 53267ae092SWei Liu if (size < name_size) { 54267ae092SWei Liu errno = ERANGE; 55267ae092SWei Liu return -1; 56267ae092SWei Liu } 57267ae092SWei Liu 58267ae092SWei Liu /* no need for strncpy: name_size is strlen(name)+1 */ 59267ae092SWei Liu memcpy(value, name, name_size); 60267ae092SWei Liu return name_size; 61267ae092SWei Liu } 62267ae092SWei Liu 63267ae092SWei Liu 64267ae092SWei Liu /* 65267ae092SWei Liu * Get the list and pass to each layer to find out whether 66267ae092SWei Liu * to send the data or not 67267ae092SWei Liu */ 68267ae092SWei Liu ssize_t v9fs_list_xattr(FsContext *ctx, const char *path, 69267ae092SWei Liu void *value, size_t vsize) 70267ae092SWei Liu { 71267ae092SWei Liu ssize_t size = 0; 72267ae092SWei Liu char *buffer; 73267ae092SWei Liu void *ovalue = value; 74267ae092SWei Liu XattrOperations *xops; 75267ae092SWei Liu char *orig_value, *orig_value_start; 76267ae092SWei Liu ssize_t xattr_len, parsed_len = 0, attr_len; 77267ae092SWei Liu 78267ae092SWei Liu /* Get the actual len */ 79267ae092SWei Liu buffer = rpath(ctx, path); 80267ae092SWei Liu xattr_len = llistxattr(buffer, value, 0); 81267ae092SWei Liu if (xattr_len <= 0) { 82267ae092SWei Liu g_free(buffer); 83267ae092SWei Liu return xattr_len; 84267ae092SWei Liu } 85267ae092SWei Liu 86267ae092SWei Liu /* Now fetch the xattr and find the actual size */ 87267ae092SWei Liu orig_value = g_malloc(xattr_len); 88267ae092SWei Liu xattr_len = llistxattr(buffer, orig_value, xattr_len); 89267ae092SWei Liu g_free(buffer); 90267ae092SWei Liu 91267ae092SWei Liu /* store the orig pointer */ 92267ae092SWei Liu orig_value_start = orig_value; 93267ae092SWei Liu while (xattr_len > parsed_len) { 94267ae092SWei Liu xops = get_xattr_operations(ctx->xops, orig_value); 95267ae092SWei Liu if (!xops) { 96267ae092SWei Liu goto next_entry; 97267ae092SWei Liu } 98267ae092SWei Liu 99267ae092SWei Liu if (!value) { 100267ae092SWei Liu size += xops->listxattr(ctx, path, orig_value, value, vsize); 101267ae092SWei Liu } else { 102267ae092SWei Liu size = xops->listxattr(ctx, path, orig_value, value, vsize); 103267ae092SWei Liu if (size < 0) { 104267ae092SWei Liu goto err_out; 105267ae092SWei Liu } 106267ae092SWei Liu value += size; 107267ae092SWei Liu vsize -= size; 108267ae092SWei Liu } 109267ae092SWei Liu next_entry: 110267ae092SWei Liu /* Got the next entry */ 111267ae092SWei Liu attr_len = strlen(orig_value) + 1; 112267ae092SWei Liu parsed_len += attr_len; 113267ae092SWei Liu orig_value += attr_len; 114267ae092SWei Liu } 115267ae092SWei Liu if (value) { 116267ae092SWei Liu size = value - ovalue; 117267ae092SWei Liu } 118267ae092SWei Liu 119267ae092SWei Liu err_out: 120267ae092SWei Liu g_free(orig_value_start); 121267ae092SWei Liu return size; 122267ae092SWei Liu } 123267ae092SWei Liu 124267ae092SWei Liu int v9fs_set_xattr(FsContext *ctx, const char *path, const char *name, 125267ae092SWei Liu void *value, size_t size, int flags) 126267ae092SWei Liu { 127267ae092SWei Liu XattrOperations *xops = get_xattr_operations(ctx->xops, name); 128267ae092SWei Liu if (xops) { 129267ae092SWei Liu return xops->setxattr(ctx, path, name, value, size, flags); 130267ae092SWei Liu } 131267ae092SWei Liu errno = EOPNOTSUPP; 132267ae092SWei Liu return -1; 133267ae092SWei Liu 134267ae092SWei Liu } 135267ae092SWei Liu 136267ae092SWei Liu int v9fs_remove_xattr(FsContext *ctx, 137267ae092SWei Liu const char *path, const char *name) 138267ae092SWei Liu { 139267ae092SWei Liu XattrOperations *xops = get_xattr_operations(ctx->xops, name); 140267ae092SWei Liu if (xops) { 141267ae092SWei Liu return xops->removexattr(ctx, path, name); 142267ae092SWei Liu } 143267ae092SWei Liu errno = EOPNOTSUPP; 144267ae092SWei Liu return -1; 145267ae092SWei Liu 146267ae092SWei Liu } 147267ae092SWei Liu 148*56ad3e54SGreg Kurz ssize_t local_getxattr_nofollow(FsContext *ctx, const char *path, 149*56ad3e54SGreg Kurz const char *name, void *value, size_t size) 150*56ad3e54SGreg Kurz { 151*56ad3e54SGreg Kurz char *dirpath = g_path_get_dirname(path); 152*56ad3e54SGreg Kurz char *filename = g_path_get_basename(path); 153*56ad3e54SGreg Kurz int dirfd; 154*56ad3e54SGreg Kurz ssize_t ret = -1; 155*56ad3e54SGreg Kurz 156*56ad3e54SGreg Kurz dirfd = local_opendir_nofollow(ctx, dirpath); 157*56ad3e54SGreg Kurz if (dirfd == -1) { 158*56ad3e54SGreg Kurz goto out; 159*56ad3e54SGreg Kurz } 160*56ad3e54SGreg Kurz 161*56ad3e54SGreg Kurz ret = fgetxattrat_nofollow(dirfd, filename, name, value, size); 162*56ad3e54SGreg Kurz close_preserve_errno(dirfd); 163*56ad3e54SGreg Kurz out: 164*56ad3e54SGreg Kurz g_free(dirpath); 165*56ad3e54SGreg Kurz g_free(filename); 166*56ad3e54SGreg Kurz return ret; 167*56ad3e54SGreg Kurz } 168*56ad3e54SGreg Kurz 16956fc494bSGreg Kurz ssize_t pt_getxattr(FsContext *ctx, const char *path, const char *name, 17056fc494bSGreg Kurz void *value, size_t size) 17156fc494bSGreg Kurz { 172*56ad3e54SGreg Kurz return local_getxattr_nofollow(ctx, path, name, value, size); 17356fc494bSGreg Kurz } 17456fc494bSGreg Kurz 17556fc494bSGreg Kurz int pt_setxattr(FsContext *ctx, const char *path, const char *name, void *value, 17656fc494bSGreg Kurz size_t size, int flags) 17756fc494bSGreg Kurz { 17856fc494bSGreg Kurz char *buffer; 17956fc494bSGreg Kurz int ret; 18056fc494bSGreg Kurz 18156fc494bSGreg Kurz buffer = rpath(ctx, path); 18256fc494bSGreg Kurz ret = lsetxattr(buffer, name, value, size, flags); 18356fc494bSGreg Kurz g_free(buffer); 18456fc494bSGreg Kurz return ret; 18556fc494bSGreg Kurz } 18656fc494bSGreg Kurz 18756fc494bSGreg Kurz int pt_removexattr(FsContext *ctx, const char *path, const char *name) 18856fc494bSGreg Kurz { 18956fc494bSGreg Kurz char *buffer; 19056fc494bSGreg Kurz int ret; 19156fc494bSGreg Kurz 19256fc494bSGreg Kurz buffer = rpath(ctx, path); 19356fc494bSGreg Kurz ret = lremovexattr(path, name); 19456fc494bSGreg Kurz g_free(buffer); 19556fc494bSGreg Kurz return ret; 19656fc494bSGreg Kurz } 19756fc494bSGreg Kurz 19856fc494bSGreg Kurz ssize_t notsup_getxattr(FsContext *ctx, const char *path, const char *name, 19956fc494bSGreg Kurz void *value, size_t size) 20056fc494bSGreg Kurz { 20156fc494bSGreg Kurz errno = ENOTSUP; 20256fc494bSGreg Kurz return -1; 20356fc494bSGreg Kurz } 20456fc494bSGreg Kurz 20556fc494bSGreg Kurz int notsup_setxattr(FsContext *ctx, const char *path, const char *name, 20656fc494bSGreg Kurz void *value, size_t size, int flags) 20756fc494bSGreg Kurz { 20856fc494bSGreg Kurz errno = ENOTSUP; 20956fc494bSGreg Kurz return -1; 21056fc494bSGreg Kurz } 21156fc494bSGreg Kurz 21256fc494bSGreg Kurz ssize_t notsup_listxattr(FsContext *ctx, const char *path, char *name, 21356fc494bSGreg Kurz void *value, size_t size) 21456fc494bSGreg Kurz { 21556fc494bSGreg Kurz return 0; 21656fc494bSGreg Kurz } 21756fc494bSGreg Kurz 21856fc494bSGreg Kurz int notsup_removexattr(FsContext *ctx, const char *path, const char *name) 21956fc494bSGreg Kurz { 22056fc494bSGreg Kurz errno = ENOTSUP; 22156fc494bSGreg Kurz return -1; 22256fc494bSGreg Kurz } 22356fc494bSGreg Kurz 224267ae092SWei Liu XattrOperations *mapped_xattr_ops[] = { 225267ae092SWei Liu &mapped_user_xattr, 226267ae092SWei Liu &mapped_pacl_xattr, 227267ae092SWei Liu &mapped_dacl_xattr, 228267ae092SWei Liu NULL, 229267ae092SWei Liu }; 230267ae092SWei Liu 231267ae092SWei Liu XattrOperations *passthrough_xattr_ops[] = { 232267ae092SWei Liu &passthrough_user_xattr, 233267ae092SWei Liu &passthrough_acl_xattr, 234267ae092SWei Liu NULL, 235267ae092SWei Liu }; 236267ae092SWei Liu 237267ae092SWei Liu /* for .user none model should be same as passthrough */ 238267ae092SWei Liu XattrOperations *none_xattr_ops[] = { 239267ae092SWei Liu &passthrough_user_xattr, 240267ae092SWei Liu &none_acl_xattr, 241267ae092SWei Liu NULL, 242267ae092SWei Liu }; 243