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/*
  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};
 292