| /* | 
 |  * 9p system.posix* xattr callback | 
 |  * | 
 |  * Copyright IBM, Corp. 2010 | 
 |  * | 
 |  * Authors: | 
 |  * Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com> | 
 |  * | 
 |  * This work is licensed under the terms of the GNU GPL, version 2.  See | 
 |  * the COPYING file in the top-level directory. | 
 |  * | 
 |  */ | 
 |  | 
 | /* | 
 |  * Not so fast! You might want to read the 9p developer docs first: | 
 |  * https://wiki.qemu.org/Documentation/9p | 
 |  */ | 
 |  | 
 | #include "qemu/osdep.h" | 
 | #include "qemu/xattr.h" | 
 | #include "9p.h" | 
 | #include "fsdev/file-op-9p.h" | 
 | #include "9p-xattr.h" | 
 |  | 
 | #define MAP_ACL_ACCESS "user.virtfs.system.posix_acl_access" | 
 | #define MAP_ACL_DEFAULT "user.virtfs.system.posix_acl_default" | 
 | #define ACL_ACCESS "system.posix_acl_access" | 
 | #define ACL_DEFAULT "system.posix_acl_default" | 
 |  | 
 | static ssize_t mp_pacl_getxattr(FsContext *ctx, const char *path, | 
 |                                 const char *name, void *value, size_t size) | 
 | { | 
 |     return local_getxattr_nofollow(ctx, path, MAP_ACL_ACCESS, value, size); | 
 | } | 
 |  | 
 | static ssize_t mp_pacl_listxattr(FsContext *ctx, const char *path, | 
 |                                  char *name, void *value, size_t osize) | 
 | { | 
 |     ssize_t len = sizeof(ACL_ACCESS); | 
 |  | 
 |     if (!value) { | 
 |         return len; | 
 |     } | 
 |  | 
 |     if (osize < len) { | 
 |         errno = ERANGE; | 
 |         return -1; | 
 |     } | 
 |  | 
 |     /* len includes the trailing NUL */ | 
 |     memcpy(value, ACL_ACCESS, len); | 
 |     return 0; | 
 | } | 
 |  | 
 | static int mp_pacl_setxattr(FsContext *ctx, const char *path, const char *name, | 
 |                             void *value, size_t size, int flags) | 
 | { | 
 |     return local_setxattr_nofollow(ctx, path, MAP_ACL_ACCESS, value, size, | 
 |                                    flags); | 
 | } | 
 |  | 
 | static int mp_pacl_removexattr(FsContext *ctx, | 
 |                                const char *path, const char *name) | 
 | { | 
 |     int ret; | 
 |  | 
 |     ret = local_removexattr_nofollow(ctx, path, MAP_ACL_ACCESS); | 
 |     /* | 
 |      * macOS returns ENOATTR (!=ENODATA on macOS), whereas Linux returns | 
 |      * ENODATA (==ENOATTR on Linux), so checking for ENOATTR is fine | 
 |      */ | 
 |     if (ret == -1 && errno == ENOATTR) { | 
 |         /* | 
 |          * We don't get ENODATA error when trying to remove a | 
 |          * posix acl that is not present. So don't throw the error | 
 |          * even in case of mapped security model | 
 |          */ | 
 |         errno = 0; | 
 |         ret = 0; | 
 |     } | 
 |     return ret; | 
 | } | 
 |  | 
 | static ssize_t mp_dacl_getxattr(FsContext *ctx, const char *path, | 
 |                                 const char *name, void *value, size_t size) | 
 | { | 
 |     return local_getxattr_nofollow(ctx, path, MAP_ACL_DEFAULT, value, size); | 
 | } | 
 |  | 
 | static ssize_t mp_dacl_listxattr(FsContext *ctx, const char *path, | 
 |                                  char *name, void *value, size_t osize) | 
 | { | 
 |     ssize_t len = sizeof(ACL_DEFAULT); | 
 |  | 
 |     if (!value) { | 
 |         return len; | 
 |     } | 
 |  | 
 |     if (osize < len) { | 
 |         errno = ERANGE; | 
 |         return -1; | 
 |     } | 
 |  | 
 |     /* len includes the trailing NUL */ | 
 |     memcpy(value, ACL_DEFAULT, len); | 
 |     return 0; | 
 | } | 
 |  | 
 | static int mp_dacl_setxattr(FsContext *ctx, const char *path, const char *name, | 
 |                             void *value, size_t size, int flags) | 
 | { | 
 |     return local_setxattr_nofollow(ctx, path, MAP_ACL_DEFAULT, value, size, | 
 |                                    flags); | 
 | } | 
 |  | 
 | static int mp_dacl_removexattr(FsContext *ctx, | 
 |                                const char *path, const char *name) | 
 | { | 
 |     int ret; | 
 |  | 
 |     ret = local_removexattr_nofollow(ctx, path, MAP_ACL_DEFAULT); | 
 |     /* | 
 |      * macOS returns ENOATTR (!=ENODATA on macOS), whereas Linux returns | 
 |      * ENODATA (==ENOATTR on Linux), so checking for ENOATTR is fine | 
 |      */ | 
 |     if (ret == -1 && errno == ENOATTR) { | 
 |         /* | 
 |          * We don't get ENODATA error when trying to remove a | 
 |          * posix acl that is not present. So don't throw the error | 
 |          * even in case of mapped security model | 
 |          */ | 
 |         errno = 0; | 
 |         ret = 0; | 
 |     } | 
 |     return ret; | 
 | } | 
 |  | 
 |  | 
 | XattrOperations mapped_pacl_xattr = { | 
 |     .name = "system.posix_acl_access", | 
 |     .getxattr = mp_pacl_getxattr, | 
 |     .setxattr = mp_pacl_setxattr, | 
 |     .listxattr = mp_pacl_listxattr, | 
 |     .removexattr = mp_pacl_removexattr, | 
 | }; | 
 |  | 
 | XattrOperations mapped_dacl_xattr = { | 
 |     .name = "system.posix_acl_default", | 
 |     .getxattr = mp_dacl_getxattr, | 
 |     .setxattr = mp_dacl_setxattr, | 
 |     .listxattr = mp_dacl_listxattr, | 
 |     .removexattr = mp_dacl_removexattr, | 
 | }; | 
 |  | 
 | XattrOperations passthrough_acl_xattr = { | 
 |     .name = "system.posix_acl_", | 
 |     .getxattr = pt_getxattr, | 
 |     .setxattr = pt_setxattr, | 
 |     .listxattr = pt_listxattr, | 
 |     .removexattr = pt_removexattr, | 
 | }; | 
 |  | 
 | XattrOperations none_acl_xattr = { | 
 |     .name = "system.posix_acl_", | 
 |     .getxattr = notsup_getxattr, | 
 |     .setxattr = notsup_setxattr, | 
 |     .listxattr = notsup_listxattr, | 
 |     .removexattr = notsup_removexattr, | 
 | }; |