diff options
| author | Miklos Szeredi <miklos@szeredi.hu> | 2005-09-09 16:10:31 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-09-09 17:03:45 -0400 |
| commit | 92a8780e1136c5ca0c7ed940000d399943d1576e (patch) | |
| tree | b7fb327d66c06b47156f157c470f3ac7fed31682 | |
| parent | 1e9a4ed9396e9c31139721b639550ffb1df17065 (diff) | |
[PATCH] FUSE - extended attribute operations
This patch adds the extended attribute operations to FUSE.
The following operations are added:
o getxattr
o setxattr
o listxattr
o removexattr
Signed-off-by: Miklos Szeredi <miklos@szeredi.hu>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
| -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; |
