qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

9p-xattr.c (7276B)


      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 };