qemu/hw/9pfs/9p-xattr.c
<<
>>
Prefs
   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
  22static 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
  34ssize_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
  45ssize_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
  63static 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 */
  78ssize_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        }
 133next_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
 143err_out:
 144    g_free(orig_value_start);
 145    return size;
 146}
 147
 148int 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
 160int 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
 172ssize_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);
 187out:
 188    g_free(dirpath);
 189    g_free(filename);
 190    return ret;
 191}
 192
 193ssize_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
 199int 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
 210ssize_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);
 226out:
 227    g_free(dirpath);
 228    g_free(filename);
 229    return ret;
 230}
 231
 232int 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
 238static 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
 249ssize_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);
 264out:
 265    g_free(dirpath);
 266    g_free(filename);
 267    return ret;
 268}
 269
 270int pt_removexattr(FsContext *ctx, const char *path, const char *name)
 271{
 272    return local_removexattr_nofollow(ctx, path, name);
 273}
 274
 275ssize_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
 282int 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
 289ssize_t notsup_listxattr(FsContext *ctx, const char *path, char *name,
 290                         void *value, size_t size)
 291{
 292    return 0;
 293}
 294
 295int notsup_removexattr(FsContext *ctx, const char *path, const char *name)
 296{
 297    errno = ENOTSUP;
 298    return -1;
 299}
 300
 301XattrOperations *mapped_xattr_ops[] = {
 302    &mapped_user_xattr,
 303    &mapped_pacl_xattr,
 304    &mapped_dacl_xattr,
 305    NULL,
 306};
 307
 308XattrOperations *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 */
 315XattrOperations *none_xattr_ops[] = {
 316    &passthrough_user_xattr,
 317    &none_acl_xattr,
 318    NULL,
 319};
 320