linux/fs/hfsplus/posix_acl.c
<<
>>
Prefs
   1/*
   2 * linux/fs/hfsplus/posix_acl.c
   3 *
   4 * Vyacheslav Dubeyko <slava@dubeyko.com>
   5 *
   6 * Handler for Posix Access Control Lists (ACLs) support.
   7 */
   8
   9#include "hfsplus_fs.h"
  10#include "xattr.h"
  11#include "acl.h"
  12
  13struct posix_acl *hfsplus_get_posix_acl(struct inode *inode, int type)
  14{
  15        struct posix_acl *acl;
  16        char *xattr_name;
  17        char *value = NULL;
  18        ssize_t size;
  19
  20        acl = get_cached_acl(inode, type);
  21        if (acl != ACL_NOT_CACHED)
  22                return acl;
  23
  24        switch (type) {
  25        case ACL_TYPE_ACCESS:
  26                xattr_name = POSIX_ACL_XATTR_ACCESS;
  27                break;
  28        case ACL_TYPE_DEFAULT:
  29                xattr_name = POSIX_ACL_XATTR_DEFAULT;
  30                break;
  31        default:
  32                return ERR_PTR(-EINVAL);
  33        }
  34
  35        size = __hfsplus_getxattr(inode, xattr_name, NULL, 0);
  36
  37        if (size > 0) {
  38                value = (char *)hfsplus_alloc_attr_entry();
  39                if (unlikely(!value))
  40                        return ERR_PTR(-ENOMEM);
  41                size = __hfsplus_getxattr(inode, xattr_name, value, size);
  42        }
  43
  44        if (size > 0)
  45                acl = posix_acl_from_xattr(&init_user_ns, value, size);
  46        else if (size == -ENODATA)
  47                acl = NULL;
  48        else
  49                acl = ERR_PTR(size);
  50
  51        hfsplus_destroy_attr_entry((hfsplus_attr_entry *)value);
  52
  53        if (!IS_ERR(acl))
  54                set_cached_acl(inode, type, acl);
  55
  56        return acl;
  57}
  58
  59static int hfsplus_set_posix_acl(struct inode *inode,
  60                                        int type,
  61                                        struct posix_acl *acl)
  62{
  63        int err;
  64        char *xattr_name;
  65        size_t size = 0;
  66        char *value = NULL;
  67
  68        if (S_ISLNK(inode->i_mode))
  69                return -EOPNOTSUPP;
  70
  71        switch (type) {
  72        case ACL_TYPE_ACCESS:
  73                xattr_name = POSIX_ACL_XATTR_ACCESS;
  74                if (acl) {
  75                        err = posix_acl_equiv_mode(acl, &inode->i_mode);
  76                        if (err < 0)
  77                                return err;
  78                }
  79                err = 0;
  80                break;
  81
  82        case ACL_TYPE_DEFAULT:
  83                xattr_name = POSIX_ACL_XATTR_DEFAULT;
  84                if (!S_ISDIR(inode->i_mode))
  85                        return acl ? -EACCES : 0;
  86                break;
  87
  88        default:
  89                return -EINVAL;
  90        }
  91
  92        if (acl) {
  93                size = posix_acl_xattr_size(acl->a_count);
  94                if (unlikely(size > HFSPLUS_MAX_INLINE_DATA_SIZE))
  95                        return -ENOMEM;
  96                value = (char *)hfsplus_alloc_attr_entry();
  97                if (unlikely(!value))
  98                        return -ENOMEM;
  99                err = posix_acl_to_xattr(&init_user_ns, acl, value, size);
 100                if (unlikely(err < 0))
 101                        goto end_set_acl;
 102        }
 103
 104        err = __hfsplus_setxattr(inode, xattr_name, value, size, 0);
 105
 106end_set_acl:
 107        hfsplus_destroy_attr_entry((hfsplus_attr_entry *)value);
 108
 109        if (!err)
 110                set_cached_acl(inode, type, acl);
 111
 112        return err;
 113}
 114
 115int hfsplus_init_posix_acl(struct inode *inode, struct inode *dir)
 116{
 117        int err = 0;
 118        struct posix_acl *acl = NULL;
 119
 120        hfs_dbg(ACL_MOD,
 121                "[%s]: ino %lu, dir->ino %lu\n",
 122                __func__, inode->i_ino, dir->i_ino);
 123
 124        if (S_ISLNK(inode->i_mode))
 125                return 0;
 126
 127        acl = hfsplus_get_posix_acl(dir, ACL_TYPE_DEFAULT);
 128        if (IS_ERR(acl))
 129                return PTR_ERR(acl);
 130
 131        if (acl) {
 132                if (S_ISDIR(inode->i_mode)) {
 133                        err = hfsplus_set_posix_acl(inode,
 134                                                        ACL_TYPE_DEFAULT,
 135                                                        acl);
 136                        if (unlikely(err))
 137                                goto init_acl_cleanup;
 138                }
 139
 140                err = posix_acl_create(&acl, GFP_NOFS, &inode->i_mode);
 141                if (unlikely(err < 0))
 142                        return err;
 143
 144                if (err > 0)
 145                        err = hfsplus_set_posix_acl(inode,
 146                                                        ACL_TYPE_ACCESS,
 147                                                        acl);
 148        } else
 149                inode->i_mode &= ~current_umask();
 150
 151init_acl_cleanup:
 152        posix_acl_release(acl);
 153        return err;
 154}
 155
 156int hfsplus_posix_acl_chmod(struct inode *inode)
 157{
 158        int err;
 159        struct posix_acl *acl;
 160
 161        hfs_dbg(ACL_MOD, "[%s]: ino %lu\n", __func__, inode->i_ino);
 162
 163        if (S_ISLNK(inode->i_mode))
 164                return -EOPNOTSUPP;
 165
 166        acl = hfsplus_get_posix_acl(inode, ACL_TYPE_ACCESS);
 167        if (IS_ERR(acl) || !acl)
 168                return PTR_ERR(acl);
 169
 170        err = posix_acl_chmod(&acl, GFP_KERNEL, inode->i_mode);
 171        if (unlikely(err))
 172                return err;
 173
 174        err = hfsplus_set_posix_acl(inode, ACL_TYPE_ACCESS, acl);
 175        posix_acl_release(acl);
 176        return err;
 177}
 178
 179static int hfsplus_xattr_get_posix_acl(struct dentry *dentry,
 180                                        const char *name,
 181                                        void *buffer,
 182                                        size_t size,
 183                                        int type)
 184{
 185        int err = 0;
 186        struct posix_acl *acl;
 187
 188        hfs_dbg(ACL_MOD,
 189                "[%s]: ino %lu, buffer %p, size %zu, type %#x\n",
 190                __func__, dentry->d_inode->i_ino, buffer, size, type);
 191
 192        if (strcmp(name, "") != 0)
 193                return -EINVAL;
 194
 195        acl = hfsplus_get_posix_acl(dentry->d_inode, type);
 196        if (IS_ERR(acl))
 197                return PTR_ERR(acl);
 198        if (acl == NULL)
 199                return -ENODATA;
 200
 201        err = posix_acl_to_xattr(&init_user_ns, acl, buffer, size);
 202        posix_acl_release(acl);
 203
 204        return err;
 205}
 206
 207static int hfsplus_xattr_set_posix_acl(struct dentry *dentry,
 208                                        const char *name,
 209                                        const void *value,
 210                                        size_t size,
 211                                        int flags,
 212                                        int type)
 213{
 214        int err = 0;
 215        struct inode *inode = dentry->d_inode;
 216        struct posix_acl *acl = NULL;
 217
 218        hfs_dbg(ACL_MOD,
 219                "[%s]: ino %lu, value %p, size %zu, flags %#x, type %#x\n",
 220                __func__, inode->i_ino, value, size, flags, type);
 221
 222        if (strcmp(name, "") != 0)
 223                return -EINVAL;
 224
 225        if (!inode_owner_or_capable(inode))
 226                return -EPERM;
 227
 228        if (value) {
 229                acl = posix_acl_from_xattr(&init_user_ns, value, size);
 230                if (IS_ERR(acl))
 231                        return PTR_ERR(acl);
 232                else if (acl) {
 233                        err = posix_acl_valid(acl);
 234                        if (err)
 235                                goto end_xattr_set_acl;
 236                }
 237        }
 238
 239        err = hfsplus_set_posix_acl(inode, type, acl);
 240
 241end_xattr_set_acl:
 242        posix_acl_release(acl);
 243        return err;
 244}
 245
 246static size_t hfsplus_xattr_list_posix_acl(struct dentry *dentry,
 247                                                char *list,
 248                                                size_t list_size,
 249                                                const char *name,
 250                                                size_t name_len,
 251                                                int type)
 252{
 253        /*
 254         * This method is not used.
 255         * It is used hfsplus_listxattr() instead of generic_listxattr().
 256         */
 257        return -EOPNOTSUPP;
 258}
 259
 260const struct xattr_handler hfsplus_xattr_acl_access_handler = {
 261        .prefix = POSIX_ACL_XATTR_ACCESS,
 262        .flags  = ACL_TYPE_ACCESS,
 263        .list   = hfsplus_xattr_list_posix_acl,
 264        .get    = hfsplus_xattr_get_posix_acl,
 265        .set    = hfsplus_xattr_set_posix_acl,
 266};
 267
 268const struct xattr_handler hfsplus_xattr_acl_default_handler = {
 269        .prefix = POSIX_ACL_XATTR_DEFAULT,
 270        .flags  = ACL_TYPE_DEFAULT,
 271        .list   = hfsplus_xattr_list_posix_acl,
 272        .get    = hfsplus_xattr_get_posix_acl,
 273        .set    = hfsplus_xattr_set_posix_acl,
 274};
 275
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.