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