diff options
-rw-r--r-- | fs/fuse/dir.c | 183 | ||||
-rw-r--r-- | fs/fuse/fuse_i.h | 12 | ||||
-rw-r--r-- | include/linux/fuse.h | 18 |
3 files changed, 213 insertions, 0 deletions
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c index 0950455914dd..f127625543b4 100644 --- a/fs/fuse/dir.c +++ b/fs/fuse/dir.c | |||
@@ -744,6 +744,177 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry, | |||
744 | return d_splice_alias(inode, entry); | 744 | return d_splice_alias(inode, entry); |
745 | } | 745 | } |
746 | 746 | ||
747 | static int fuse_setxattr(struct dentry *entry, const char *name, | ||
748 | const void *value, size_t size, int flags) | ||
749 | { | ||
750 | struct inode *inode = entry->d_inode; | ||
751 | struct fuse_conn *fc = get_fuse_conn(inode); | ||
752 | struct fuse_req *req; | ||
753 | struct fuse_setxattr_in inarg; | ||
754 | int err; | ||
755 | |||
756 | if (size > FUSE_XATTR_SIZE_MAX) | ||
757 | return -E2BIG; | ||
758 | |||
759 | if (fc->no_setxattr) | ||
760 | return -EOPNOTSUPP; | ||
761 | |||
762 | req = fuse_get_request(fc); | ||
763 | if (!req) | ||
764 | return -ERESTARTNOINTR; | ||
765 | |||
766 | memset(&inarg, 0, sizeof(inarg)); | ||
767 | inarg.size = size; | ||
768 | inarg.flags = flags; | ||
769 | req->in.h.opcode = FUSE_SETXATTR; | ||
770 | req->in.h.nodeid = get_node_id(inode); | ||
771 | req->inode = inode; | ||
772 | req->in.numargs = 3; | ||
773 | req->in.args[0].size = sizeof(inarg); | ||
774 | req->in.args[0].value = &inarg; | ||
775 | req->in.args[1].size = strlen(name) + 1; | ||
776 | req->in.args[1].value = name; | ||
777 | req->in.args[2].size = size; | ||
778 | req->in.args[2].value = value; | ||
779 | request_send(fc, req); | ||
780 | err = req->out.h.error; | ||
781 | fuse_put_request(fc, req); | ||
782 | if (err == -ENOSYS) { | ||
783 | fc->no_setxattr = 1; | ||
784 | err = -EOPNOTSUPP; | ||
785 | } | ||
786 | return err; | ||
787 | } | ||
788 | |||
789 | static ssize_t fuse_getxattr(struct dentry *entry, const char *name, | ||
790 | void *value, size_t size) | ||
791 | { | ||
792 | struct inode *inode = entry->d_inode; | ||
793 | struct fuse_conn *fc = get_fuse_conn(inode); | ||
794 | struct fuse_req *req; | ||
795 | struct fuse_getxattr_in inarg; | ||
796 | struct fuse_getxattr_out outarg; | ||
797 | ssize_t ret; | ||
798 | |||
799 | if (fc->no_getxattr) | ||
800 | return -EOPNOTSUPP; | ||
801 | |||
802 | req = fuse_get_request(fc); | ||
803 | if (!req) | ||
804 | return -ERESTARTNOINTR; | ||
805 | |||
806 | memset(&inarg, 0, sizeof(inarg)); | ||
807 | inarg.size = size; | ||
808 | req->in.h.opcode = FUSE_GETXATTR; | ||
809 | req->in.h.nodeid = get_node_id(inode); | ||
810 | req->inode = inode; | ||
811 | req->in.numargs = 2; | ||
812 | req->in.args[0].size = sizeof(inarg); | ||
813 | req->in.args[0].value = &inarg; | ||
814 | req->in.args[1].size = strlen(name) + 1; | ||
815 | req->in.args[1].value = name; | ||
816 | /* This is really two different operations rolled into one */ | ||
817 | req->out.numargs = 1; | ||
818 | if (size) { | ||
819 | req->out.argvar = 1; | ||
820 | req->out.args[0].size = size; | ||
821 | req->out.args[0].value = value; | ||
822 | } else { | ||
823 | req->out.args[0].size = sizeof(outarg); | ||
824 | req->out.args[0].value = &outarg; | ||
825 | } | ||
826 | request_send(fc, req); | ||
827 | ret = req->out.h.error; | ||
828 | if (!ret) | ||
829 | ret = size ? req->out.args[0].size : outarg.size; | ||
830 | else { | ||
831 | if (ret == -ENOSYS) { | ||
832 | fc->no_getxattr = 1; | ||
833 | ret = -EOPNOTSUPP; | ||
834 | } | ||
835 | } | ||
836 | fuse_put_request(fc, req); | ||
837 | return ret; | ||
838 | } | ||
839 | |||
840 | static ssize_t fuse_listxattr(struct dentry *entry, char *list, size_t size) | ||
841 | { | ||
842 | struct inode *inode = entry->d_inode; | ||
843 | struct fuse_conn *fc = get_fuse_conn(inode); | ||
844 | struct fuse_req *req; | ||
845 | struct fuse_getxattr_in inarg; | ||
846 | struct fuse_getxattr_out outarg; | ||
847 | ssize_t ret; | ||
848 | |||
849 | if (fc->no_listxattr) | ||
850 | return -EOPNOTSUPP; | ||
851 | |||
852 | req = fuse_get_request(fc); | ||
853 | if (!req) | ||
854 | return -ERESTARTNOINTR; | ||
855 | |||
856 | memset(&inarg, 0, sizeof(inarg)); | ||
857 | inarg.size = size; | ||
858 | req->in.h.opcode = FUSE_LISTXATTR; | ||
859 | req->in.h.nodeid = get_node_id(inode); | ||
860 | req->inode = inode; | ||
861 | req->in.numargs = 1; | ||
862 | req->in.args[0].size = sizeof(inarg); | ||
863 | req->in.args[0].value = &inarg; | ||
864 | /* This is really two different operations rolled into one */ | ||
865 | req->out.numargs = 1; | ||
866 | if (size) { | ||
867 | req->out.argvar = 1; | ||
868 | req->out.args[0].size = size; | ||
869 | req->out.args[0].value = list; | ||
870 | } else { | ||
871 | req->out.args[0].size = sizeof(outarg); | ||
872 | req->out.args[0].value = &outarg; | ||
873 | } | ||
874 | request_send(fc, req); | ||
875 | ret = req->out.h.error; | ||
876 | if (!ret) | ||
877 | ret = size ? req->out.args[0].size : outarg.size; | ||
878 | else { | ||
879 | if (ret == -ENOSYS) { | ||
880 | fc->no_listxattr = 1; | ||
881 | ret = -EOPNOTSUPP; | ||
882 | } | ||
883 | } | ||
884 | fuse_put_request(fc, req); | ||
885 | return ret; | ||
886 | } | ||
887 | |||
888 | static int fuse_removexattr(struct dentry *entry, const char *name) | ||
889 | { | ||
890 | struct inode *inode = entry->d_inode; | ||
891 | struct fuse_conn *fc = get_fuse_conn(inode); | ||
892 | struct fuse_req *req; | ||
893 | int err; | ||
894 | |||
895 | if (fc->no_removexattr) | ||
896 | return -EOPNOTSUPP; | ||
897 | |||
898 | req = fuse_get_request(fc); | ||
899 | if (!req) | ||
900 | return -ERESTARTNOINTR; | ||
901 | |||
902 | req->in.h.opcode = FUSE_REMOVEXATTR; | ||
903 | req->in.h.nodeid = get_node_id(inode); | ||
904 | req->inode = inode; | ||
905 | req->in.numargs = 1; | ||
906 | req->in.args[0].size = strlen(name) + 1; | ||
907 | req->in.args[0].value = name; | ||
908 | request_send(fc, req); | ||
909 | err = req->out.h.error; | ||
910 | fuse_put_request(fc, req); | ||
911 | if (err == -ENOSYS) { | ||
912 | fc->no_removexattr = 1; | ||
913 | err = -EOPNOTSUPP; | ||
914 | } | ||
915 | return err; | ||
916 | } | ||
917 | |||
747 | static struct inode_operations fuse_dir_inode_operations = { | 918 | static struct inode_operations fuse_dir_inode_operations = { |
748 | .lookup = fuse_lookup, | 919 | .lookup = fuse_lookup, |
749 | .mkdir = fuse_mkdir, | 920 | .mkdir = fuse_mkdir, |
@@ -757,6 +928,10 @@ static struct inode_operations fuse_dir_inode_operations = { | |||
757 | .mknod = fuse_mknod, | 928 | .mknod = fuse_mknod, |
758 | .permission = fuse_permission, | 929 | .permission = fuse_permission, |
759 | .getattr = fuse_getattr, | 930 | .getattr = fuse_getattr, |
931 | .setxattr = fuse_setxattr, | ||
932 | .getxattr = fuse_getxattr, | ||
933 | .listxattr = fuse_listxattr, | ||
934 | .removexattr = fuse_removexattr, | ||
760 | }; | 935 | }; |
761 | 936 | ||
762 | static struct file_operations fuse_dir_operations = { | 937 | static struct file_operations fuse_dir_operations = { |
@@ -771,6 +946,10 @@ static struct inode_operations fuse_common_inode_operations = { | |||
771 | .setattr = fuse_setattr, | 946 | .setattr = fuse_setattr, |
772 | .permission = fuse_permission, | 947 | .permission = fuse_permission, |
773 | .getattr = fuse_getattr, | 948 | .getattr = fuse_getattr, |
949 | .setxattr = fuse_setxattr, | ||
950 | .getxattr = fuse_getxattr, | ||
951 | .listxattr = fuse_listxattr, | ||
952 | .removexattr = fuse_removexattr, | ||
774 | }; | 953 | }; |
775 | 954 | ||
776 | static struct inode_operations fuse_symlink_inode_operations = { | 955 | static struct inode_operations fuse_symlink_inode_operations = { |
@@ -779,6 +958,10 @@ static struct inode_operations fuse_symlink_inode_operations = { | |||
779 | .put_link = fuse_put_link, | 958 | .put_link = fuse_put_link, |
780 | .readlink = generic_readlink, | 959 | .readlink = generic_readlink, |
781 | .getattr = fuse_getattr, | 960 | .getattr = fuse_getattr, |
961 | .setxattr = fuse_setxattr, | ||
962 | .getxattr = fuse_getxattr, | ||
963 | .listxattr = fuse_listxattr, | ||
964 | .removexattr = fuse_removexattr, | ||
782 | }; | 965 | }; |
783 | 966 | ||
784 | void fuse_init_common(struct inode *inode) | 967 | void fuse_init_common(struct inode *inode) |
diff --git a/fs/fuse/fuse_i.h b/fs/fuse/fuse_i.h index c8e6c87496e0..86183c562104 100644 --- a/fs/fuse/fuse_i.h +++ b/fs/fuse/fuse_i.h | |||
@@ -245,6 +245,18 @@ struct fuse_conn { | |||
245 | /** Is flush not implemented by fs? */ | 245 | /** Is flush not implemented by fs? */ |
246 | unsigned no_flush : 1; | 246 | unsigned no_flush : 1; |
247 | 247 | ||
248 | /** Is setxattr not implemented by fs? */ | ||
249 | unsigned no_setxattr : 1; | ||
250 | |||
251 | /** Is getxattr not implemented by fs? */ | ||
252 | unsigned no_getxattr : 1; | ||
253 | |||
254 | /** Is listxattr not implemented by fs? */ | ||
255 | unsigned no_listxattr : 1; | ||
256 | |||
257 | /** Is removexattr not implemented by fs? */ | ||
258 | unsigned no_removexattr : 1; | ||
259 | |||
248 | /** Backing dev info */ | 260 | /** Backing dev info */ |
249 | struct backing_dev_info bdi; | 261 | struct backing_dev_info bdi; |
250 | }; | 262 | }; |
diff --git a/include/linux/fuse.h b/include/linux/fuse.h index 61f34636ffbc..bf564edf9905 100644 --- a/include/linux/fuse.h +++ b/include/linux/fuse.h | |||
@@ -80,6 +80,10 @@ enum fuse_opcode { | |||
80 | FUSE_STATFS = 17, | 80 | FUSE_STATFS = 17, |
81 | FUSE_RELEASE = 18, | 81 | FUSE_RELEASE = 18, |
82 | FUSE_FSYNC = 20, | 82 | FUSE_FSYNC = 20, |
83 | FUSE_SETXATTR = 21, | ||
84 | FUSE_GETXATTR = 22, | ||
85 | FUSE_LISTXATTR = 23, | ||
86 | FUSE_REMOVEXATTR = 24, | ||
83 | FUSE_FLUSH = 25, | 87 | FUSE_FLUSH = 25, |
84 | FUSE_INIT = 26 | 88 | FUSE_INIT = 26 |
85 | }; | 89 | }; |
@@ -89,6 +93,7 @@ enum fuse_opcode { | |||
89 | 93 | ||
90 | #define FUSE_NAME_MAX 1024 | 94 | #define FUSE_NAME_MAX 1024 |
91 | #define FUSE_SYMLINK_MAX 4096 | 95 | #define FUSE_SYMLINK_MAX 4096 |
96 | #define FUSE_XATTR_SIZE_MAX 4096 | ||
92 | 97 | ||
93 | struct fuse_entry_out { | 98 | struct fuse_entry_out { |
94 | __u64 nodeid; /* Inode ID */ | 99 | __u64 nodeid; /* Inode ID */ |
@@ -183,6 +188,19 @@ struct fuse_fsync_in { | |||
183 | __u32 fsync_flags; | 188 | __u32 fsync_flags; |
184 | }; | 189 | }; |
185 | 190 | ||
191 | struct fuse_setxattr_in { | ||
192 | __u32 size; | ||
193 | __u32 flags; | ||
194 | }; | ||
195 | |||
196 | struct fuse_getxattr_in { | ||
197 | __u32 size; | ||
198 | }; | ||
199 | |||
200 | struct fuse_getxattr_out { | ||
201 | __u32 size; | ||
202 | }; | ||
203 | |||
186 | struct fuse_init_in_out { | 204 | struct fuse_init_in_out { |
187 | __u32 major; | 205 | __u32 major; |
188 | __u32 minor; | 206 | __u32 minor; |