9p-xattr.c (7276B)
1/* 2 * 9p xattr callback 3 * 4 * Copyright IBM, Corp. 2010 5 * 6 * Authors: 7 * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> 8 * 9 * This work is licensed under the terms of the GNU GPL, version 2. See 10 * the COPYING file in the top-level directory. 11 * 12 */ 13 14/* 15 * Not so fast! You might want to read the 9p developer docs first: 16 * https://wiki.qemu.org/Documentation/9p 17 */ 18 19#include "qemu/osdep.h" 20#include "9p.h" 21#include "fsdev/file-op-9p.h" 22#include "9p-xattr.h" 23#include "9p-util.h" 24#include "9p-local.h" 25 26 27static XattrOperations *get_xattr_operations(XattrOperations **h, 28 const char *name) 29{ 30 XattrOperations *xops; 31 for (xops = *(h)++; xops != NULL; xops = *(h)++) { 32 if (!strncmp(name, xops->name, strlen(xops->name))) { 33 return xops; 34 } 35 } 36 return NULL; 37} 38 39ssize_t v9fs_get_xattr(FsContext *ctx, const char *path, 40 const char *name, void *value, size_t size) 41{ 42 XattrOperations *xops = get_xattr_operations(ctx->xops, name); 43 if (xops) { 44 return xops->getxattr(ctx, path, name, value, size); 45 } 46 errno = EOPNOTSUPP; 47 return -1; 48} 49 50ssize_t pt_listxattr(FsContext *ctx, const char *path, 51 char *name, void *value, size_t size) 52{ 53 int name_size = strlen(name) + 1; 54 if (!value) { 55 return name_size; 56 } 57 58 if (size < name_size) { 59 errno = ERANGE; 60 return -1; 61 } 62 63 /* no need for strncpy: name_size is strlen(name)+1 */ 64 memcpy(value, name, name_size); 65 return name_size; 66} 67 68/* 69 * Get the list and pass to each layer to find out whether 70 * to send the data or not 71 */ 72ssize_t v9fs_list_xattr(FsContext *ctx, const char *path, 73 void *value, size_t vsize) 74{ 75 ssize_t size = 0; 76 void *ovalue = value; 77 XattrOperations *xops; 78 char *orig_value, *orig_value_start; 79 ssize_t xattr_len, parsed_len = 0, attr_len; 80 char *dirpath, *name; 81 int dirfd; 82 83 /* Get the actual len */ 84 dirpath = g_path_get_dirname(path); 85 dirfd = local_opendir_nofollow(ctx, dirpath); 86 g_free(dirpath); 87 if (dirfd == -1) { 88 return -1; 89 } 90 91 name = g_path_get_basename(path); 92 xattr_len = flistxattrat_nofollow(dirfd, name, value, 0); 93 if (xattr_len <= 0) { 94 g_free(name); 95 close_preserve_errno(dirfd); 96 return xattr_len; 97 } 98 99 /* Now fetch the xattr and find the actual size */ 100 orig_value = g_malloc(xattr_len); 101 xattr_len = flistxattrat_nofollow(dirfd, name, orig_value, xattr_len); 102 g_free(name); 103 close_preserve_errno(dirfd); 104 if (xattr_len < 0) { 105 g_free(orig_value); 106 return -1; 107 } 108 109 /* store the orig pointer */ 110 orig_value_start = orig_value; 111 while (xattr_len > parsed_len) { 112 xops = get_xattr_operations(ctx->xops, orig_value); 113 if (!xops) { 114 goto next_entry; 115 } 116 117 if (!value) { 118 size += xops->listxattr(ctx, path, orig_value, value, vsize); 119 } else { 120 size = xops->listxattr(ctx, path, orig_value, value, vsize); 121 if (size < 0) { 122 goto err_out; 123 } 124 value += size; 125 vsize -= size; 126 } 127next_entry: 128 /* Got the next entry */ 129 attr_len = strlen(orig_value) + 1; 130 parsed_len += attr_len; 131 orig_value += attr_len; 132 } 133 if (value) { 134 size = value - ovalue; 135 } 136 137err_out: 138 g_free(orig_value_start); 139 return size; 140} 141 142int v9fs_set_xattr(FsContext *ctx, const char *path, const char *name, 143 void *value, size_t size, int flags) 144{ 145 XattrOperations *xops = get_xattr_operations(ctx->xops, name); 146 if (xops) { 147 return xops->setxattr(ctx, path, name, value, size, flags); 148 } 149 errno = EOPNOTSUPP; 150 return -1; 151 152} 153 154int v9fs_remove_xattr(FsContext *ctx, 155 const char *path, const char *name) 156{ 157 XattrOperations *xops = get_xattr_operations(ctx->xops, name); 158 if (xops) { 159 return xops->removexattr(ctx, path, name); 160 } 161 errno = EOPNOTSUPP; 162 return -1; 163 164} 165 166ssize_t local_getxattr_nofollow(FsContext *ctx, const char *path, 167 const char *name, void *value, size_t size) 168{ 169 char *dirpath = g_path_get_dirname(path); 170 char *filename = g_path_get_basename(path); 171 int dirfd; 172 ssize_t ret = -1; 173 174 dirfd = local_opendir_nofollow(ctx, dirpath); 175 if (dirfd == -1) { 176 goto out; 177 } 178 179 ret = fgetxattrat_nofollow(dirfd, filename, name, value, size); 180 close_preserve_errno(dirfd); 181out: 182 g_free(dirpath); 183 g_free(filename); 184 return ret; 185} 186 187ssize_t pt_getxattr(FsContext *ctx, const char *path, const char *name, 188 void *value, size_t size) 189{ 190 return local_getxattr_nofollow(ctx, path, name, value, size); 191} 192 193ssize_t local_setxattr_nofollow(FsContext *ctx, const char *path, 194 const char *name, void *value, size_t size, 195 int flags) 196{ 197 char *dirpath = g_path_get_dirname(path); 198 char *filename = g_path_get_basename(path); 199 int dirfd; 200 ssize_t ret = -1; 201 202 dirfd = local_opendir_nofollow(ctx, dirpath); 203 if (dirfd == -1) { 204 goto out; 205 } 206 207 ret = fsetxattrat_nofollow(dirfd, filename, name, value, size, flags); 208 close_preserve_errno(dirfd); 209out: 210 g_free(dirpath); 211 g_free(filename); 212 return ret; 213} 214 215int pt_setxattr(FsContext *ctx, const char *path, const char *name, void *value, 216 size_t size, int flags) 217{ 218 return local_setxattr_nofollow(ctx, path, name, value, size, flags); 219} 220 221ssize_t local_removexattr_nofollow(FsContext *ctx, const char *path, 222 const char *name) 223{ 224 char *dirpath = g_path_get_dirname(path); 225 char *filename = g_path_get_basename(path); 226 int dirfd; 227 ssize_t ret = -1; 228 229 dirfd = local_opendir_nofollow(ctx, dirpath); 230 if (dirfd == -1) { 231 goto out; 232 } 233 234 ret = fremovexattrat_nofollow(dirfd, filename, name); 235 close_preserve_errno(dirfd); 236out: 237 g_free(dirpath); 238 g_free(filename); 239 return ret; 240} 241 242int pt_removexattr(FsContext *ctx, const char *path, const char *name) 243{ 244 return local_removexattr_nofollow(ctx, path, name); 245} 246 247ssize_t notsup_getxattr(FsContext *ctx, const char *path, const char *name, 248 void *value, size_t size) 249{ 250 errno = ENOTSUP; 251 return -1; 252} 253 254int notsup_setxattr(FsContext *ctx, const char *path, const char *name, 255 void *value, size_t size, int flags) 256{ 257 errno = ENOTSUP; 258 return -1; 259} 260 261ssize_t notsup_listxattr(FsContext *ctx, const char *path, char *name, 262 void *value, size_t size) 263{ 264 return 0; 265} 266 267int notsup_removexattr(FsContext *ctx, const char *path, const char *name) 268{ 269 errno = ENOTSUP; 270 return -1; 271} 272 273XattrOperations *mapped_xattr_ops[] = { 274 &mapped_user_xattr, 275 &mapped_pacl_xattr, 276 &mapped_dacl_xattr, 277 NULL, 278}; 279 280XattrOperations *passthrough_xattr_ops[] = { 281 &passthrough_user_xattr, 282 &passthrough_acl_xattr, 283 NULL, 284}; 285 286/* for .user none model should be same as passthrough */ 287XattrOperations *none_xattr_ops[] = { 288 &passthrough_user_xattr, 289 &none_acl_xattr, 290 NULL, 291};