diff options
Diffstat (limited to 'fs/cifs/xattr.c')
-rw-r--r-- | fs/cifs/xattr.c | 334 |
1 files changed, 334 insertions, 0 deletions
diff --git a/fs/cifs/xattr.c b/fs/cifs/xattr.c new file mode 100644 index 000000000000..549afa184fd6 --- /dev/null +++ b/fs/cifs/xattr.c | |||
@@ -0,0 +1,334 @@ | |||
1 | /* | ||
2 | * fs/cifs/xattr.c | ||
3 | * | ||
4 | * Copyright (c) International Business Machines Corp., 2003 | ||
5 | * Author(s): Steve French (sfrench@us.ibm.com) | ||
6 | * | ||
7 | * This library is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU Lesser General Public License as published | ||
9 | * by the Free Software Foundation; either version 2.1 of the License, or | ||
10 | * (at your option) any later version. | ||
11 | * | ||
12 | * This library is distributed in the hope that it will be useful, | ||
13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | ||
15 | * the GNU Lesser General Public License for more details. | ||
16 | * | ||
17 | * You should have received a copy of the GNU Lesser General Public License | ||
18 | * along with this library; if not, write to the Free Software | ||
19 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
20 | */ | ||
21 | |||
22 | #include <linux/fs.h> | ||
23 | #include <linux/posix_acl_xattr.h> | ||
24 | #include "cifsfs.h" | ||
25 | #include "cifspdu.h" | ||
26 | #include "cifsglob.h" | ||
27 | #include "cifsproto.h" | ||
28 | #include "cifs_debug.h" | ||
29 | |||
30 | #define MAX_EA_VALUE_SIZE 65535 | ||
31 | #define CIFS_XATTR_DOS_ATTRIB "user.DosAttrib" | ||
32 | #define CIFS_XATTR_USER_PREFIX "user." | ||
33 | #define CIFS_XATTR_SYSTEM_PREFIX "system." | ||
34 | #define CIFS_XATTR_OS2_PREFIX "os2." | ||
35 | #define CIFS_XATTR_SECURITY_PREFIX ".security" | ||
36 | #define CIFS_XATTR_TRUSTED_PREFIX "trusted." | ||
37 | #define XATTR_TRUSTED_PREFIX_LEN 8 | ||
38 | #define XATTR_SECURITY_PREFIX_LEN 9 | ||
39 | /* BB need to add server (Samba e.g) support for security and trusted prefix */ | ||
40 | |||
41 | |||
42 | |||
43 | int cifs_removexattr(struct dentry * direntry, const char * ea_name) | ||
44 | { | ||
45 | int rc = -EOPNOTSUPP; | ||
46 | #ifdef CONFIG_CIFS_XATTR | ||
47 | int xid; | ||
48 | struct cifs_sb_info *cifs_sb; | ||
49 | struct cifsTconInfo *pTcon; | ||
50 | struct super_block * sb; | ||
51 | char * full_path; | ||
52 | |||
53 | if(direntry == NULL) | ||
54 | return -EIO; | ||
55 | if(direntry->d_inode == NULL) | ||
56 | return -EIO; | ||
57 | sb = direntry->d_inode->i_sb; | ||
58 | if(sb == NULL) | ||
59 | return -EIO; | ||
60 | xid = GetXid(); | ||
61 | |||
62 | cifs_sb = CIFS_SB(sb); | ||
63 | pTcon = cifs_sb->tcon; | ||
64 | |||
65 | down(&sb->s_vfs_rename_sem); | ||
66 | full_path = build_path_from_dentry(direntry); | ||
67 | up(&sb->s_vfs_rename_sem); | ||
68 | if(full_path == NULL) { | ||
69 | FreeXid(xid); | ||
70 | return -ENOMEM; | ||
71 | } | ||
72 | if(ea_name == NULL) { | ||
73 | cFYI(1,("Null xattr names not supported")); | ||
74 | } else if(strncmp(ea_name,CIFS_XATTR_USER_PREFIX,5) | ||
75 | && (strncmp(ea_name,CIFS_XATTR_OS2_PREFIX,4))) { | ||
76 | cFYI(1,("illegal xattr namespace %s (only user namespace supported)",ea_name)); | ||
77 | /* BB what if no namespace prefix? */ | ||
78 | /* Should we just pass them to server, except for | ||
79 | system and perhaps security prefixes? */ | ||
80 | } else { | ||
81 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) | ||
82 | goto remove_ea_exit; | ||
83 | |||
84 | ea_name+=5; /* skip past user. prefix */ | ||
85 | rc = CIFSSMBSetEA(xid,pTcon,full_path,ea_name,NULL, | ||
86 | (__u16)0, cifs_sb->local_nls); | ||
87 | } | ||
88 | remove_ea_exit: | ||
89 | if (full_path) | ||
90 | kfree(full_path); | ||
91 | FreeXid(xid); | ||
92 | #endif | ||
93 | return rc; | ||
94 | } | ||
95 | |||
96 | int cifs_setxattr(struct dentry * direntry, const char * ea_name, | ||
97 | const void * ea_value, size_t value_size, int flags) | ||
98 | { | ||
99 | int rc = -EOPNOTSUPP; | ||
100 | #ifdef CONFIG_CIFS_XATTR | ||
101 | int xid; | ||
102 | struct cifs_sb_info *cifs_sb; | ||
103 | struct cifsTconInfo *pTcon; | ||
104 | struct super_block * sb; | ||
105 | char * full_path; | ||
106 | |||
107 | if(direntry == NULL) | ||
108 | return -EIO; | ||
109 | if(direntry->d_inode == NULL) | ||
110 | return -EIO; | ||
111 | sb = direntry->d_inode->i_sb; | ||
112 | if(sb == NULL) | ||
113 | return -EIO; | ||
114 | xid = GetXid(); | ||
115 | |||
116 | cifs_sb = CIFS_SB(sb); | ||
117 | pTcon = cifs_sb->tcon; | ||
118 | |||
119 | down(&sb->s_vfs_rename_sem); | ||
120 | full_path = build_path_from_dentry(direntry); | ||
121 | up(&sb->s_vfs_rename_sem); | ||
122 | if(full_path == NULL) { | ||
123 | FreeXid(xid); | ||
124 | return -ENOMEM; | ||
125 | } | ||
126 | /* return dos attributes as pseudo xattr */ | ||
127 | /* return alt name if available as pseudo attr */ | ||
128 | |||
129 | /* if proc/fs/cifs/streamstoxattr is set then | ||
130 | search server for EAs or streams to | ||
131 | returns as xattrs */ | ||
132 | if(value_size > MAX_EA_VALUE_SIZE) { | ||
133 | cFYI(1,("size of EA value too large")); | ||
134 | if(full_path) | ||
135 | kfree(full_path); | ||
136 | FreeXid(xid); | ||
137 | return -EOPNOTSUPP; | ||
138 | } | ||
139 | |||
140 | if(ea_name == NULL) { | ||
141 | cFYI(1,("Null xattr names not supported")); | ||
142 | } else if(strncmp(ea_name,CIFS_XATTR_USER_PREFIX,5) == 0) { | ||
143 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) | ||
144 | goto set_ea_exit; | ||
145 | if(strncmp(ea_name,CIFS_XATTR_DOS_ATTRIB,14) == 0) { | ||
146 | cFYI(1,("attempt to set cifs inode metadata")); | ||
147 | } | ||
148 | ea_name += 5; /* skip past user. prefix */ | ||
149 | rc = CIFSSMBSetEA(xid,pTcon,full_path,ea_name,ea_value, | ||
150 | (__u16)value_size, cifs_sb->local_nls); | ||
151 | } else if(strncmp(ea_name, CIFS_XATTR_OS2_PREFIX,4) == 0) { | ||
152 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) | ||
153 | goto set_ea_exit; | ||
154 | |||
155 | ea_name += 4; /* skip past os2. prefix */ | ||
156 | rc = CIFSSMBSetEA(xid,pTcon,full_path,ea_name,ea_value, | ||
157 | (__u16)value_size, cifs_sb->local_nls); | ||
158 | } else { | ||
159 | int temp; | ||
160 | temp = strncmp(ea_name,POSIX_ACL_XATTR_ACCESS, | ||
161 | strlen(POSIX_ACL_XATTR_ACCESS)); | ||
162 | if (temp == 0) { | ||
163 | #ifdef CONFIG_CIFS_POSIX | ||
164 | rc = CIFSSMBSetPosixACL(xid, pTcon,full_path,ea_value, | ||
165 | (const int)value_size, ACL_TYPE_ACCESS, | ||
166 | cifs_sb->local_nls); | ||
167 | cFYI(1,("set POSIX ACL rc %d",rc)); | ||
168 | #else | ||
169 | cFYI(1,("set POSIX ACL not supported")); | ||
170 | #endif | ||
171 | } else if(strncmp(ea_name,POSIX_ACL_XATTR_DEFAULT,strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) { | ||
172 | #ifdef CONFIG_CIFS_POSIX | ||
173 | rc = CIFSSMBSetPosixACL(xid, pTcon,full_path,ea_value, | ||
174 | (const int)value_size, ACL_TYPE_DEFAULT, | ||
175 | cifs_sb->local_nls); | ||
176 | cFYI(1,("set POSIX default ACL rc %d",rc)); | ||
177 | #else | ||
178 | cFYI(1,("set default POSIX ACL not supported")); | ||
179 | #endif | ||
180 | } else { | ||
181 | cFYI(1,("illegal xattr request %s (only user namespace supported)",ea_name)); | ||
182 | /* BB what if no namespace prefix? */ | ||
183 | /* Should we just pass them to server, except for | ||
184 | system and perhaps security prefixes? */ | ||
185 | } | ||
186 | } | ||
187 | |||
188 | set_ea_exit: | ||
189 | if (full_path) | ||
190 | kfree(full_path); | ||
191 | FreeXid(xid); | ||
192 | #endif | ||
193 | return rc; | ||
194 | } | ||
195 | |||
196 | ssize_t cifs_getxattr(struct dentry * direntry, const char * ea_name, | ||
197 | void * ea_value, size_t buf_size) | ||
198 | { | ||
199 | ssize_t rc = -EOPNOTSUPP; | ||
200 | #ifdef CONFIG_CIFS_XATTR | ||
201 | int xid; | ||
202 | struct cifs_sb_info *cifs_sb; | ||
203 | struct cifsTconInfo *pTcon; | ||
204 | struct super_block * sb; | ||
205 | char * full_path; | ||
206 | |||
207 | if(direntry == NULL) | ||
208 | return -EIO; | ||
209 | if(direntry->d_inode == NULL) | ||
210 | return -EIO; | ||
211 | sb = direntry->d_inode->i_sb; | ||
212 | if(sb == NULL) | ||
213 | return -EIO; | ||
214 | |||
215 | xid = GetXid(); | ||
216 | |||
217 | cifs_sb = CIFS_SB(sb); | ||
218 | pTcon = cifs_sb->tcon; | ||
219 | |||
220 | down(&sb->s_vfs_rename_sem); | ||
221 | full_path = build_path_from_dentry(direntry); | ||
222 | up(&sb->s_vfs_rename_sem); | ||
223 | if(full_path == NULL) { | ||
224 | FreeXid(xid); | ||
225 | return -ENOMEM; | ||
226 | } | ||
227 | /* return dos attributes as pseudo xattr */ | ||
228 | /* return alt name if available as pseudo attr */ | ||
229 | if(ea_name == NULL) { | ||
230 | cFYI(1,("Null xattr names not supported")); | ||
231 | } else if(strncmp(ea_name,CIFS_XATTR_USER_PREFIX,5) == 0) { | ||
232 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) | ||
233 | goto get_ea_exit; | ||
234 | |||
235 | if(strncmp(ea_name,CIFS_XATTR_DOS_ATTRIB,14) == 0) { | ||
236 | cFYI(1,("attempt to query cifs inode metadata")); | ||
237 | /* revalidate/getattr then populate from inode */ | ||
238 | } /* BB add else when above is implemented */ | ||
239 | ea_name += 5; /* skip past user. prefix */ | ||
240 | rc = CIFSSMBQueryEA(xid,pTcon,full_path,ea_name,ea_value, | ||
241 | buf_size, cifs_sb->local_nls); | ||
242 | } else if(strncmp(ea_name, CIFS_XATTR_OS2_PREFIX,4) == 0) { | ||
243 | if(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR) | ||
244 | goto get_ea_exit; | ||
245 | |||
246 | ea_name += 4; /* skip past os2. prefix */ | ||
247 | rc = CIFSSMBQueryEA(xid,pTcon,full_path,ea_name,ea_value, | ||
248 | buf_size, cifs_sb->local_nls); | ||
249 | } else if(strncmp(ea_name,POSIX_ACL_XATTR_ACCESS,strlen(POSIX_ACL_XATTR_ACCESS)) == 0) { | ||
250 | #ifdef CONFIG_CIFS_POSIX | ||
251 | rc = CIFSSMBGetPosixACL(xid, pTcon, full_path, | ||
252 | ea_value, buf_size, ACL_TYPE_ACCESS, | ||
253 | cifs_sb->local_nls); | ||
254 | #else | ||
255 | cFYI(1,("query POSIX ACL not supported yet")); | ||
256 | #endif /* CONFIG_CIFS_POSIX */ | ||
257 | } else if(strncmp(ea_name,POSIX_ACL_XATTR_DEFAULT,strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) { | ||
258 | #ifdef CONFIG_CIFS_POSIX | ||
259 | rc = CIFSSMBGetPosixACL(xid, pTcon, full_path, | ||
260 | ea_value, buf_size, ACL_TYPE_DEFAULT, | ||
261 | cifs_sb->local_nls); | ||
262 | #else | ||
263 | cFYI(1,("query POSIX default ACL not supported yet")); | ||
264 | #endif | ||
265 | } else if(strncmp(ea_name, | ||
266 | CIFS_XATTR_TRUSTED_PREFIX,XATTR_TRUSTED_PREFIX_LEN) == 0) { | ||
267 | cFYI(1,("Trusted xattr namespace not supported yet")); | ||
268 | } else if(strncmp(ea_name, | ||
269 | CIFS_XATTR_SECURITY_PREFIX,XATTR_SECURITY_PREFIX_LEN) == 0) { | ||
270 | cFYI(1,("Security xattr namespace not supported yet")); | ||
271 | } else { | ||
272 | cFYI(1,("illegal xattr name request %s (only user namespace supported)",ea_name)); | ||
273 | } | ||
274 | |||
275 | /* We could add an additional check for streams ie | ||
276 | if proc/fs/cifs/streamstoxattr is set then | ||
277 | search server for EAs or streams to | ||
278 | returns as xattrs */ | ||
279 | |||
280 | if(rc == -EINVAL) | ||
281 | rc = -EOPNOTSUPP; | ||
282 | |||
283 | get_ea_exit: | ||
284 | if (full_path) | ||
285 | kfree(full_path); | ||
286 | FreeXid(xid); | ||
287 | #endif | ||
288 | return rc; | ||
289 | } | ||
290 | |||
291 | ssize_t cifs_listxattr(struct dentry * direntry, char * data, size_t buf_size) | ||
292 | { | ||
293 | ssize_t rc = -EOPNOTSUPP; | ||
294 | #ifdef CONFIG_CIFS_XATTR | ||
295 | int xid; | ||
296 | struct cifs_sb_info *cifs_sb; | ||
297 | struct cifsTconInfo *pTcon; | ||
298 | struct super_block * sb; | ||
299 | char * full_path; | ||
300 | |||
301 | if(direntry == NULL) | ||
302 | return -EIO; | ||
303 | if(direntry->d_inode == NULL) | ||
304 | return -EIO; | ||
305 | sb = direntry->d_inode->i_sb; | ||
306 | if(sb == NULL) | ||
307 | return -EIO; | ||
308 | xid = GetXid(); | ||
309 | |||
310 | cifs_sb = CIFS_SB(sb); | ||
311 | pTcon = cifs_sb->tcon; | ||
312 | |||
313 | down(&sb->s_vfs_rename_sem); | ||
314 | full_path = build_path_from_dentry(direntry); | ||
315 | up(&sb->s_vfs_rename_sem); | ||
316 | if(full_path == NULL) { | ||
317 | FreeXid(xid); | ||
318 | return -ENOMEM; | ||
319 | } | ||
320 | /* return dos attributes as pseudo xattr */ | ||
321 | /* return alt name if available as pseudo attr */ | ||
322 | |||
323 | /* if proc/fs/cifs/streamstoxattr is set then | ||
324 | search server for EAs or streams to | ||
325 | returns as xattrs */ | ||
326 | rc = CIFSSMBQAllEAs(xid,pTcon,full_path,data,buf_size, | ||
327 | cifs_sb->local_nls); | ||
328 | |||
329 | if (full_path) | ||
330 | kfree(full_path); | ||
331 | FreeXid(xid); | ||
332 | #endif | ||
333 | return rc; | ||
334 | } | ||