diff options
-rw-r--r-- | fs/cifs/Makefile | 3 | ||||
-rw-r--r-- | fs/cifs/cifsfs.c | 26 | ||||
-rw-r--r-- | fs/cifs/cifsfs.h | 12 | ||||
-rw-r--r-- | fs/cifs/xattr.c | 342 |
4 files changed, 165 insertions, 218 deletions
diff --git a/fs/cifs/Makefile b/fs/cifs/Makefile index 1964d212ab08..eed7eb09f46f 100644 --- a/fs/cifs/Makefile +++ b/fs/cifs/Makefile | |||
@@ -5,9 +5,10 @@ obj-$(CONFIG_CIFS) += cifs.o | |||
5 | 5 | ||
6 | cifs-y := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o \ | 6 | cifs-y := cifsfs.o cifssmb.o cifs_debug.o connect.o dir.o file.o inode.o \ |
7 | link.o misc.o netmisc.o smbencrypt.o transport.o asn1.o \ | 7 | link.o misc.o netmisc.o smbencrypt.o transport.o asn1.o \ |
8 | cifs_unicode.o nterr.o xattr.o cifsencrypt.o \ | 8 | cifs_unicode.o nterr.o cifsencrypt.o \ |
9 | readdir.o ioctl.o sess.o export.o smb1ops.o winucase.o | 9 | readdir.o ioctl.o sess.o export.o smb1ops.o winucase.o |
10 | 10 | ||
11 | cifs-$(CONFIG_CIFS_XATTR) += xattr.o | ||
11 | cifs-$(CONFIG_CIFS_ACL) += cifsacl.o | 12 | cifs-$(CONFIG_CIFS_ACL) += cifsacl.o |
12 | 13 | ||
13 | cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o | 14 | cifs-$(CONFIG_CIFS_UPCALL) += cifs_spnego.o |
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c index 1d86fc620e5c..43cc522b11e4 100644 --- a/fs/cifs/cifsfs.c +++ b/fs/cifs/cifsfs.c | |||
@@ -37,6 +37,7 @@ | |||
37 | #include <linux/freezer.h> | 37 | #include <linux/freezer.h> |
38 | #include <linux/namei.h> | 38 | #include <linux/namei.h> |
39 | #include <linux/random.h> | 39 | #include <linux/random.h> |
40 | #include <linux/xattr.h> | ||
40 | #include <net/ipv6.h> | 41 | #include <net/ipv6.h> |
41 | #include "cifsfs.h" | 42 | #include "cifsfs.h" |
42 | #include "cifspdu.h" | 43 | #include "cifspdu.h" |
@@ -135,6 +136,7 @@ cifs_read_super(struct super_block *sb) | |||
135 | 136 | ||
136 | sb->s_magic = CIFS_MAGIC_NUMBER; | 137 | sb->s_magic = CIFS_MAGIC_NUMBER; |
137 | sb->s_op = &cifs_super_ops; | 138 | sb->s_op = &cifs_super_ops; |
139 | sb->s_xattr = cifs_xattr_handlers; | ||
138 | sb->s_bdi = &cifs_sb->bdi; | 140 | sb->s_bdi = &cifs_sb->bdi; |
139 | sb->s_blocksize = CIFS_MAX_MSGSIZE; | 141 | sb->s_blocksize = CIFS_MAX_MSGSIZE; |
140 | sb->s_blocksize_bits = 14; /* default 2**14 = CIFS_MAX_MSGSIZE */ | 142 | sb->s_blocksize_bits = 14; /* default 2**14 = CIFS_MAX_MSGSIZE */ |
@@ -892,12 +894,10 @@ const struct inode_operations cifs_dir_inode_ops = { | |||
892 | .setattr = cifs_setattr, | 894 | .setattr = cifs_setattr, |
893 | .symlink = cifs_symlink, | 895 | .symlink = cifs_symlink, |
894 | .mknod = cifs_mknod, | 896 | .mknod = cifs_mknod, |
895 | #ifdef CONFIG_CIFS_XATTR | 897 | .setxattr = generic_setxattr, |
896 | .setxattr = cifs_setxattr, | 898 | .getxattr = generic_getxattr, |
897 | .getxattr = cifs_getxattr, | ||
898 | .listxattr = cifs_listxattr, | 899 | .listxattr = cifs_listxattr, |
899 | .removexattr = cifs_removexattr, | 900 | .removexattr = generic_removexattr, |
900 | #endif | ||
901 | }; | 901 | }; |
902 | 902 | ||
903 | const struct inode_operations cifs_file_inode_ops = { | 903 | const struct inode_operations cifs_file_inode_ops = { |
@@ -905,12 +905,10 @@ const struct inode_operations cifs_file_inode_ops = { | |||
905 | .setattr = cifs_setattr, | 905 | .setattr = cifs_setattr, |
906 | .getattr = cifs_getattr, /* do we need this anymore? */ | 906 | .getattr = cifs_getattr, /* do we need this anymore? */ |
907 | .permission = cifs_permission, | 907 | .permission = cifs_permission, |
908 | #ifdef CONFIG_CIFS_XATTR | 908 | .setxattr = generic_setxattr, |
909 | .setxattr = cifs_setxattr, | 909 | .getxattr = generic_getxattr, |
910 | .getxattr = cifs_getxattr, | ||
911 | .listxattr = cifs_listxattr, | 910 | .listxattr = cifs_listxattr, |
912 | .removexattr = cifs_removexattr, | 911 | .removexattr = generic_removexattr, |
913 | #endif | ||
914 | }; | 912 | }; |
915 | 913 | ||
916 | const struct inode_operations cifs_symlink_inode_ops = { | 914 | const struct inode_operations cifs_symlink_inode_ops = { |
@@ -920,12 +918,10 @@ const struct inode_operations cifs_symlink_inode_ops = { | |||
920 | /* BB add the following two eventually */ | 918 | /* BB add the following two eventually */ |
921 | /* revalidate: cifs_revalidate, | 919 | /* revalidate: cifs_revalidate, |
922 | setattr: cifs_notify_change, *//* BB do we need notify change */ | 920 | setattr: cifs_notify_change, *//* BB do we need notify change */ |
923 | #ifdef CONFIG_CIFS_XATTR | 921 | .setxattr = generic_setxattr, |
924 | .setxattr = cifs_setxattr, | 922 | .getxattr = generic_getxattr, |
925 | .getxattr = cifs_getxattr, | ||
926 | .listxattr = cifs_listxattr, | 923 | .listxattr = cifs_listxattr, |
927 | .removexattr = cifs_removexattr, | 924 | .removexattr = generic_removexattr, |
928 | #endif | ||
929 | }; | 925 | }; |
930 | 926 | ||
931 | static int cifs_clone_file_range(struct file *src_file, loff_t off, | 927 | static int cifs_clone_file_range(struct file *src_file, loff_t off, |
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h index c89ecd7a5c39..c1e749af749b 100644 --- a/fs/cifs/cifsfs.h +++ b/fs/cifs/cifsfs.h | |||
@@ -120,11 +120,15 @@ extern const char *cifs_get_link(struct dentry *, struct inode *, | |||
120 | struct delayed_call *); | 120 | struct delayed_call *); |
121 | extern int cifs_symlink(struct inode *inode, struct dentry *direntry, | 121 | extern int cifs_symlink(struct inode *inode, struct dentry *direntry, |
122 | const char *symname); | 122 | const char *symname); |
123 | extern int cifs_removexattr(struct dentry *, const char *); | 123 | |
124 | extern int cifs_setxattr(struct dentry *, const char *, const void *, | 124 | #ifdef CONFIG_CIFS_XATTR |
125 | size_t, int); | 125 | extern const struct xattr_handler *cifs_xattr_handlers[]; |
126 | extern ssize_t cifs_getxattr(struct dentry *, struct inode *, const char *, void *, size_t); | ||
127 | extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); | 126 | extern ssize_t cifs_listxattr(struct dentry *, char *, size_t); |
127 | #else | ||
128 | # define cifs_xattr_handlers NULL | ||
129 | # define cifs_listxattr NULL | ||
130 | #endif | ||
131 | |||
128 | extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); | 132 | extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg); |
129 | #ifdef CONFIG_CIFS_NFSD_EXPORT | 133 | #ifdef CONFIG_CIFS_NFSD_EXPORT |
130 | extern const struct export_operations cifs_export_ops; | 134 | extern const struct export_operations cifs_export_ops; |
diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c index 721c6db6fa81..c8b77aa24a1d 100644 --- a/fs/cifs/xattr.c +++ b/fs/cifs/xattr.c | |||
@@ -32,76 +32,19 @@ | |||
32 | #include "cifs_unicode.h" | 32 | #include "cifs_unicode.h" |
33 | 33 | ||
34 | #define MAX_EA_VALUE_SIZE 65535 | 34 | #define MAX_EA_VALUE_SIZE 65535 |
35 | #define CIFS_XATTR_DOS_ATTRIB "user.DosAttrib" | ||
36 | #define CIFS_XATTR_CIFS_ACL "system.cifs_acl" | 35 | #define CIFS_XATTR_CIFS_ACL "system.cifs_acl" |
37 | 36 | ||
38 | /* BB need to add server (Samba e.g) support for security and trusted prefix */ | 37 | /* BB need to add server (Samba e.g) support for security and trusted prefix */ |
39 | 38 | ||
40 | int cifs_removexattr(struct dentry *direntry, const char *ea_name) | 39 | enum { XATTR_USER, XATTR_CIFS_ACL, XATTR_ACL_ACCESS, XATTR_ACL_DEFAULT }; |
41 | { | ||
42 | int rc = -EOPNOTSUPP; | ||
43 | #ifdef CONFIG_CIFS_XATTR | ||
44 | unsigned int xid; | ||
45 | struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb); | ||
46 | struct tcon_link *tlink; | ||
47 | struct cifs_tcon *pTcon; | ||
48 | char *full_path = NULL; | ||
49 | |||
50 | tlink = cifs_sb_tlink(cifs_sb); | ||
51 | if (IS_ERR(tlink)) | ||
52 | return PTR_ERR(tlink); | ||
53 | pTcon = tlink_tcon(tlink); | ||
54 | 40 | ||
55 | xid = get_xid(); | 41 | static int cifs_xattr_set(const struct xattr_handler *handler, |
56 | 42 | struct dentry *dentry, const char *name, | |
57 | full_path = build_path_from_dentry(direntry); | 43 | const void *value, size_t size, int flags) |
58 | if (full_path == NULL) { | ||
59 | rc = -ENOMEM; | ||
60 | goto remove_ea_exit; | ||
61 | } | ||
62 | if (ea_name == NULL) { | ||
63 | cifs_dbg(FYI, "Null xattr names not supported\n"); | ||
64 | } else if (!strncmp(ea_name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) { | ||
65 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) | ||
66 | goto remove_ea_exit; | ||
67 | |||
68 | ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */ | ||
69 | if (pTcon->ses->server->ops->set_EA) | ||
70 | rc = pTcon->ses->server->ops->set_EA(xid, pTcon, | ||
71 | full_path, ea_name, NULL, (__u16)0, | ||
72 | cifs_sb->local_nls, cifs_remap(cifs_sb)); | ||
73 | } else if (!strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN)) { | ||
74 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) | ||
75 | goto remove_ea_exit; | ||
76 | |||
77 | ea_name += XATTR_OS2_PREFIX_LEN; /* skip past os2. prefix */ | ||
78 | if (pTcon->ses->server->ops->set_EA) | ||
79 | rc = pTcon->ses->server->ops->set_EA(xid, pTcon, | ||
80 | full_path, ea_name, NULL, (__u16)0, | ||
81 | cifs_sb->local_nls, cifs_remap(cifs_sb)); | ||
82 | } else { | ||
83 | cifs_dbg(FYI, | ||
84 | "illegal xattr request %s (only user namespace supported)\n", | ||
85 | ea_name); | ||
86 | /* BB what if no namespace prefix? */ | ||
87 | /* Should we just pass them to server, except for | ||
88 | system and perhaps security prefixes? */ | ||
89 | } | ||
90 | remove_ea_exit: | ||
91 | kfree(full_path); | ||
92 | free_xid(xid); | ||
93 | cifs_put_tlink(tlink); | ||
94 | #endif | ||
95 | return rc; | ||
96 | } | ||
97 | |||
98 | int cifs_setxattr(struct dentry *direntry, const char *ea_name, | ||
99 | const void *ea_value, size_t value_size, int flags) | ||
100 | { | 44 | { |
101 | int rc = -EOPNOTSUPP; | 45 | int rc = -EOPNOTSUPP; |
102 | #ifdef CONFIG_CIFS_XATTR | ||
103 | unsigned int xid; | 46 | unsigned int xid; |
104 | struct super_block *sb = direntry->d_sb; | 47 | struct super_block *sb = dentry->d_sb; |
105 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | 48 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
106 | struct tcon_link *tlink; | 49 | struct tcon_link *tlink; |
107 | struct cifs_tcon *pTcon; | 50 | struct cifs_tcon *pTcon; |
@@ -114,10 +57,10 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name, | |||
114 | 57 | ||
115 | xid = get_xid(); | 58 | xid = get_xid(); |
116 | 59 | ||
117 | full_path = build_path_from_dentry(direntry); | 60 | full_path = build_path_from_dentry(dentry); |
118 | if (full_path == NULL) { | 61 | if (full_path == NULL) { |
119 | rc = -ENOMEM; | 62 | rc = -ENOMEM; |
120 | goto set_ea_exit; | 63 | goto out; |
121 | } | 64 | } |
122 | /* return dos attributes as pseudo xattr */ | 65 | /* return dos attributes as pseudo xattr */ |
123 | /* return alt name if available as pseudo attr */ | 66 | /* return alt name if available as pseudo attr */ |
@@ -125,104 +68,88 @@ int cifs_setxattr(struct dentry *direntry, const char *ea_name, | |||
125 | /* if proc/fs/cifs/streamstoxattr is set then | 68 | /* if proc/fs/cifs/streamstoxattr is set then |
126 | search server for EAs or streams to | 69 | search server for EAs or streams to |
127 | returns as xattrs */ | 70 | returns as xattrs */ |
128 | if (value_size > MAX_EA_VALUE_SIZE) { | 71 | if (size > MAX_EA_VALUE_SIZE) { |
129 | cifs_dbg(FYI, "size of EA value too large\n"); | 72 | cifs_dbg(FYI, "size of EA value too large\n"); |
130 | rc = -EOPNOTSUPP; | 73 | rc = -EOPNOTSUPP; |
131 | goto set_ea_exit; | 74 | goto out; |
132 | } | 75 | } |
133 | 76 | ||
134 | if (ea_name == NULL) { | 77 | switch (handler->flags) { |
135 | cifs_dbg(FYI, "Null xattr names not supported\n"); | 78 | case XATTR_USER: |
136 | } else if (strncmp(ea_name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) | ||
137 | == 0) { | ||
138 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) | 79 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) |
139 | goto set_ea_exit; | 80 | goto out; |
140 | if (strcmp(ea_name, CIFS_XATTR_DOS_ATTRIB) == 0) | ||
141 | cifs_dbg(FYI, "attempt to set cifs inode metadata\n"); | ||
142 | 81 | ||
143 | ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */ | ||
144 | if (pTcon->ses->server->ops->set_EA) | 82 | if (pTcon->ses->server->ops->set_EA) |
145 | rc = pTcon->ses->server->ops->set_EA(xid, pTcon, | 83 | rc = pTcon->ses->server->ops->set_EA(xid, pTcon, |
146 | full_path, ea_name, ea_value, (__u16)value_size, | 84 | full_path, name, value, (__u16)size, |
147 | cifs_sb->local_nls, cifs_remap(cifs_sb)); | 85 | cifs_sb->local_nls, cifs_remap(cifs_sb)); |
148 | } else if (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) | 86 | break; |
149 | == 0) { | ||
150 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) | ||
151 | goto set_ea_exit; | ||
152 | 87 | ||
153 | ea_name += XATTR_OS2_PREFIX_LEN; /* skip past os2. prefix */ | 88 | case XATTR_CIFS_ACL: { |
154 | if (pTcon->ses->server->ops->set_EA) | ||
155 | rc = pTcon->ses->server->ops->set_EA(xid, pTcon, | ||
156 | full_path, ea_name, ea_value, (__u16)value_size, | ||
157 | cifs_sb->local_nls, cifs_remap(cifs_sb)); | ||
158 | } else if (strcmp(ea_name, CIFS_XATTR_CIFS_ACL) == 0) { | ||
159 | #ifdef CONFIG_CIFS_ACL | 89 | #ifdef CONFIG_CIFS_ACL |
160 | struct cifs_ntsd *pacl; | 90 | struct cifs_ntsd *pacl; |
161 | pacl = kmalloc(value_size, GFP_KERNEL); | 91 | |
92 | if (!value) | ||
93 | goto out; | ||
94 | pacl = kmalloc(size, GFP_KERNEL); | ||
162 | if (!pacl) { | 95 | if (!pacl) { |
163 | rc = -ENOMEM; | 96 | rc = -ENOMEM; |
164 | } else { | 97 | } else { |
165 | memcpy(pacl, ea_value, value_size); | 98 | memcpy(pacl, value, size); |
166 | if (pTcon->ses->server->ops->set_acl) | 99 | if (value && |
100 | pTcon->ses->server->ops->set_acl) | ||
167 | rc = pTcon->ses->server->ops->set_acl(pacl, | 101 | rc = pTcon->ses->server->ops->set_acl(pacl, |
168 | value_size, d_inode(direntry), | 102 | size, d_inode(dentry), |
169 | full_path, CIFS_ACL_DACL); | 103 | full_path, CIFS_ACL_DACL); |
170 | else | 104 | else |
171 | rc = -EOPNOTSUPP; | 105 | rc = -EOPNOTSUPP; |
172 | if (rc == 0) /* force revalidate of the inode */ | 106 | if (rc == 0) /* force revalidate of the inode */ |
173 | CIFS_I(d_inode(direntry))->time = 0; | 107 | CIFS_I(d_inode(dentry))->time = 0; |
174 | kfree(pacl); | 108 | kfree(pacl); |
175 | } | 109 | } |
176 | #else | ||
177 | cifs_dbg(FYI, "Set CIFS ACL not supported yet\n"); | ||
178 | #endif /* CONFIG_CIFS_ACL */ | 110 | #endif /* CONFIG_CIFS_ACL */ |
179 | } else { | 111 | break; |
180 | if (strcmp(ea_name, XATTR_NAME_POSIX_ACL_ACCESS) == 0) { | 112 | } |
113 | |||
114 | case XATTR_ACL_ACCESS: | ||
181 | #ifdef CONFIG_CIFS_POSIX | 115 | #ifdef CONFIG_CIFS_POSIX |
182 | if (sb->s_flags & MS_POSIXACL) | 116 | if (!value) |
183 | rc = CIFSSMBSetPosixACL(xid, pTcon, full_path, | 117 | goto out; |
184 | ea_value, (const int)value_size, | 118 | if (sb->s_flags & MS_POSIXACL) |
185 | ACL_TYPE_ACCESS, cifs_sb->local_nls, | 119 | rc = CIFSSMBSetPosixACL(xid, pTcon, full_path, |
186 | cifs_remap(cifs_sb)); | 120 | value, (const int)size, |
187 | cifs_dbg(FYI, "set POSIX ACL rc %d\n", rc); | 121 | ACL_TYPE_ACCESS, cifs_sb->local_nls, |
188 | #else | 122 | cifs_remap(cifs_sb)); |
189 | cifs_dbg(FYI, "set POSIX ACL not supported\n"); | 123 | #endif /* CONFIG_CIFS_POSIX */ |
190 | #endif | 124 | break; |
191 | } else if (strcmp(ea_name, XATTR_NAME_POSIX_ACL_DEFAULT) == 0) { | 125 | |
126 | case XATTR_ACL_DEFAULT: | ||
192 | #ifdef CONFIG_CIFS_POSIX | 127 | #ifdef CONFIG_CIFS_POSIX |
193 | if (sb->s_flags & MS_POSIXACL) | 128 | if (!value) |
194 | rc = CIFSSMBSetPosixACL(xid, pTcon, full_path, | 129 | goto out; |
195 | ea_value, (const int)value_size, | 130 | if (sb->s_flags & MS_POSIXACL) |
196 | ACL_TYPE_DEFAULT, cifs_sb->local_nls, | 131 | rc = CIFSSMBSetPosixACL(xid, pTcon, full_path, |
197 | cifs_remap(cifs_sb)); | 132 | value, (const int)size, |
198 | cifs_dbg(FYI, "set POSIX default ACL rc %d\n", rc); | 133 | ACL_TYPE_DEFAULT, cifs_sb->local_nls, |
199 | #else | 134 | cifs_remap(cifs_sb)); |
200 | cifs_dbg(FYI, "set default POSIX ACL not supported\n"); | 135 | #endif /* CONFIG_CIFS_POSIX */ |
201 | #endif | 136 | break; |
202 | } else { | ||
203 | cifs_dbg(FYI, "illegal xattr request %s (only user namespace supported)\n", | ||
204 | ea_name); | ||
205 | /* BB what if no namespace prefix? */ | ||
206 | /* Should we just pass them to server, except for | ||
207 | system and perhaps security prefixes? */ | ||
208 | } | ||
209 | } | 137 | } |
210 | 138 | ||
211 | set_ea_exit: | 139 | out: |
212 | kfree(full_path); | 140 | kfree(full_path); |
213 | free_xid(xid); | 141 | free_xid(xid); |
214 | cifs_put_tlink(tlink); | 142 | cifs_put_tlink(tlink); |
215 | #endif | ||
216 | return rc; | 143 | return rc; |
217 | } | 144 | } |
218 | 145 | ||
219 | ssize_t cifs_getxattr(struct dentry *direntry, struct inode *inode, | 146 | static int cifs_xattr_get(const struct xattr_handler *handler, |
220 | const char *ea_name, void *ea_value, size_t buf_size) | 147 | struct dentry *dentry, struct inode *inode, |
148 | const char *name, void *value, size_t size) | ||
221 | { | 149 | { |
222 | ssize_t rc = -EOPNOTSUPP; | 150 | ssize_t rc = -EOPNOTSUPP; |
223 | #ifdef CONFIG_CIFS_XATTR | ||
224 | unsigned int xid; | 151 | unsigned int xid; |
225 | struct super_block *sb = direntry->d_sb; | 152 | struct super_block *sb = dentry->d_sb; |
226 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); | 153 | struct cifs_sb_info *cifs_sb = CIFS_SB(sb); |
227 | struct tcon_link *tlink; | 154 | struct tcon_link *tlink; |
228 | struct cifs_tcon *pTcon; | 155 | struct cifs_tcon *pTcon; |
@@ -235,95 +162,72 @@ ssize_t cifs_getxattr(struct dentry *direntry, struct inode *inode, | |||
235 | 162 | ||
236 | xid = get_xid(); | 163 | xid = get_xid(); |
237 | 164 | ||
238 | full_path = build_path_from_dentry(direntry); | 165 | full_path = build_path_from_dentry(dentry); |
239 | if (full_path == NULL) { | 166 | if (full_path == NULL) { |
240 | rc = -ENOMEM; | 167 | rc = -ENOMEM; |
241 | goto get_ea_exit; | 168 | goto out; |
242 | } | 169 | } |
243 | /* return dos attributes as pseudo xattr */ | 170 | /* return dos attributes as pseudo xattr */ |
244 | /* return alt name if available as pseudo attr */ | 171 | /* return alt name if available as pseudo attr */ |
245 | if (ea_name == NULL) { | 172 | switch (handler->flags) { |
246 | cifs_dbg(FYI, "Null xattr names not supported\n"); | 173 | case XATTR_USER: |
247 | } else if (strncmp(ea_name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN) | ||
248 | == 0) { | ||
249 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) | 174 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) |
250 | goto get_ea_exit; | 175 | goto out; |
251 | 176 | ||
252 | if (strcmp(ea_name, CIFS_XATTR_DOS_ATTRIB) == 0) { | ||
253 | cifs_dbg(FYI, "attempt to query cifs inode metadata\n"); | ||
254 | /* revalidate/getattr then populate from inode */ | ||
255 | } /* BB add else when above is implemented */ | ||
256 | ea_name += XATTR_USER_PREFIX_LEN; /* skip past user. prefix */ | ||
257 | if (pTcon->ses->server->ops->query_all_EAs) | 177 | if (pTcon->ses->server->ops->query_all_EAs) |
258 | rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon, | 178 | rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon, |
259 | full_path, ea_name, ea_value, buf_size, | 179 | full_path, name, value, size, |
260 | cifs_sb->local_nls, cifs_remap(cifs_sb)); | 180 | cifs_sb->local_nls, cifs_remap(cifs_sb)); |
261 | } else if (strncmp(ea_name, XATTR_OS2_PREFIX, XATTR_OS2_PREFIX_LEN) == 0) { | 181 | break; |
262 | if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) | ||
263 | goto get_ea_exit; | ||
264 | 182 | ||
265 | ea_name += XATTR_OS2_PREFIX_LEN; /* skip past os2. prefix */ | 183 | case XATTR_CIFS_ACL: { |
266 | if (pTcon->ses->server->ops->query_all_EAs) | 184 | #ifdef CONFIG_CIFS_ACL |
267 | rc = pTcon->ses->server->ops->query_all_EAs(xid, pTcon, | 185 | u32 acllen; |
268 | full_path, ea_name, ea_value, buf_size, | 186 | struct cifs_ntsd *pacl; |
269 | cifs_sb->local_nls, cifs_remap(cifs_sb)); | 187 | |
270 | } else if (strcmp(ea_name, XATTR_NAME_POSIX_ACL_ACCESS) == 0) { | 188 | if (pTcon->ses->server->ops->get_acl == NULL) |
189 | goto out; /* rc already EOPNOTSUPP */ | ||
190 | |||
191 | pacl = pTcon->ses->server->ops->get_acl(cifs_sb, | ||
192 | inode, full_path, &acllen); | ||
193 | if (IS_ERR(pacl)) { | ||
194 | rc = PTR_ERR(pacl); | ||
195 | cifs_dbg(VFS, "%s: error %zd getting sec desc\n", | ||
196 | __func__, rc); | ||
197 | } else { | ||
198 | if (value) { | ||
199 | if (acllen > size) | ||
200 | acllen = -ERANGE; | ||
201 | else | ||
202 | memcpy(value, pacl, acllen); | ||
203 | } | ||
204 | rc = acllen; | ||
205 | kfree(pacl); | ||
206 | } | ||
207 | #endif /* CONFIG_CIFS_ACL */ | ||
208 | break; | ||
209 | } | ||
210 | |||
211 | case XATTR_ACL_ACCESS: | ||
271 | #ifdef CONFIG_CIFS_POSIX | 212 | #ifdef CONFIG_CIFS_POSIX |
272 | if (sb->s_flags & MS_POSIXACL) | 213 | if (sb->s_flags & MS_POSIXACL) |
273 | rc = CIFSSMBGetPosixACL(xid, pTcon, full_path, | 214 | rc = CIFSSMBGetPosixACL(xid, pTcon, full_path, |
274 | ea_value, buf_size, ACL_TYPE_ACCESS, | 215 | value, size, ACL_TYPE_ACCESS, |
275 | cifs_sb->local_nls, | 216 | cifs_sb->local_nls, |
276 | cifs_remap(cifs_sb)); | 217 | cifs_remap(cifs_sb)); |
277 | #else | 218 | #endif /* CONFIG_CIFS_POSIX */ |
278 | cifs_dbg(FYI, "Query POSIX ACL not supported yet\n"); | 219 | break; |
279 | #endif /* CONFIG_CIFS_POSIX */ | 220 | |
280 | } else if (strcmp(ea_name, XATTR_NAME_POSIX_ACL_DEFAULT) == 0) { | 221 | case XATTR_ACL_DEFAULT: |
281 | #ifdef CONFIG_CIFS_POSIX | 222 | #ifdef CONFIG_CIFS_POSIX |
282 | if (sb->s_flags & MS_POSIXACL) | 223 | if (sb->s_flags & MS_POSIXACL) |
283 | rc = CIFSSMBGetPosixACL(xid, pTcon, full_path, | 224 | rc = CIFSSMBGetPosixACL(xid, pTcon, full_path, |
284 | ea_value, buf_size, ACL_TYPE_DEFAULT, | 225 | value, size, ACL_TYPE_DEFAULT, |
285 | cifs_sb->local_nls, | 226 | cifs_sb->local_nls, |
286 | cifs_remap(cifs_sb)); | 227 | cifs_remap(cifs_sb)); |
287 | #else | 228 | #endif /* CONFIG_CIFS_POSIX */ |
288 | cifs_dbg(FYI, "Query POSIX default ACL not supported yet\n"); | 229 | break; |
289 | #endif /* CONFIG_CIFS_POSIX */ | 230 | } |
290 | } else if (strcmp(ea_name, CIFS_XATTR_CIFS_ACL) == 0) { | ||
291 | #ifdef CONFIG_CIFS_ACL | ||
292 | u32 acllen; | ||
293 | struct cifs_ntsd *pacl; | ||
294 | |||
295 | if (pTcon->ses->server->ops->get_acl == NULL) | ||
296 | goto get_ea_exit; /* rc already EOPNOTSUPP */ | ||
297 | |||
298 | pacl = pTcon->ses->server->ops->get_acl(cifs_sb, | ||
299 | inode, full_path, &acllen); | ||
300 | if (IS_ERR(pacl)) { | ||
301 | rc = PTR_ERR(pacl); | ||
302 | cifs_dbg(VFS, "%s: error %zd getting sec desc\n", | ||
303 | __func__, rc); | ||
304 | } else { | ||
305 | if (ea_value) { | ||
306 | if (acllen > buf_size) | ||
307 | acllen = -ERANGE; | ||
308 | else | ||
309 | memcpy(ea_value, pacl, acllen); | ||
310 | } | ||
311 | rc = acllen; | ||
312 | kfree(pacl); | ||
313 | } | ||
314 | #else | ||
315 | cifs_dbg(FYI, "Query CIFS ACL not supported yet\n"); | ||
316 | #endif /* CONFIG_CIFS_ACL */ | ||
317 | } else if (strncmp(ea_name, | ||
318 | XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) == 0) { | ||
319 | cifs_dbg(FYI, "Trusted xattr namespace not supported yet\n"); | ||
320 | } else if (strncmp(ea_name, | ||
321 | XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) == 0) { | ||
322 | cifs_dbg(FYI, "Security xattr namespace not supported yet\n"); | ||
323 | } else | ||
324 | cifs_dbg(FYI, | ||
325 | "illegal xattr request %s (only user namespace supported)\n", | ||
326 | ea_name); | ||
327 | 231 | ||
328 | /* We could add an additional check for streams ie | 232 | /* We could add an additional check for streams ie |
329 | if proc/fs/cifs/streamstoxattr is set then | 233 | if proc/fs/cifs/streamstoxattr is set then |
@@ -333,18 +237,16 @@ ssize_t cifs_getxattr(struct dentry *direntry, struct inode *inode, | |||
333 | if (rc == -EINVAL) | 237 | if (rc == -EINVAL) |
334 | rc = -EOPNOTSUPP; | 238 | rc = -EOPNOTSUPP; |
335 | 239 | ||
336 | get_ea_exit: | 240 | out: |
337 | kfree(full_path); | 241 | kfree(full_path); |
338 | free_xid(xid); | 242 | free_xid(xid); |
339 | cifs_put_tlink(tlink); | 243 | cifs_put_tlink(tlink); |
340 | #endif | ||
341 | return rc; | 244 | return rc; |
342 | } | 245 | } |
343 | 246 | ||
344 | ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size) | 247 | ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size) |
345 | { | 248 | { |
346 | ssize_t rc = -EOPNOTSUPP; | 249 | ssize_t rc = -EOPNOTSUPP; |
347 | #ifdef CONFIG_CIFS_XATTR | ||
348 | unsigned int xid; | 250 | unsigned int xid; |
349 | struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb); | 251 | struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb); |
350 | struct tcon_link *tlink; | 252 | struct tcon_link *tlink; |
@@ -381,6 +283,50 @@ list_ea_exit: | |||
381 | kfree(full_path); | 283 | kfree(full_path); |
382 | free_xid(xid); | 284 | free_xid(xid); |
383 | cifs_put_tlink(tlink); | 285 | cifs_put_tlink(tlink); |
384 | #endif | ||
385 | return rc; | 286 | return rc; |
386 | } | 287 | } |
288 | |||
289 | static const struct xattr_handler cifs_user_xattr_handler = { | ||
290 | .prefix = XATTR_USER_PREFIX, | ||
291 | .flags = XATTR_USER, | ||
292 | .get = cifs_xattr_get, | ||
293 | .set = cifs_xattr_set, | ||
294 | }; | ||
295 | |||
296 | /* os2.* attributes are treated like user.* attributes */ | ||
297 | static const struct xattr_handler cifs_os2_xattr_handler = { | ||
298 | .prefix = XATTR_OS2_PREFIX, | ||
299 | .flags = XATTR_USER, | ||
300 | .get = cifs_xattr_get, | ||
301 | .set = cifs_xattr_set, | ||
302 | }; | ||
303 | |||
304 | static const struct xattr_handler cifs_cifs_acl_xattr_handler = { | ||
305 | .name = CIFS_XATTR_CIFS_ACL, | ||
306 | .flags = XATTR_CIFS_ACL, | ||
307 | .get = cifs_xattr_get, | ||
308 | .set = cifs_xattr_set, | ||
309 | }; | ||
310 | |||
311 | static const struct xattr_handler cifs_posix_acl_access_xattr_handler = { | ||
312 | .name = XATTR_NAME_POSIX_ACL_ACCESS, | ||
313 | .flags = XATTR_ACL_ACCESS, | ||
314 | .get = cifs_xattr_get, | ||
315 | .set = cifs_xattr_set, | ||
316 | }; | ||
317 | |||
318 | static const struct xattr_handler cifs_posix_acl_default_xattr_handler = { | ||
319 | .name = XATTR_NAME_POSIX_ACL_DEFAULT, | ||
320 | .flags = XATTR_ACL_DEFAULT, | ||
321 | .get = cifs_xattr_get, | ||
322 | .set = cifs_xattr_set, | ||
323 | }; | ||
324 | |||
325 | const struct xattr_handler *cifs_xattr_handlers[] = { | ||
326 | &cifs_user_xattr_handler, | ||
327 | &cifs_os2_xattr_handler, | ||
328 | &cifs_cifs_acl_xattr_handler, | ||
329 | &cifs_posix_acl_access_xattr_handler, | ||
330 | &cifs_posix_acl_default_xattr_handler, | ||
331 | NULL | ||
332 | }; | ||