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" 1856ad3e54SGreg Kurz #include "9p-util.h" 1956ad3e54SGreg 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 63*5507904eSGreg Kurz static ssize_t flistxattrat_nofollow(int dirfd, const char *filename, 64*5507904eSGreg Kurz char *list, size_t size) 65*5507904eSGreg Kurz { 66*5507904eSGreg Kurz char *proc_path = g_strdup_printf("/proc/self/fd/%d/%s", dirfd, filename); 67*5507904eSGreg Kurz int ret; 68*5507904eSGreg Kurz 69*5507904eSGreg Kurz ret = llistxattr(proc_path, list, size); 70*5507904eSGreg Kurz g_free(proc_path); 71*5507904eSGreg Kurz return ret; 72*5507904eSGreg Kurz } 73267ae092SWei Liu 74267ae092SWei Liu /* 75267ae092SWei Liu * Get the list and pass to each layer to find out whether 76267ae092SWei Liu * to send the data or not 77267ae092SWei Liu */ 78267ae092SWei Liu ssize_t v9fs_list_xattr(FsContext *ctx, const char *path, 79267ae092SWei Liu void *value, size_t vsize) 80267ae092SWei Liu { 81267ae092SWei Liu ssize_t size = 0; 82267ae092SWei Liu void *ovalue = value; 83267ae092SWei Liu XattrOperations *xops; 84267ae092SWei Liu char *orig_value, *orig_value_start; 85267ae092SWei Liu ssize_t xattr_len, parsed_len = 0, attr_len; 86*5507904eSGreg Kurz char *dirpath, *name; 87*5507904eSGreg Kurz int dirfd; 88267ae092SWei Liu 89267ae092SWei Liu /* Get the actual len */ 90*5507904eSGreg Kurz dirpath = g_path_get_dirname(path); 91*5507904eSGreg Kurz dirfd = local_opendir_nofollow(ctx, dirpath); 92*5507904eSGreg Kurz g_free(dirpath); 93*5507904eSGreg Kurz if (dirfd == -1) { 94*5507904eSGreg Kurz return -1; 95*5507904eSGreg Kurz } 96*5507904eSGreg Kurz 97*5507904eSGreg Kurz name = g_path_get_basename(path); 98*5507904eSGreg Kurz xattr_len = flistxattrat_nofollow(dirfd, name, value, 0); 99267ae092SWei Liu if (xattr_len <= 0) { 100*5507904eSGreg Kurz g_free(name); 101*5507904eSGreg Kurz close_preserve_errno(dirfd); 102267ae092SWei Liu return xattr_len; 103267ae092SWei Liu } 104267ae092SWei Liu 105267ae092SWei Liu /* Now fetch the xattr and find the actual size */ 106267ae092SWei Liu orig_value = g_malloc(xattr_len); 107*5507904eSGreg Kurz xattr_len = flistxattrat_nofollow(dirfd, name, orig_value, xattr_len); 108*5507904eSGreg Kurz g_free(name); 109*5507904eSGreg Kurz close_preserve_errno(dirfd); 110*5507904eSGreg Kurz if (xattr_len < 0) { 111*5507904eSGreg Kurz return -1; 112*5507904eSGreg Kurz } 113267ae092SWei Liu 114267ae092SWei Liu /* store the orig pointer */ 115267ae092SWei Liu orig_value_start = orig_value; 116267ae092SWei Liu while (xattr_len > parsed_len) { 117267ae092SWei Liu xops = get_xattr_operations(ctx->xops, orig_value); 118267ae092SWei Liu if (!xops) { 119267ae092SWei Liu goto next_entry; 120267ae092SWei Liu } 121267ae092SWei Liu 122267ae092SWei Liu if (!value) { 123267ae092SWei Liu size += xops->listxattr(ctx, path, orig_value, value, vsize); 124267ae092SWei Liu } else { 125267ae092SWei Liu size = xops->listxattr(ctx, path, orig_value, value, vsize); 126267ae092SWei Liu if (size < 0) { 127267ae092SWei Liu goto err_out; 128267ae092SWei Liu } 129267ae092SWei Liu value += size; 130267ae092SWei Liu vsize -= size; 131267ae092SWei Liu } 132267ae092SWei Liu next_entry: 133267ae092SWei Liu /* Got the next entry */ 134267ae092SWei Liu attr_len = strlen(orig_value) + 1; 135267ae092SWei Liu parsed_len += attr_len; 136267ae092SWei Liu orig_value += attr_len; 137267ae092SWei Liu } 138267ae092SWei Liu if (value) { 139267ae092SWei Liu size = value - ovalue; 140267ae092SWei Liu } 141267ae092SWei Liu 142267ae092SWei Liu err_out: 143267ae092SWei Liu g_free(orig_value_start); 144267ae092SWei Liu return size; 145267ae092SWei Liu } 146267ae092SWei Liu 147267ae092SWei Liu int v9fs_set_xattr(FsContext *ctx, const char *path, const char *name, 148267ae092SWei Liu void *value, size_t size, int flags) 149267ae092SWei Liu { 150267ae092SWei Liu XattrOperations *xops = get_xattr_operations(ctx->xops, name); 151267ae092SWei Liu if (xops) { 152267ae092SWei Liu return xops->setxattr(ctx, path, name, value, size, flags); 153267ae092SWei Liu } 154267ae092SWei Liu errno = EOPNOTSUPP; 155267ae092SWei Liu return -1; 156267ae092SWei Liu 157267ae092SWei Liu } 158267ae092SWei Liu 159267ae092SWei Liu int v9fs_remove_xattr(FsContext *ctx, 160267ae092SWei Liu const char *path, const char *name) 161267ae092SWei Liu { 162267ae092SWei Liu XattrOperations *xops = get_xattr_operations(ctx->xops, name); 163267ae092SWei Liu if (xops) { 164267ae092SWei Liu return xops->removexattr(ctx, path, name); 165267ae092SWei Liu } 166267ae092SWei Liu errno = EOPNOTSUPP; 167267ae092SWei Liu return -1; 168267ae092SWei Liu 169267ae092SWei Liu } 170267ae092SWei Liu 17156ad3e54SGreg Kurz ssize_t local_getxattr_nofollow(FsContext *ctx, const char *path, 17256ad3e54SGreg Kurz const char *name, void *value, size_t size) 17356ad3e54SGreg Kurz { 17456ad3e54SGreg Kurz char *dirpath = g_path_get_dirname(path); 17556ad3e54SGreg Kurz char *filename = g_path_get_basename(path); 17656ad3e54SGreg Kurz int dirfd; 17756ad3e54SGreg Kurz ssize_t ret = -1; 17856ad3e54SGreg Kurz 17956ad3e54SGreg Kurz dirfd = local_opendir_nofollow(ctx, dirpath); 18056ad3e54SGreg Kurz if (dirfd == -1) { 18156ad3e54SGreg Kurz goto out; 18256ad3e54SGreg Kurz } 18356ad3e54SGreg Kurz 18456ad3e54SGreg Kurz ret = fgetxattrat_nofollow(dirfd, filename, name, value, size); 18556ad3e54SGreg Kurz close_preserve_errno(dirfd); 18656ad3e54SGreg Kurz out: 18756ad3e54SGreg Kurz g_free(dirpath); 18856ad3e54SGreg Kurz g_free(filename); 18956ad3e54SGreg Kurz return ret; 19056ad3e54SGreg Kurz } 19156ad3e54SGreg Kurz 19256fc494bSGreg Kurz ssize_t pt_getxattr(FsContext *ctx, const char *path, const char *name, 19356fc494bSGreg Kurz void *value, size_t size) 19456fc494bSGreg Kurz { 19556ad3e54SGreg Kurz return local_getxattr_nofollow(ctx, path, name, value, size); 19656fc494bSGreg Kurz } 19756fc494bSGreg Kurz 19856fc494bSGreg Kurz int pt_setxattr(FsContext *ctx, const char *path, const char *name, void *value, 19956fc494bSGreg Kurz size_t size, int flags) 20056fc494bSGreg Kurz { 20156fc494bSGreg Kurz char *buffer; 20256fc494bSGreg Kurz int ret; 20356fc494bSGreg Kurz 20456fc494bSGreg Kurz buffer = rpath(ctx, path); 20556fc494bSGreg Kurz ret = lsetxattr(buffer, name, value, size, flags); 20656fc494bSGreg Kurz g_free(buffer); 20756fc494bSGreg Kurz return ret; 20856fc494bSGreg Kurz } 20956fc494bSGreg Kurz 21056fc494bSGreg Kurz int pt_removexattr(FsContext *ctx, const char *path, const char *name) 21156fc494bSGreg Kurz { 21256fc494bSGreg Kurz char *buffer; 21356fc494bSGreg Kurz int ret; 21456fc494bSGreg Kurz 21556fc494bSGreg Kurz buffer = rpath(ctx, path); 21656fc494bSGreg Kurz ret = lremovexattr(path, name); 21756fc494bSGreg Kurz g_free(buffer); 21856fc494bSGreg Kurz return ret; 21956fc494bSGreg Kurz } 22056fc494bSGreg Kurz 22156fc494bSGreg Kurz ssize_t notsup_getxattr(FsContext *ctx, const char *path, const char *name, 22256fc494bSGreg Kurz void *value, size_t size) 22356fc494bSGreg Kurz { 22456fc494bSGreg Kurz errno = ENOTSUP; 22556fc494bSGreg Kurz return -1; 22656fc494bSGreg Kurz } 22756fc494bSGreg Kurz 22856fc494bSGreg Kurz int notsup_setxattr(FsContext *ctx, const char *path, const char *name, 22956fc494bSGreg Kurz void *value, size_t size, int flags) 23056fc494bSGreg Kurz { 23156fc494bSGreg Kurz errno = ENOTSUP; 23256fc494bSGreg Kurz return -1; 23356fc494bSGreg Kurz } 23456fc494bSGreg Kurz 23556fc494bSGreg Kurz ssize_t notsup_listxattr(FsContext *ctx, const char *path, char *name, 23656fc494bSGreg Kurz void *value, size_t size) 23756fc494bSGreg Kurz { 23856fc494bSGreg Kurz return 0; 23956fc494bSGreg Kurz } 24056fc494bSGreg Kurz 24156fc494bSGreg Kurz int notsup_removexattr(FsContext *ctx, const char *path, const char *name) 24256fc494bSGreg Kurz { 24356fc494bSGreg Kurz errno = ENOTSUP; 24456fc494bSGreg Kurz return -1; 24556fc494bSGreg Kurz } 24656fc494bSGreg Kurz 247267ae092SWei Liu XattrOperations *mapped_xattr_ops[] = { 248267ae092SWei Liu &mapped_user_xattr, 249267ae092SWei Liu &mapped_pacl_xattr, 250267ae092SWei Liu &mapped_dacl_xattr, 251267ae092SWei Liu NULL, 252267ae092SWei Liu }; 253267ae092SWei Liu 254267ae092SWei Liu XattrOperations *passthrough_xattr_ops[] = { 255267ae092SWei Liu &passthrough_user_xattr, 256267ae092SWei Liu &passthrough_acl_xattr, 257267ae092SWei Liu NULL, 258267ae092SWei Liu }; 259267ae092SWei Liu 260267ae092SWei Liu /* for .user none model should be same as passthrough */ 261267ae092SWei Liu XattrOperations *none_xattr_ops[] = { 262267ae092SWei Liu &passthrough_user_xattr, 263267ae092SWei Liu &none_acl_xattr, 264267ae092SWei Liu NULL, 265267ae092SWei Liu }; 266