Merge tag 'fs.v5.18' of git://git.kernel.org/pub/scm/linux/kernel/git/brauner/linux
[linux-2.6-microblaze.git] / fs / ntfs3 / xattr.c
index 7282d85..afd0dda 100644 (file)
@@ -5,10 +5,7 @@
  *
  */
 
-#include <linux/blkdev.h>
-#include <linux/buffer_head.h>
 #include <linux/fs.h>
-#include <linux/nls.h>
 #include <linux/posix_acl.h>
 #include <linux/posix_acl_xattr.h>
 #include <linux/xattr.h>
@@ -78,6 +75,7 @@ static int ntfs_read_ea(struct ntfs_inode *ni, struct EA_FULL **ea,
                        size_t add_bytes, const struct EA_INFO **info)
 {
        int err;
+       struct ntfs_sb_info *sbi = ni->mi.sbi;
        struct ATTR_LIST_ENTRY *le = NULL;
        struct ATTRIB *attr_info, *attr_ea;
        void *ea_p;
@@ -102,10 +100,10 @@ static int ntfs_read_ea(struct ntfs_inode *ni, struct EA_FULL **ea,
 
        /* Check Ea limit. */
        size = le32_to_cpu((*info)->size);
-       if (size > ni->mi.sbi->ea_max_size)
+       if (size > sbi->ea_max_size)
                return -EFBIG;
 
-       if (attr_size(attr_ea) > ni->mi.sbi->ea_max_size)
+       if (attr_size(attr_ea) > sbi->ea_max_size)
                return -EFBIG;
 
        /* Allocate memory for packed Ea. */
@@ -113,15 +111,16 @@ static int ntfs_read_ea(struct ntfs_inode *ni, struct EA_FULL **ea,
        if (!ea_p)
                return -ENOMEM;
 
-       if (attr_ea->non_res) {
+       if (!size) {
+               ;
+       } else if (attr_ea->non_res) {
                struct runs_tree run;
 
                run_init(&run);
 
                err = attr_load_runs(attr_ea, ni, &run, NULL);
                if (!err)
-                       err = ntfs_read_run_nb(ni->mi.sbi, &run, 0, ea_p, size,
-                                              NULL);
+                       err = ntfs_read_run_nb(sbi, &run, 0, ea_p, size, NULL);
                run_close(&run);
 
                if (err)
@@ -260,7 +259,7 @@ out:
 
 static noinline int ntfs_set_ea(struct inode *inode, const char *name,
                                size_t name_len, const void *value,
-                               size_t val_size, int flags, int locked)
+                               size_t val_size, int flags)
 {
        struct ntfs_inode *ni = ntfs_i(inode);
        struct ntfs_sb_info *sbi = ni->mi.sbi;
@@ -279,8 +278,7 @@ static noinline int ntfs_set_ea(struct inode *inode, const char *name,
        u64 new_sz;
        void *p;
 
-       if (!locked)
-               ni_lock(ni);
+       ni_lock(ni);
 
        run_init(&ea_run);
 
@@ -370,21 +368,22 @@ static noinline int ntfs_set_ea(struct inode *inode, const char *name,
        new_ea->name[name_len] = 0;
        memcpy(new_ea->name + name_len + 1, value, val_size);
        new_pack = le16_to_cpu(ea_info.size_pack) + packed_ea_size(new_ea);
-
-       /* Should fit into 16 bits. */
-       if (new_pack > 0xffff) {
-               err = -EFBIG; // -EINVAL?
-               goto out;
-       }
        ea_info.size_pack = cpu_to_le16(new_pack);
-
        /* New size of ATTR_EA. */
        size += add;
-       if (size > sbi->ea_max_size) {
+       ea_info.size = cpu_to_le32(size);
+
+       /*
+        * 1. Check ea_info.size_pack for overflow.
+        * 2. New attibute size must fit value from $AttrDef
+        */
+       if (new_pack > 0xffff || size > sbi->ea_max_size) {
+               ntfs_inode_warn(
+                       inode,
+                       "The size of extended attributes must not exceed 64KiB");
                err = -EFBIG; // -EINVAL?
                goto out;
        }
-       ea_info.size = cpu_to_le32(size);
 
 update_ea:
 
@@ -444,7 +443,7 @@ update_ea:
                /* Delete xattr, ATTR_EA */
                ni_remove_attr_le(ni, attr, mi, le);
        } else if (attr->non_res) {
-               err = ntfs_sb_write_run(sbi, &ea_run, 0, ea_all, size);
+               err = ntfs_sb_write_run(sbi, &ea_run, 0, ea_all, size, 0);
                if (err)
                        goto out;
        } else {
@@ -468,8 +467,7 @@ update_ea:
        mark_inode_dirty(&ni->vfs_inode);
 
 out:
-       if (!locked)
-               ni_unlock(ni);
+       ni_unlock(ni);
 
        run_close(&ea_run);
        kfree(ea_all);
@@ -478,12 +476,6 @@ out:
 }
 
 #ifdef CONFIG_NTFS3_FS_POSIX_ACL
-static inline void ntfs_posix_acl_release(struct posix_acl *acl)
-{
-       if (acl && refcount_dec_and_test(&acl->a_refcount))
-               kfree(acl);
-}
-
 static struct posix_acl *ntfs_get_acl_ex(struct user_namespace *mnt_userns,
                                         struct inode *inode, int type,
                                         int locked)
@@ -521,12 +513,15 @@ static struct posix_acl *ntfs_get_acl_ex(struct user_namespace *mnt_userns,
        /* Translate extended attribute to acl. */
        if (err >= 0) {
                acl = posix_acl_from_xattr(mnt_userns, buf, err);
-               if (!IS_ERR(acl))
-                       set_cached_acl(inode, type, acl);
+       } else if (err == -ENODATA) {
+               acl = NULL;
        } else {
-               acl = err == -ENODATA ? NULL : ERR_PTR(err);
+               acl = ERR_PTR(err);
        }
 
+       if (!IS_ERR(acl))
+               set_cached_acl(inode, type, acl);
+
        __putname(buf);
 
        return acl;
@@ -546,12 +541,13 @@ struct posix_acl *ntfs_get_acl(struct inode *inode, int type, bool rcu)
 
 static noinline int ntfs_set_acl_ex(struct user_namespace *mnt_userns,
                                    struct inode *inode, struct posix_acl *acl,
-                                   int type, int locked)
+                                   int type)
 {
        const char *name;
        size_t size, name_len;
        void *value = NULL;
        int err = 0;
+       int flags;
 
        if (S_ISLNK(inode->i_mode))
                return -EOPNOTSUPP;
@@ -561,22 +557,15 @@ static noinline int ntfs_set_acl_ex(struct user_namespace *mnt_userns,
                if (acl) {
                        umode_t mode = inode->i_mode;
 
-                       err = posix_acl_equiv_mode(acl, &mode);
-                       if (err < 0)
-                               return err;
+                       err = posix_acl_update_mode(mnt_userns, inode, &mode,
+                                                   &acl);
+                       if (err)
+                               goto out;
 
                        if (inode->i_mode != mode) {
                                inode->i_mode = mode;
                                mark_inode_dirty(inode);
                        }
-
-                       if (!err) {
-                               /*
-                                * ACL can be exactly represented in the
-                                * traditional file mode permission bits.
-                                */
-                               acl = NULL;
-                       }
                }
                name = XATTR_NAME_POSIX_ACL_ACCESS;
                name_len = sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1;
@@ -594,20 +583,24 @@ static noinline int ntfs_set_acl_ex(struct user_namespace *mnt_userns,
        }
 
        if (!acl) {
+               /* Remove xattr if it can be presented via mode. */
                size = 0;
                value = NULL;
+               flags = XATTR_REPLACE;
        } else {
                size = posix_acl_xattr_size(acl->a_count);
                value = kmalloc(size, GFP_NOFS);
                if (!value)
                        return -ENOMEM;
-
                err = posix_acl_to_xattr(mnt_userns, acl, value, size);
                if (err < 0)
                        goto out;
+               flags = 0;
        }
 
-       err = ntfs_set_ea(inode, name, name_len, value, size, 0, locked);
+       err = ntfs_set_ea(inode, name, name_len, value, size, flags);
+       if (err == -ENODATA && !size)
+               err = 0; /* Removing non existed xattr. */
        if (!err)
                set_cached_acl(inode, type, acl);
 
@@ -623,68 +616,7 @@ out:
 int ntfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
                 struct posix_acl *acl, int type)
 {
-       return ntfs_set_acl_ex(mnt_userns, inode, acl, type, 0);
-}
-
-static int ntfs_xattr_get_acl(struct user_namespace *mnt_userns,
-                             struct inode *inode, int type, void *buffer,
-                             size_t size)
-{
-       struct posix_acl *acl;
-       int err;
-
-       if (!(inode->i_sb->s_flags & SB_POSIXACL)) {
-               ntfs_inode_warn(inode, "add mount option \"acl\" to use acl");
-               return -EOPNOTSUPP;
-       }
-
-       acl = ntfs_get_acl(inode, type, false);
-       if (IS_ERR(acl))
-               return PTR_ERR(acl);
-
-       if (!acl)
-               return -ENODATA;
-
-       err = posix_acl_to_xattr(mnt_userns, acl, buffer, size);
-       ntfs_posix_acl_release(acl);
-
-       return err;
-}
-
-static int ntfs_xattr_set_acl(struct user_namespace *mnt_userns,
-                             struct inode *inode, int type, const void *value,
-                             size_t size)
-{
-       struct posix_acl *acl;
-       int err;
-
-       if (!(inode->i_sb->s_flags & SB_POSIXACL)) {
-               ntfs_inode_warn(inode, "add mount option \"acl\" to use acl");
-               return -EOPNOTSUPP;
-       }
-
-       if (!inode_owner_or_capable(mnt_userns, inode))
-               return -EPERM;
-
-       if (!value) {
-               acl = NULL;
-       } else {
-               acl = posix_acl_from_xattr(mnt_userns, value, size);
-               if (IS_ERR(acl))
-                       return PTR_ERR(acl);
-
-               if (acl) {
-                       err = posix_acl_valid(mnt_userns, acl);
-                       if (err)
-                               goto release_and_out;
-               }
-       }
-
-       err = ntfs_set_acl(mnt_userns, inode, acl, type);
-
-release_and_out:
-       ntfs_posix_acl_release(acl);
-       return err;
+       return ntfs_set_acl_ex(mnt_userns, inode, acl, type);
 }
 
 /*
@@ -698,54 +630,27 @@ int ntfs_init_acl(struct user_namespace *mnt_userns, struct inode *inode,
        struct posix_acl *default_acl, *acl;
        int err;
 
-       /*
-        * TODO: Refactoring lock.
-        * ni_lock(dir) ... -> posix_acl_create(dir,...) -> ntfs_get_acl -> ni_lock(dir)
-        */
-       inode->i_default_acl = NULL;
-
-       default_acl = ntfs_get_acl_ex(mnt_userns, dir, ACL_TYPE_DEFAULT, 1);
-
-       if (!default_acl || default_acl == ERR_PTR(-EOPNOTSUPP)) {
-               inode->i_mode &= ~current_umask();
-               err = 0;
-               goto out;
-       }
-
-       if (IS_ERR(default_acl)) {
-               err = PTR_ERR(default_acl);
-               goto out;
-       }
-
-       acl = default_acl;
-       err = __posix_acl_create(&acl, GFP_NOFS, &inode->i_mode);
-       if (err < 0)
-               goto out1;
-       if (!err) {
-               posix_acl_release(acl);
-               acl = NULL;
-       }
+       err = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
+       if (err)
+               return err;
 
-       if (!S_ISDIR(inode->i_mode)) {
+       if (default_acl) {
+               err = ntfs_set_acl_ex(mnt_userns, inode, default_acl,
+                                     ACL_TYPE_DEFAULT);
                posix_acl_release(default_acl);
-               default_acl = NULL;
+       } else {
+               inode->i_default_acl = NULL;
        }
 
-       if (default_acl)
-               err = ntfs_set_acl_ex(mnt_userns, inode, default_acl,
-                                     ACL_TYPE_DEFAULT, 1);
-
        if (!acl)
                inode->i_acl = NULL;
-       else if (!err)
-               err = ntfs_set_acl_ex(mnt_userns, inode, acl, ACL_TYPE_ACCESS,
-                                     1);
-
-       posix_acl_release(acl);
-out1:
-       posix_acl_release(default_acl);
+       else {
+               if (!err)
+                       err = ntfs_set_acl_ex(mnt_userns, inode, acl,
+                                             ACL_TYPE_ACCESS);
+               posix_acl_release(acl);
+       }
 
-out:
        return err;
 }
 #endif
@@ -772,7 +677,7 @@ int ntfs_acl_chmod(struct user_namespace *mnt_userns, struct inode *inode)
 int ntfs_permission(struct user_namespace *mnt_userns, struct inode *inode,
                    int mask)
 {
-       if (ntfs_sb(inode->i_sb)->options.no_acs_rules) {
+       if (ntfs_sb(inode->i_sb)->options->noacsrules) {
                /* "No access rules" mode - Allow all changes. */
                return 0;
        }
@@ -880,23 +785,6 @@ static int ntfs_getxattr(const struct xattr_handler *handler, struct dentry *de,
                goto out;
        }
 
-#ifdef CONFIG_NTFS3_FS_POSIX_ACL
-       if ((name_len == sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1 &&
-            !memcmp(name, XATTR_NAME_POSIX_ACL_ACCESS,
-                    sizeof(XATTR_NAME_POSIX_ACL_ACCESS))) ||
-           (name_len == sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) - 1 &&
-            !memcmp(name, XATTR_NAME_POSIX_ACL_DEFAULT,
-                    sizeof(XATTR_NAME_POSIX_ACL_DEFAULT)))) {
-               /* TODO: init_user_ns? */
-               err = ntfs_xattr_get_acl(
-                       &init_user_ns, inode,
-                       name_len == sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1
-                               ? ACL_TYPE_ACCESS
-                               : ACL_TYPE_DEFAULT,
-                       buffer, size);
-               goto out;
-       }
-#endif
        /* Deal with NTFS extended attribute. */
        err = ntfs_get_ea(inode, name, name_len, buffer, size, NULL);
 
@@ -1009,24 +897,8 @@ set_new_fa:
                goto out;
        }
 
-#ifdef CONFIG_NTFS3_FS_POSIX_ACL
-       if ((name_len == sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1 &&
-            !memcmp(name, XATTR_NAME_POSIX_ACL_ACCESS,
-                    sizeof(XATTR_NAME_POSIX_ACL_ACCESS))) ||
-           (name_len == sizeof(XATTR_NAME_POSIX_ACL_DEFAULT) - 1 &&
-            !memcmp(name, XATTR_NAME_POSIX_ACL_DEFAULT,
-                    sizeof(XATTR_NAME_POSIX_ACL_DEFAULT)))) {
-               err = ntfs_xattr_set_acl(
-                       mnt_userns, inode,
-                       name_len == sizeof(XATTR_NAME_POSIX_ACL_ACCESS) - 1
-                               ? ACL_TYPE_ACCESS
-                               : ACL_TYPE_DEFAULT,
-                       value, size);
-               goto out;
-       }
-#endif
        /* Deal with NTFS extended attribute. */
-       err = ntfs_set_ea(inode, name, name_len, value, size, flags, 0);
+       err = ntfs_set_ea(inode, name, name_len, value, size, flags);
 
 out:
        return err;
@@ -1042,28 +914,29 @@ int ntfs_save_wsl_perm(struct inode *inode)
        int err;
        __le32 value;
 
+       /* TODO: refactor this, so we don't lock 4 times in ntfs_set_ea */
        value = cpu_to_le32(i_uid_read(inode));
        err = ntfs_set_ea(inode, "$LXUID", sizeof("$LXUID") - 1, &value,
-                         sizeof(value), 0, 0);
+                         sizeof(value), 0);
        if (err)
                goto out;
 
        value = cpu_to_le32(i_gid_read(inode));
        err = ntfs_set_ea(inode, "$LXGID", sizeof("$LXGID") - 1, &value,
-                         sizeof(value), 0, 0);
+                         sizeof(value), 0);
        if (err)
                goto out;
 
        value = cpu_to_le32(inode->i_mode);
        err = ntfs_set_ea(inode, "$LXMOD", sizeof("$LXMOD") - 1, &value,
-                         sizeof(value), 0, 0);
+                         sizeof(value), 0);
        if (err)
                goto out;
 
        if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) {
                value = cpu_to_le32(inode->i_rdev);
                err = ntfs_set_ea(inode, "$LXDEV", sizeof("$LXDEV") - 1, &value,
-                                 sizeof(value), 0, 0);
+                                 sizeof(value), 0);
                if (err)
                        goto out;
        }