diff options
author | Christoph Hellwig <hch@infradead.org> | 2013-12-20 08:16:40 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2014-01-25 23:58:17 -0500 |
commit | 2aeccbe957d0d2b9fbb2a236e53a955097e2a9ce (patch) | |
tree | b07768d451a0d4b4be65096f9462660e856e6798 | |
parent | 893d46e443346370cd4ea81d9d35f72952c62a37 (diff) |
fs: add generic xattr_acl handlers
With the ->set_acl inode operation we can implement the Posix ACL
xattr handlers in generic code instead of duplicating them all
over the tree.
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Jan Kara <jack@suse.cz>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
-rw-r--r-- | fs/posix_acl.c | 102 | ||||
-rw-r--r-- | include/linux/posix_acl_xattr.h | 3 |
2 files changed, 105 insertions, 0 deletions
diff --git a/fs/posix_acl.c b/fs/posix_acl.c index 30524de49a6b..e699b076cdd8 100644 --- a/fs/posix_acl.c +++ b/fs/posix_acl.c | |||
@@ -17,6 +17,7 @@ | |||
17 | #include <linux/sched.h> | 17 | #include <linux/sched.h> |
18 | #include <linux/posix_acl.h> | 18 | #include <linux/posix_acl.h> |
19 | #include <linux/posix_acl_xattr.h> | 19 | #include <linux/posix_acl_xattr.h> |
20 | #include <linux/xattr.h> | ||
20 | #include <linux/export.h> | 21 | #include <linux/export.h> |
21 | #include <linux/user_namespace.h> | 22 | #include <linux/user_namespace.h> |
22 | 23 | ||
@@ -611,3 +612,104 @@ posix_acl_to_xattr(struct user_namespace *user_ns, const struct posix_acl *acl, | |||
611 | return real_size; | 612 | return real_size; |
612 | } | 613 | } |
613 | EXPORT_SYMBOL (posix_acl_to_xattr); | 614 | EXPORT_SYMBOL (posix_acl_to_xattr); |
615 | |||
616 | static int | ||
617 | posix_acl_xattr_get(struct dentry *dentry, const char *name, | ||
618 | void *value, size_t size, int type) | ||
619 | { | ||
620 | struct posix_acl *acl; | ||
621 | int error; | ||
622 | |||
623 | if (!IS_POSIXACL(dentry->d_inode)) | ||
624 | return -EOPNOTSUPP; | ||
625 | if (S_ISLNK(dentry->d_inode->i_mode)) | ||
626 | return -EOPNOTSUPP; | ||
627 | |||
628 | acl = get_acl(dentry->d_inode, type); | ||
629 | if (IS_ERR(acl)) | ||
630 | return PTR_ERR(acl); | ||
631 | if (acl == NULL) | ||
632 | return -ENODATA; | ||
633 | |||
634 | error = posix_acl_to_xattr(&init_user_ns, acl, value, size); | ||
635 | posix_acl_release(acl); | ||
636 | |||
637 | return error; | ||
638 | } | ||
639 | |||
640 | static int | ||
641 | posix_acl_xattr_set(struct dentry *dentry, const char *name, | ||
642 | const void *value, size_t size, int flags, int type) | ||
643 | { | ||
644 | struct inode *inode = dentry->d_inode; | ||
645 | struct posix_acl *acl = NULL; | ||
646 | int ret; | ||
647 | |||
648 | if (!IS_POSIXACL(inode)) | ||
649 | return -EOPNOTSUPP; | ||
650 | if (!inode->i_op->set_acl) | ||
651 | return -EOPNOTSUPP; | ||
652 | |||
653 | if (type == ACL_TYPE_DEFAULT && !S_ISDIR(inode->i_mode)) | ||
654 | return value ? -EACCES : 0; | ||
655 | if (!inode_owner_or_capable(inode)) | ||
656 | return -EPERM; | ||
657 | |||
658 | if (value) { | ||
659 | acl = posix_acl_from_xattr(&init_user_ns, value, size); | ||
660 | if (IS_ERR(acl)) | ||
661 | return PTR_ERR(acl); | ||
662 | |||
663 | if (acl) { | ||
664 | ret = posix_acl_valid(acl); | ||
665 | if (ret) | ||
666 | goto out; | ||
667 | } | ||
668 | } | ||
669 | |||
670 | ret = inode->i_op->set_acl(inode, acl, type); | ||
671 | out: | ||
672 | posix_acl_release(acl); | ||
673 | return ret; | ||
674 | } | ||
675 | |||
676 | static size_t | ||
677 | posix_acl_xattr_list(struct dentry *dentry, char *list, size_t list_size, | ||
678 | const char *name, size_t name_len, int type) | ||
679 | { | ||
680 | const char *xname; | ||
681 | size_t size; | ||
682 | |||
683 | if (!IS_POSIXACL(dentry->d_inode)) | ||
684 | return -EOPNOTSUPP; | ||
685 | if (S_ISLNK(dentry->d_inode->i_mode)) | ||
686 | return -EOPNOTSUPP; | ||
687 | |||
688 | if (type == ACL_TYPE_ACCESS) | ||
689 | xname = POSIX_ACL_XATTR_ACCESS; | ||
690 | else | ||
691 | xname = POSIX_ACL_XATTR_DEFAULT; | ||
692 | |||
693 | size = strlen(xname) + 1; | ||
694 | if (list && size <= list_size) | ||
695 | memcpy(list, xname, size); | ||
696 | return size; | ||
697 | } | ||
698 | |||
699 | const struct xattr_handler posix_acl_access_xattr_handler = { | ||
700 | .prefix = POSIX_ACL_XATTR_ACCESS, | ||
701 | .flags = ACL_TYPE_ACCESS, | ||
702 | .list = posix_acl_xattr_list, | ||
703 | .get = posix_acl_xattr_get, | ||
704 | .set = posix_acl_xattr_set, | ||
705 | }; | ||
706 | EXPORT_SYMBOL_GPL(posix_acl_access_xattr_handler); | ||
707 | |||
708 | const struct xattr_handler posix_acl_default_xattr_handler = { | ||
709 | .prefix = POSIX_ACL_XATTR_DEFAULT, | ||
710 | .flags = ACL_TYPE_DEFAULT, | ||
711 | .list = posix_acl_xattr_list, | ||
712 | .get = posix_acl_xattr_get, | ||
713 | .set = posix_acl_xattr_set, | ||
714 | }; | ||
715 | EXPORT_SYMBOL_GPL(posix_acl_default_xattr_handler); | ||
diff --git a/include/linux/posix_acl_xattr.h b/include/linux/posix_acl_xattr.h index ad93ad0f1db0..6f14ee295822 100644 --- a/include/linux/posix_acl_xattr.h +++ b/include/linux/posix_acl_xattr.h | |||
@@ -69,4 +69,7 @@ struct posix_acl *posix_acl_from_xattr(struct user_namespace *user_ns, | |||
69 | int posix_acl_to_xattr(struct user_namespace *user_ns, | 69 | int posix_acl_to_xattr(struct user_namespace *user_ns, |
70 | const struct posix_acl *acl, void *buffer, size_t size); | 70 | const struct posix_acl *acl, void *buffer, size_t size); |
71 | 71 | ||
72 | extern const struct xattr_handler posix_acl_access_xattr_handler; | ||
73 | extern const struct xattr_handler posix_acl_default_xattr_handler; | ||
74 | |||
72 | #endif /* _POSIX_ACL_XATTR_H */ | 75 | #endif /* _POSIX_ACL_XATTR_H */ |