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 /* 64 * Get the list and pass to each layer to find out whether 65 * to send the data or not 66 */ 67 ssize_t v9fs_list_xattr(FsContext *ctx, const char *path, 68 void *value, size_t vsize) 69 { 70 ssize_t size = 0; 71 void *ovalue = value; 72 XattrOperations *xops; 73 char *orig_value, *orig_value_start; 74 ssize_t xattr_len, parsed_len = 0, attr_len; 75 char *dirpath, *name; 76 int dirfd; 77 78 /* Get the actual len */ 79 dirpath = g_path_get_dirname(path); 80 dirfd = local_opendir_nofollow(ctx, dirpath); 81 g_free(dirpath); 82 if (dirfd == -1) { 83 return -1; 84 } 85 86 name = g_path_get_basename(path); 87 xattr_len = flistxattrat_nofollow(dirfd, name, value, 0); 88 if (xattr_len <= 0) { 89 g_free(name); 90 close_preserve_errno(dirfd); 91 return xattr_len; 92 } 93 94 /* Now fetch the xattr and find the actual size */ 95 orig_value = g_malloc(xattr_len); 96 xattr_len = flistxattrat_nofollow(dirfd, name, orig_value, xattr_len); 97 g_free(name); 98 close_preserve_errno(dirfd); 99 if (xattr_len < 0) { 100 g_free(orig_value); 101 return -1; 102 } 103 104 /* store the orig pointer */ 105 orig_value_start = orig_value; 106 while (xattr_len > parsed_len) { 107 xops = get_xattr_operations(ctx->xops, orig_value); 108 if (!xops) { 109 goto next_entry; 110 } 111 112 if (!value) { 113 size += xops->listxattr(ctx, path, orig_value, value, vsize); 114 } else { 115 size = xops->listxattr(ctx, path, orig_value, value, vsize); 116 if (size < 0) { 117 goto err_out; 118 } 119 value += size; 120 vsize -= size; 121 } 122 next_entry: 123 /* Got the next entry */ 124 attr_len = strlen(orig_value) + 1; 125 parsed_len += attr_len; 126 orig_value += attr_len; 127 } 128 if (value) { 129 size = value - ovalue; 130 } 131 132 err_out: 133 g_free(orig_value_start); 134 return size; 135 } 136 137 int v9fs_set_xattr(FsContext *ctx, const char *path, const char *name, 138 void *value, size_t size, int flags) 139 { 140 XattrOperations *xops = get_xattr_operations(ctx->xops, name); 141 if (xops) { 142 return xops->setxattr(ctx, path, name, value, size, flags); 143 } 144 errno = EOPNOTSUPP; 145 return -1; 146 147 } 148 149 int v9fs_remove_xattr(FsContext *ctx, 150 const char *path, const char *name) 151 { 152 XattrOperations *xops = get_xattr_operations(ctx->xops, name); 153 if (xops) { 154 return xops->removexattr(ctx, path, name); 155 } 156 errno = EOPNOTSUPP; 157 return -1; 158 159 } 160 161 ssize_t local_getxattr_nofollow(FsContext *ctx, const char *path, 162 const char *name, void *value, size_t size) 163 { 164 char *dirpath = g_path_get_dirname(path); 165 char *filename = g_path_get_basename(path); 166 int dirfd; 167 ssize_t ret = -1; 168 169 dirfd = local_opendir_nofollow(ctx, dirpath); 170 if (dirfd == -1) { 171 goto out; 172 } 173 174 ret = fgetxattrat_nofollow(dirfd, filename, name, value, size); 175 close_preserve_errno(dirfd); 176 out: 177 g_free(dirpath); 178 g_free(filename); 179 return ret; 180 } 181 182 ssize_t pt_getxattr(FsContext *ctx, const char *path, const char *name, 183 void *value, size_t size) 184 { 185 return local_getxattr_nofollow(ctx, path, name, value, size); 186 } 187 188 ssize_t local_setxattr_nofollow(FsContext *ctx, const char *path, 189 const char *name, void *value, size_t size, 190 int flags) 191 { 192 char *dirpath = g_path_get_dirname(path); 193 char *filename = g_path_get_basename(path); 194 int dirfd; 195 ssize_t ret = -1; 196 197 dirfd = local_opendir_nofollow(ctx, dirpath); 198 if (dirfd == -1) { 199 goto out; 200 } 201 202 ret = fsetxattrat_nofollow(dirfd, filename, name, value, size, flags); 203 close_preserve_errno(dirfd); 204 out: 205 g_free(dirpath); 206 g_free(filename); 207 return ret; 208 } 209 210 int pt_setxattr(FsContext *ctx, const char *path, const char *name, void *value, 211 size_t size, int flags) 212 { 213 return local_setxattr_nofollow(ctx, path, name, value, size, flags); 214 } 215 216 ssize_t local_removexattr_nofollow(FsContext *ctx, const char *path, 217 const char *name) 218 { 219 char *dirpath = g_path_get_dirname(path); 220 char *filename = g_path_get_basename(path); 221 int dirfd; 222 ssize_t ret = -1; 223 224 dirfd = local_opendir_nofollow(ctx, dirpath); 225 if (dirfd == -1) { 226 goto out; 227 } 228 229 ret = fremovexattrat_nofollow(dirfd, filename, name); 230 close_preserve_errno(dirfd); 231 out: 232 g_free(dirpath); 233 g_free(filename); 234 return ret; 235 } 236 237 int pt_removexattr(FsContext *ctx, const char *path, const char *name) 238 { 239 return local_removexattr_nofollow(ctx, path, name); 240 } 241 242 ssize_t notsup_getxattr(FsContext *ctx, const char *path, const char *name, 243 void *value, size_t size) 244 { 245 errno = ENOTSUP; 246 return -1; 247 } 248 249 int notsup_setxattr(FsContext *ctx, const char *path, const char *name, 250 void *value, size_t size, int flags) 251 { 252 errno = ENOTSUP; 253 return -1; 254 } 255 256 ssize_t notsup_listxattr(FsContext *ctx, const char *path, char *name, 257 void *value, size_t size) 258 { 259 return 0; 260 } 261 262 int notsup_removexattr(FsContext *ctx, const char *path, const char *name) 263 { 264 errno = ENOTSUP; 265 return -1; 266 } 267 268 XattrOperations *mapped_xattr_ops[] = { 269 &mapped_user_xattr, 270 &mapped_pacl_xattr, 271 &mapped_dacl_xattr, 272 NULL, 273 }; 274 275 XattrOperations *passthrough_xattr_ops[] = { 276 &passthrough_user_xattr, 277 &passthrough_acl_xattr, 278 NULL, 279 }; 280 281 /* for .user none model should be same as passthrough */ 282 XattrOperations *none_xattr_ops[] = { 283 &passthrough_user_xattr, 284 &none_acl_xattr, 285 NULL, 286 }; 287