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 635507904eSGreg Kurz static ssize_t flistxattrat_nofollow(int dirfd, const char *filename, 645507904eSGreg Kurz char *list, size_t size) 655507904eSGreg Kurz { 665507904eSGreg Kurz char *proc_path = g_strdup_printf("/proc/self/fd/%d/%s", dirfd, filename); 675507904eSGreg Kurz int ret; 685507904eSGreg Kurz 695507904eSGreg Kurz ret = llistxattr(proc_path, list, size); 705507904eSGreg Kurz g_free(proc_path); 715507904eSGreg Kurz return ret; 725507904eSGreg 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; 865507904eSGreg Kurz char *dirpath, *name; 875507904eSGreg Kurz int dirfd; 88267ae092SWei Liu 89267ae092SWei Liu /* Get the actual len */ 905507904eSGreg Kurz dirpath = g_path_get_dirname(path); 915507904eSGreg Kurz dirfd = local_opendir_nofollow(ctx, dirpath); 925507904eSGreg Kurz g_free(dirpath); 935507904eSGreg Kurz if (dirfd == -1) { 945507904eSGreg Kurz return -1; 955507904eSGreg Kurz } 965507904eSGreg Kurz 975507904eSGreg Kurz name = g_path_get_basename(path); 985507904eSGreg Kurz xattr_len = flistxattrat_nofollow(dirfd, name, value, 0); 99267ae092SWei Liu if (xattr_len <= 0) { 1005507904eSGreg Kurz g_free(name); 1015507904eSGreg 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); 1075507904eSGreg Kurz xattr_len = flistxattrat_nofollow(dirfd, name, orig_value, xattr_len); 1085507904eSGreg Kurz g_free(name); 1095507904eSGreg Kurz close_preserve_errno(dirfd); 1105507904eSGreg Kurz if (xattr_len < 0) { 1115507904eSGreg Kurz return -1; 1125507904eSGreg 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 198*3e36aba7SGreg Kurz int fsetxattrat_nofollow(int dirfd, const char *filename, const char *name, 199*3e36aba7SGreg Kurz void *value, size_t size, int flags) 200*3e36aba7SGreg Kurz { 201*3e36aba7SGreg Kurz char *proc_path = g_strdup_printf("/proc/self/fd/%d/%s", dirfd, filename); 202*3e36aba7SGreg Kurz int ret; 203*3e36aba7SGreg Kurz 204*3e36aba7SGreg Kurz ret = lsetxattr(proc_path, name, value, size, flags); 205*3e36aba7SGreg Kurz g_free(proc_path); 206*3e36aba7SGreg Kurz return ret; 207*3e36aba7SGreg Kurz } 208*3e36aba7SGreg Kurz 209*3e36aba7SGreg Kurz ssize_t local_setxattr_nofollow(FsContext *ctx, const char *path, 210*3e36aba7SGreg Kurz const char *name, void *value, size_t size, 211*3e36aba7SGreg Kurz int flags) 212*3e36aba7SGreg Kurz { 213*3e36aba7SGreg Kurz char *dirpath = g_path_get_dirname(path); 214*3e36aba7SGreg Kurz char *filename = g_path_get_basename(path); 215*3e36aba7SGreg Kurz int dirfd; 216*3e36aba7SGreg Kurz ssize_t ret = -1; 217*3e36aba7SGreg Kurz 218*3e36aba7SGreg Kurz dirfd = local_opendir_nofollow(ctx, dirpath); 219*3e36aba7SGreg Kurz if (dirfd == -1) { 220*3e36aba7SGreg Kurz goto out; 221*3e36aba7SGreg Kurz } 222*3e36aba7SGreg Kurz 223*3e36aba7SGreg Kurz ret = fsetxattrat_nofollow(dirfd, filename, name, value, size, flags); 224*3e36aba7SGreg Kurz close_preserve_errno(dirfd); 225*3e36aba7SGreg Kurz out: 226*3e36aba7SGreg Kurz g_free(dirpath); 227*3e36aba7SGreg Kurz g_free(filename); 228*3e36aba7SGreg Kurz return ret; 229*3e36aba7SGreg Kurz } 230*3e36aba7SGreg Kurz 23156fc494bSGreg Kurz int pt_setxattr(FsContext *ctx, const char *path, const char *name, void *value, 23256fc494bSGreg Kurz size_t size, int flags) 23356fc494bSGreg Kurz { 234*3e36aba7SGreg Kurz return local_setxattr_nofollow(ctx, path, name, value, size, flags); 23556fc494bSGreg Kurz } 23656fc494bSGreg Kurz 23756fc494bSGreg Kurz int pt_removexattr(FsContext *ctx, const char *path, const char *name) 23856fc494bSGreg Kurz { 23956fc494bSGreg Kurz char *buffer; 24056fc494bSGreg Kurz int ret; 24156fc494bSGreg Kurz 24256fc494bSGreg Kurz buffer = rpath(ctx, path); 24356fc494bSGreg Kurz ret = lremovexattr(path, name); 24456fc494bSGreg Kurz g_free(buffer); 24556fc494bSGreg Kurz return ret; 24656fc494bSGreg Kurz } 24756fc494bSGreg Kurz 24856fc494bSGreg Kurz ssize_t notsup_getxattr(FsContext *ctx, const char *path, const char *name, 24956fc494bSGreg Kurz void *value, size_t size) 25056fc494bSGreg Kurz { 25156fc494bSGreg Kurz errno = ENOTSUP; 25256fc494bSGreg Kurz return -1; 25356fc494bSGreg Kurz } 25456fc494bSGreg Kurz 25556fc494bSGreg Kurz int notsup_setxattr(FsContext *ctx, const char *path, const char *name, 25656fc494bSGreg Kurz void *value, size_t size, int flags) 25756fc494bSGreg Kurz { 25856fc494bSGreg Kurz errno = ENOTSUP; 25956fc494bSGreg Kurz return -1; 26056fc494bSGreg Kurz } 26156fc494bSGreg Kurz 26256fc494bSGreg Kurz ssize_t notsup_listxattr(FsContext *ctx, const char *path, char *name, 26356fc494bSGreg Kurz void *value, size_t size) 26456fc494bSGreg Kurz { 26556fc494bSGreg Kurz return 0; 26656fc494bSGreg Kurz } 26756fc494bSGreg Kurz 26856fc494bSGreg Kurz int notsup_removexattr(FsContext *ctx, const char *path, const char *name) 26956fc494bSGreg Kurz { 27056fc494bSGreg Kurz errno = ENOTSUP; 27156fc494bSGreg Kurz return -1; 27256fc494bSGreg Kurz } 27356fc494bSGreg Kurz 274267ae092SWei Liu XattrOperations *mapped_xattr_ops[] = { 275267ae092SWei Liu &mapped_user_xattr, 276267ae092SWei Liu &mapped_pacl_xattr, 277267ae092SWei Liu &mapped_dacl_xattr, 278267ae092SWei Liu NULL, 279267ae092SWei Liu }; 280267ae092SWei Liu 281267ae092SWei Liu XattrOperations *passthrough_xattr_ops[] = { 282267ae092SWei Liu &passthrough_user_xattr, 283267ae092SWei Liu &passthrough_acl_xattr, 284267ae092SWei Liu NULL, 285267ae092SWei Liu }; 286267ae092SWei Liu 287267ae092SWei Liu /* for .user none model should be same as passthrough */ 288267ae092SWei Liu XattrOperations *none_xattr_ops[] = { 289267ae092SWei Liu &passthrough_user_xattr, 290267ae092SWei Liu &none_acl_xattr, 291267ae092SWei Liu NULL, 292267ae092SWei Liu }; 293