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