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 27 static 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 39 ssize_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 50 ssize_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 */ 72 ssize_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 } 127 next_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 137 err_out: 138 g_free(orig_value_start); 139 return size; 140 } 141 142 int 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 154 int 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 166 ssize_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); 181 out: 182 g_free(dirpath); 183 g_free(filename); 184 return ret; 185 } 186 187 ssize_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 193 ssize_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); 209 out: 210 g_free(dirpath); 211 g_free(filename); 212 return ret; 213 } 214 215 int 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 221 ssize_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); 236 out: 237 g_free(dirpath); 238 g_free(filename); 239 return ret; 240 } 241 242 int pt_removexattr(FsContext *ctx, const char *path, const char *name) 243 { 244 return local_removexattr_nofollow(ctx, path, name); 245 } 246 247 ssize_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 254 int 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 261 ssize_t notsup_listxattr(FsContext *ctx, const char *path, char *name, 262 void *value, size_t size) 263 { 264 return 0; 265 } 266 267 int notsup_removexattr(FsContext *ctx, const char *path, const char *name) 268 { 269 errno = ENOTSUP; 270 return -1; 271 } 272 273 XattrOperations *mapped_xattr_ops[] = { 274 &mapped_user_xattr, 275 &mapped_pacl_xattr, 276 &mapped_dacl_xattr, 277 NULL, 278 }; 279 280 XattrOperations *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 */ 287 XattrOperations *none_xattr_ops[] = { 288 &passthrough_user_xattr, 289 &none_acl_xattr, 290 NULL, 291 }; 292