Merge branch 'rbd-sysfs' of git://git.kernel.org/pub/scm/linux/kernel/git/sage/ceph...
[pandora-kernel.git] / fs / cifs / xattr.c
1 /*
2  *   fs/cifs/xattr.c
3  *
4  *   Copyright (c) International Business Machines  Corp., 2003, 2007
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 <linux/slab.h>
25 #include "cifsfs.h"
26 #include "cifspdu.h"
27 #include "cifsglob.h"
28 #include "cifsproto.h"
29 #include "cifs_debug.h"
30
31 #define MAX_EA_VALUE_SIZE 65535
32 #define CIFS_XATTR_DOS_ATTRIB "user.DosAttrib"
33 #define CIFS_XATTR_CIFS_ACL "system.cifs_acl"
34 #define CIFS_XATTR_USER_PREFIX "user."
35 #define CIFS_XATTR_SYSTEM_PREFIX "system."
36 #define CIFS_XATTR_OS2_PREFIX "os2."
37 #define CIFS_XATTR_SECURITY_PREFIX "security."
38 #define CIFS_XATTR_TRUSTED_PREFIX "trusted."
39 #define XATTR_TRUSTED_PREFIX_LEN  8
40 #define XATTR_SECURITY_PREFIX_LEN 9
41 /* BB need to add server (Samba e.g) support for security and trusted prefix */
42
43
44
45 int cifs_removexattr(struct dentry *direntry, const char *ea_name)
46 {
47         int rc = -EOPNOTSUPP;
48 #ifdef CONFIG_CIFS_XATTR
49         int xid;
50         struct cifs_sb_info *cifs_sb;
51         struct tcon_link *tlink;
52         struct cifsTconInfo *pTcon;
53         struct super_block *sb;
54         char *full_path = NULL;
55
56         if (direntry == NULL)
57                 return -EIO;
58         if (direntry->d_inode == NULL)
59                 return -EIO;
60         sb = direntry->d_inode->i_sb;
61         if (sb == NULL)
62                 return -EIO;
63
64         cifs_sb = CIFS_SB(sb);
65         tlink = cifs_sb_tlink(cifs_sb);
66         if (IS_ERR(tlink))
67                 return PTR_ERR(tlink);
68         pTcon = tlink_tcon(tlink);
69
70         xid = GetXid();
71
72         full_path = build_path_from_dentry(direntry);
73         if (full_path == NULL) {
74                 rc = -ENOMEM;
75                 goto remove_ea_exit;
76         }
77         if (ea_name == NULL) {
78                 cFYI(1, "Null xattr names not supported");
79         } else if (strncmp(ea_name, CIFS_XATTR_USER_PREFIX, 5)
80                 && (strncmp(ea_name, CIFS_XATTR_OS2_PREFIX, 4))) {
81                 cFYI(1,
82                      "illegal xattr request %s (only user namespace supported)",
83                      ea_name);
84                 /* BB what if no namespace prefix? */
85                 /* Should we just pass them to server, except for
86                 system and perhaps security prefixes? */
87         } else {
88                 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
89                         goto remove_ea_exit;
90
91                 ea_name += 5; /* skip past user. prefix */
92                 rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, NULL,
93                         (__u16)0, cifs_sb->local_nls,
94                         cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
95         }
96 remove_ea_exit:
97         kfree(full_path);
98         FreeXid(xid);
99         cifs_put_tlink(tlink);
100 #endif
101         return rc;
102 }
103
104 int cifs_setxattr(struct dentry *direntry, const char *ea_name,
105                   const void *ea_value, size_t value_size, int flags)
106 {
107         int rc = -EOPNOTSUPP;
108 #ifdef CONFIG_CIFS_XATTR
109         int xid;
110         struct cifs_sb_info *cifs_sb;
111         struct tcon_link *tlink;
112         struct cifsTconInfo *pTcon;
113         struct super_block *sb;
114         char *full_path;
115
116         if (direntry == NULL)
117                 return -EIO;
118         if (direntry->d_inode == NULL)
119                 return -EIO;
120         sb = direntry->d_inode->i_sb;
121         if (sb == NULL)
122                 return -EIO;
123
124         cifs_sb = CIFS_SB(sb);
125         tlink = cifs_sb_tlink(cifs_sb);
126         if (IS_ERR(tlink))
127                 return PTR_ERR(tlink);
128         pTcon = tlink_tcon(tlink);
129
130         xid = GetXid();
131
132         full_path = build_path_from_dentry(direntry);
133         if (full_path == NULL) {
134                 rc = -ENOMEM;
135                 goto set_ea_exit;
136         }
137         /* return dos attributes as pseudo xattr */
138         /* return alt name if available as pseudo attr */
139
140         /* if proc/fs/cifs/streamstoxattr is set then
141                 search server for EAs or streams to
142                 returns as xattrs */
143         if (value_size > MAX_EA_VALUE_SIZE) {
144                 cFYI(1, "size of EA value too large");
145                 rc = -EOPNOTSUPP;
146                 goto set_ea_exit;
147         }
148
149         if (ea_name == NULL) {
150                 cFYI(1, "Null xattr names not supported");
151         } else if (strncmp(ea_name, CIFS_XATTR_USER_PREFIX, 5) == 0) {
152                 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
153                         goto set_ea_exit;
154                 if (strncmp(ea_name, CIFS_XATTR_DOS_ATTRIB, 14) == 0)
155                         cFYI(1, "attempt to set cifs inode metadata");
156
157                 ea_name += 5; /* skip past user. prefix */
158                 rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, ea_value,
159                         (__u16)value_size, cifs_sb->local_nls,
160                         cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
161         } else if (strncmp(ea_name, CIFS_XATTR_OS2_PREFIX, 4) == 0) {
162                 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
163                         goto set_ea_exit;
164
165                 ea_name += 4; /* skip past os2. prefix */
166                 rc = CIFSSMBSetEA(xid, pTcon, full_path, ea_name, ea_value,
167                         (__u16)value_size, cifs_sb->local_nls,
168                         cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
169         } else {
170                 int temp;
171                 temp = strncmp(ea_name, POSIX_ACL_XATTR_ACCESS,
172                         strlen(POSIX_ACL_XATTR_ACCESS));
173                 if (temp == 0) {
174 #ifdef CONFIG_CIFS_POSIX
175                         if (sb->s_flags & MS_POSIXACL)
176                                 rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
177                                         ea_value, (const int)value_size,
178                                         ACL_TYPE_ACCESS, cifs_sb->local_nls,
179                                         cifs_sb->mnt_cifs_flags &
180                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
181                         cFYI(1, "set POSIX ACL rc %d", rc);
182 #else
183                         cFYI(1, "set POSIX ACL not supported");
184 #endif
185                 } else if (strncmp(ea_name, POSIX_ACL_XATTR_DEFAULT,
186                                    strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) {
187 #ifdef CONFIG_CIFS_POSIX
188                         if (sb->s_flags & MS_POSIXACL)
189                                 rc = CIFSSMBSetPosixACL(xid, pTcon, full_path,
190                                         ea_value, (const int)value_size,
191                                         ACL_TYPE_DEFAULT, cifs_sb->local_nls,
192                                         cifs_sb->mnt_cifs_flags &
193                                                 CIFS_MOUNT_MAP_SPECIAL_CHR);
194                         cFYI(1, "set POSIX default ACL rc %d", rc);
195 #else
196                         cFYI(1, "set default POSIX ACL not supported");
197 #endif
198                 } else {
199                         cFYI(1, "illegal xattr request %s (only user namespace"
200                                 " supported)", ea_name);
201                   /* BB what if no namespace prefix? */
202                   /* Should we just pass them to server, except for
203                   system and perhaps security prefixes? */
204                 }
205         }
206
207 set_ea_exit:
208         kfree(full_path);
209         FreeXid(xid);
210         cifs_put_tlink(tlink);
211 #endif
212         return rc;
213 }
214
215 ssize_t cifs_getxattr(struct dentry *direntry, const char *ea_name,
216         void *ea_value, size_t buf_size)
217 {
218         ssize_t rc = -EOPNOTSUPP;
219 #ifdef CONFIG_CIFS_XATTR
220         int xid;
221         struct cifs_sb_info *cifs_sb;
222         struct tcon_link *tlink;
223         struct cifsTconInfo *pTcon;
224         struct super_block *sb;
225         char *full_path;
226
227         if (direntry == NULL)
228                 return -EIO;
229         if (direntry->d_inode == NULL)
230                 return -EIO;
231         sb = direntry->d_inode->i_sb;
232         if (sb == NULL)
233                 return -EIO;
234
235         cifs_sb = CIFS_SB(sb);
236         tlink = cifs_sb_tlink(cifs_sb);
237         if (IS_ERR(tlink))
238                 return PTR_ERR(tlink);
239         pTcon = tlink_tcon(tlink);
240
241         xid = GetXid();
242
243         full_path = build_path_from_dentry(direntry);
244         if (full_path == NULL) {
245                 rc = -ENOMEM;
246                 goto get_ea_exit;
247         }
248         /* return dos attributes as pseudo xattr */
249         /* return alt name if available as pseudo attr */
250         if (ea_name == NULL) {
251                 cFYI(1, "Null xattr names not supported");
252         } else if (strncmp(ea_name, CIFS_XATTR_USER_PREFIX, 5) == 0) {
253                 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
254                         goto get_ea_exit;
255
256                 if (strncmp(ea_name, CIFS_XATTR_DOS_ATTRIB, 14) == 0) {
257                         cFYI(1, "attempt to query cifs inode metadata");
258                         /* revalidate/getattr then populate from inode */
259                 } /* BB add else when above is implemented */
260                 ea_name += 5; /* skip past user. prefix */
261                 rc = CIFSSMBQAllEAs(xid, pTcon, full_path, ea_name, ea_value,
262                         buf_size, cifs_sb->local_nls,
263                         cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
264         } else if (strncmp(ea_name, CIFS_XATTR_OS2_PREFIX, 4) == 0) {
265                 if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
266                         goto get_ea_exit;
267
268                 ea_name += 4; /* skip past os2. prefix */
269                 rc = CIFSSMBQAllEAs(xid, pTcon, full_path, ea_name, ea_value,
270                         buf_size, cifs_sb->local_nls,
271                         cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
272         } else if (strncmp(ea_name, POSIX_ACL_XATTR_ACCESS,
273                           strlen(POSIX_ACL_XATTR_ACCESS)) == 0) {
274 #ifdef CONFIG_CIFS_POSIX
275                 if (sb->s_flags & MS_POSIXACL)
276                         rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
277                                 ea_value, buf_size, ACL_TYPE_ACCESS,
278                                 cifs_sb->local_nls,
279                                 cifs_sb->mnt_cifs_flags &
280                                         CIFS_MOUNT_MAP_SPECIAL_CHR);
281 #else
282                 cFYI(1, "Query POSIX ACL not supported yet");
283 #endif /* CONFIG_CIFS_POSIX */
284         } else if (strncmp(ea_name, POSIX_ACL_XATTR_DEFAULT,
285                           strlen(POSIX_ACL_XATTR_DEFAULT)) == 0) {
286 #ifdef CONFIG_CIFS_POSIX
287                 if (sb->s_flags & MS_POSIXACL)
288                         rc = CIFSSMBGetPosixACL(xid, pTcon, full_path,
289                                 ea_value, buf_size, ACL_TYPE_DEFAULT,
290                                 cifs_sb->local_nls,
291                                 cifs_sb->mnt_cifs_flags &
292                                         CIFS_MOUNT_MAP_SPECIAL_CHR);
293 #else
294                 cFYI(1, "Query POSIX default ACL not supported yet");
295 #endif /* CONFIG_CIFS_POSIX */
296         } else if (strncmp(ea_name, CIFS_XATTR_CIFS_ACL,
297                                 strlen(CIFS_XATTR_CIFS_ACL)) == 0) {
298 #ifdef CONFIG_CIFS_ACL
299                         u32 acllen;
300                         struct cifs_ntsd *pacl;
301
302                         pacl = get_cifs_acl(cifs_sb, direntry->d_inode,
303                                                 full_path, &acllen);
304                         if (IS_ERR(pacl)) {
305                                 rc = PTR_ERR(pacl);
306                                 cERROR(1, "%s: error %zd getting sec desc",
307                                                 __func__, rc);
308                         } else {
309                                 if (ea_value) {
310                                         if (acllen > buf_size)
311                                                 acllen = -ERANGE;
312                                         else
313                                                 memcpy(ea_value, pacl, acllen);
314                                 }
315                                 rc = acllen;
316                                 kfree(pacl);
317                         }
318 #else
319                 cFYI(1, "Query CIFS ACL not supported yet");
320 #endif /* CONFIG_CIFS_ACL */
321         } else if (strncmp(ea_name,
322                   CIFS_XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN) == 0) {
323                 cFYI(1, "Trusted xattr namespace not supported yet");
324         } else if (strncmp(ea_name,
325                   CIFS_XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN) == 0) {
326                 cFYI(1, "Security xattr namespace not supported yet");
327         } else
328                 cFYI(1,
329                     "illegal xattr request %s (only user namespace supported)",
330                      ea_name);
331
332         /* We could add an additional check for streams ie
333             if proc/fs/cifs/streamstoxattr is set then
334                 search server for EAs or streams to
335                 returns as xattrs */
336
337         if (rc == -EINVAL)
338                 rc = -EOPNOTSUPP;
339
340 get_ea_exit:
341         kfree(full_path);
342         FreeXid(xid);
343         cifs_put_tlink(tlink);
344 #endif
345         return rc;
346 }
347
348 ssize_t cifs_listxattr(struct dentry *direntry, char *data, size_t buf_size)
349 {
350         ssize_t rc = -EOPNOTSUPP;
351 #ifdef CONFIG_CIFS_XATTR
352         int xid;
353         struct cifs_sb_info *cifs_sb;
354         struct tcon_link *tlink;
355         struct cifsTconInfo *pTcon;
356         struct super_block *sb;
357         char *full_path;
358
359         if (direntry == NULL)
360                 return -EIO;
361         if (direntry->d_inode == NULL)
362                 return -EIO;
363         sb = direntry->d_inode->i_sb;
364         if (sb == NULL)
365                 return -EIO;
366
367         cifs_sb = CIFS_SB(sb);
368         if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_NO_XATTR)
369                 return -EOPNOTSUPP;
370
371         tlink = cifs_sb_tlink(cifs_sb);
372         if (IS_ERR(tlink))
373                 return PTR_ERR(tlink);
374         pTcon = tlink_tcon(tlink);
375
376         xid = GetXid();
377
378         full_path = build_path_from_dentry(direntry);
379         if (full_path == NULL) {
380                 rc = -ENOMEM;
381                 goto list_ea_exit;
382         }
383         /* return dos attributes as pseudo xattr */
384         /* return alt name if available as pseudo attr */
385
386         /* if proc/fs/cifs/streamstoxattr is set then
387                 search server for EAs or streams to
388                 returns as xattrs */
389         rc = CIFSSMBQAllEAs(xid, pTcon, full_path, NULL, data,
390                                 buf_size, cifs_sb->local_nls,
391                                 cifs_sb->mnt_cifs_flags &
392                                         CIFS_MOUNT_MAP_SPECIAL_CHR);
393
394 list_ea_exit:
395         kfree(full_path);
396         FreeXid(xid);
397         cifs_put_tlink(tlink);
398 #endif
399         return rc;
400 }