aboutsummaryrefslogtreecommitdiffstats
path: root/fs/xattr.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/xattr.c')
-rw-r--r--fs/xattr.c180
1 files changed, 180 insertions, 0 deletions
diff --git a/fs/xattr.c b/fs/xattr.c
index 4d45b7189e7e..014f11321fd9 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -791,3 +791,183 @@ EXPORT_SYMBOL(generic_getxattr);
791EXPORT_SYMBOL(generic_listxattr); 791EXPORT_SYMBOL(generic_listxattr);
792EXPORT_SYMBOL(generic_setxattr); 792EXPORT_SYMBOL(generic_setxattr);
793EXPORT_SYMBOL(generic_removexattr); 793EXPORT_SYMBOL(generic_removexattr);
794
795/*
796 * Allocate new xattr and copy in the value; but leave the name to callers.
797 */
798struct simple_xattr *simple_xattr_alloc(const void *value, size_t size)
799{
800 struct simple_xattr *new_xattr;
801 size_t len;
802
803 /* wrap around? */
804 len = sizeof(*new_xattr) + size;
805 if (len <= sizeof(*new_xattr))
806 return NULL;
807
808 new_xattr = kmalloc(len, GFP_KERNEL);
809 if (!new_xattr)
810 return NULL;
811
812 new_xattr->size = size;
813 memcpy(new_xattr->value, value, size);
814 return new_xattr;
815}
816
817/*
818 * xattr GET operation for in-memory/pseudo filesystems
819 */
820int simple_xattr_get(struct simple_xattrs *xattrs, const char *name,
821 void *buffer, size_t size)
822{
823 struct simple_xattr *xattr;
824 int ret = -ENODATA;
825
826 spin_lock(&xattrs->lock);
827 list_for_each_entry(xattr, &xattrs->head, list) {
828 if (strcmp(name, xattr->name))
829 continue;
830
831 ret = xattr->size;
832 if (buffer) {
833 if (size < xattr->size)
834 ret = -ERANGE;
835 else
836 memcpy(buffer, xattr->value, xattr->size);
837 }
838 break;
839 }
840 spin_unlock(&xattrs->lock);
841 return ret;
842}
843
844static int __simple_xattr_set(struct simple_xattrs *xattrs, const char *name,
845 const void *value, size_t size, int flags)
846{
847 struct simple_xattr *xattr;
848 struct simple_xattr *uninitialized_var(new_xattr);
849 int err = 0;
850
851 /* value == NULL means remove */
852 if (value) {
853 new_xattr = simple_xattr_alloc(value, size);
854 if (!new_xattr)
855 return -ENOMEM;
856
857 new_xattr->name = kstrdup(name, GFP_KERNEL);
858 if (!new_xattr->name) {
859 kfree(new_xattr);
860 return -ENOMEM;
861 }
862 }
863
864 spin_lock(&xattrs->lock);
865 list_for_each_entry(xattr, &xattrs->head, list) {
866 if (!strcmp(name, xattr->name)) {
867 if (flags & XATTR_CREATE) {
868 xattr = new_xattr;
869 err = -EEXIST;
870 } else if (new_xattr) {
871 list_replace(&xattr->list, &new_xattr->list);
872 } else {
873 list_del(&xattr->list);
874 }
875 goto out;
876 }
877 }
878 if (flags & XATTR_REPLACE) {
879 xattr = new_xattr;
880 err = -ENODATA;
881 } else {
882 list_add(&new_xattr->list, &xattrs->head);
883 xattr = NULL;
884 }
885out:
886 spin_unlock(&xattrs->lock);
887 if (xattr) {
888 kfree(xattr->name);
889 kfree(xattr);
890 }
891 return err;
892
893}
894
895/**
896 * simple_xattr_set - xattr SET operation for in-memory/pseudo filesystems
897 * @xattrs: target simple_xattr list
898 * @name: name of the new extended attribute
899 * @value: value of the new xattr. If %NULL, will remove the attribute
900 * @size: size of the new xattr
901 * @flags: %XATTR_{CREATE|REPLACE}
902 *
903 * %XATTR_CREATE is set, the xattr shouldn't exist already; otherwise fails
904 * with -EEXIST. If %XATTR_REPLACE is set, the xattr should exist;
905 * otherwise, fails with -ENODATA.
906 *
907 * Returns 0 on success, -errno on failure.
908 */
909int simple_xattr_set(struct simple_xattrs *xattrs, const char *name,
910 const void *value, size_t size, int flags)
911{
912 if (size == 0)
913 value = ""; /* empty EA, do not remove */
914 return __simple_xattr_set(xattrs, name, value, size, flags);
915}
916
917/*
918 * xattr REMOVE operation for in-memory/pseudo filesystems
919 */
920int simple_xattr_remove(struct simple_xattrs *xattrs, const char *name)
921{
922 return __simple_xattr_set(xattrs, name, NULL, 0, XATTR_REPLACE);
923}
924
925static bool xattr_is_trusted(const char *name)
926{
927 return !strncmp(name, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN);
928}
929
930/*
931 * xattr LIST operation for in-memory/pseudo filesystems
932 */
933ssize_t simple_xattr_list(struct simple_xattrs *xattrs, char *buffer,
934 size_t size)
935{
936 bool trusted = capable(CAP_SYS_ADMIN);
937 struct simple_xattr *xattr;
938 size_t used = 0;
939
940 spin_lock(&xattrs->lock);
941 list_for_each_entry(xattr, &xattrs->head, list) {
942 size_t len;
943
944 /* skip "trusted." attributes for unprivileged callers */
945 if (!trusted && xattr_is_trusted(xattr->name))
946 continue;
947
948 len = strlen(xattr->name) + 1;
949 used += len;
950 if (buffer) {
951 if (size < used) {
952 used = -ERANGE;
953 break;
954 }
955 memcpy(buffer, xattr->name, len);
956 buffer += len;
957 }
958 }
959 spin_unlock(&xattrs->lock);
960
961 return used;
962}
963
964/*
965 * Adds an extended attribute to the list
966 */
967void simple_xattr_list_add(struct simple_xattrs *xattrs,
968 struct simple_xattr *new_xattr)
969{
970 spin_lock(&xattrs->lock);
971 list_add(&new_xattr->list, &xattrs->head);
972 spin_unlock(&xattrs->lock);
973}