]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/kern/vfs_extattr.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / kern / vfs_extattr.c
1 /*-
2  * Copyright (c) 1999-2001 Robert N. M. Watson
3  * All rights reserved.
4  *
5  * This software was developed by Robert Watson for the TrustedBSD Project.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/capability.h>
35 #include <sys/lock.h>
36 #include <sys/mount.h>
37 #include <sys/mutex.h>
38 #include <sys/sysproto.h>
39 #include <sys/fcntl.h>
40 #include <sys/namei.h>
41 #include <sys/filedesc.h>
42 #include <sys/limits.h>
43 #include <sys/vnode.h>
44 #include <sys/proc.h>
45 #include <sys/extattr.h>
46
47 #include <security/audit/audit.h>
48 #include <security/mac/mac_framework.h>
49
50 /*
51  * Syscall to push extended attribute configuration information into the VFS.
52  * Accepts a path, which it converts to a mountpoint, as well as a command
53  * (int cmd), and attribute name and misc data.
54  *
55  * Currently this is used only by UFS1 extended attributes.
56  */
57 int
58 sys_extattrctl(td, uap)
59         struct thread *td;
60         struct extattrctl_args /* {
61                 const char *path;
62                 int cmd;
63                 const char *filename;
64                 int attrnamespace;
65                 const char *attrname;
66         } */ *uap;
67 {
68         struct vnode *filename_vp;
69         struct nameidata nd;
70         struct mount *mp, *mp_writable;
71         char attrname[EXTATTR_MAXNAMELEN];
72         int vfslocked, fnvfslocked, error;
73
74         AUDIT_ARG_CMD(uap->cmd);
75         AUDIT_ARG_VALUE(uap->attrnamespace);
76         /*
77          * uap->attrname is not always defined.  We check again later when we
78          * invoke the VFS call so as to pass in NULL there if needed.
79          */
80         if (uap->attrname != NULL) {
81                 error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN,
82                     NULL);
83                 if (error)
84                         return (error);
85         }
86         AUDIT_ARG_TEXT(attrname);
87
88         vfslocked = fnvfslocked = 0;
89         mp = NULL;
90         filename_vp = NULL;
91         if (uap->filename != NULL) {
92                 NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | AUDITVNODE2,
93                     UIO_USERSPACE, uap->filename, td);
94                 error = namei(&nd);
95                 if (error)
96                         return (error);
97                 fnvfslocked = NDHASGIANT(&nd);
98                 filename_vp = nd.ni_vp;
99                 NDFREE(&nd, NDF_NO_VP_RELE);
100         }
101
102         /* uap->path is always defined. */
103         NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | LOCKLEAF | AUDITVNODE1,
104             UIO_USERSPACE, uap->path, td);
105         error = namei(&nd);
106         if (error)
107                 goto out;
108         vfslocked = NDHASGIANT(&nd);
109         mp = nd.ni_vp->v_mount;
110         error = vfs_busy(mp, 0);
111         if (error) {
112                 NDFREE(&nd, 0);
113                 mp = NULL;
114                 goto out;
115         }
116         VOP_UNLOCK(nd.ni_vp, 0);
117         error = vn_start_write(nd.ni_vp, &mp_writable, V_WAIT | PCATCH);
118         NDFREE(&nd, NDF_NO_VP_UNLOCK);
119         if (error)
120                 goto out;
121         if (filename_vp != NULL) {
122                 /*
123                  * uap->filename is not always defined.  If it is,
124                  * grab a vnode lock, which VFS_EXTATTRCTL() will
125                  * later release.
126                  */
127                 error = vn_lock(filename_vp, LK_EXCLUSIVE);
128                 if (error) {
129                         vn_finished_write(mp_writable);
130                         goto out;
131                 }
132         }
133
134         error = VFS_EXTATTRCTL(mp, uap->cmd, filename_vp, uap->attrnamespace,
135             uap->attrname != NULL ? attrname : NULL);
136
137         vn_finished_write(mp_writable);
138 out:
139         if (mp != NULL)
140                 vfs_unbusy(mp);
141
142         /*
143          * VFS_EXTATTRCTL will have unlocked, but not de-ref'd, filename_vp,
144          * so vrele it if it is defined.
145          */
146         if (filename_vp != NULL)
147                 vrele(filename_vp);
148         VFS_UNLOCK_GIANT(fnvfslocked);
149         VFS_UNLOCK_GIANT(vfslocked);
150         return (error);
151 }
152
153 /*-
154  * Set a named extended attribute on a file or directory
155  *
156  * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
157  *            kernelspace string pointer "attrname", userspace buffer
158  *            pointer "data", buffer length "nbytes", thread "td".
159  * Returns: 0 on success, an error number otherwise
160  * Locks: none
161  * References: vp must be a valid reference for the duration of the call
162  */
163 static int
164 extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname,
165     void *data, size_t nbytes, struct thread *td)
166 {
167         struct mount *mp;
168         struct uio auio;
169         struct iovec aiov;
170         ssize_t cnt;
171         int error;
172
173         VFS_ASSERT_GIANT(vp->v_mount);
174         error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
175         if (error)
176                 return (error);
177         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
178
179         aiov.iov_base = data;
180         aiov.iov_len = nbytes;
181         auio.uio_iov = &aiov;
182         auio.uio_iovcnt = 1;
183         auio.uio_offset = 0;
184         if (nbytes > IOSIZE_MAX) {
185                 error = EINVAL;
186                 goto done;
187         }
188         auio.uio_resid = nbytes;
189         auio.uio_rw = UIO_WRITE;
190         auio.uio_segflg = UIO_USERSPACE;
191         auio.uio_td = td;
192         cnt = nbytes;
193
194 #ifdef MAC
195         error = mac_vnode_check_setextattr(td->td_ucred, vp, attrnamespace,
196             attrname);
197         if (error)
198                 goto done;
199 #endif
200
201         error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio,
202             td->td_ucred, td);
203         cnt -= auio.uio_resid;
204         td->td_retval[0] = cnt;
205
206 done:
207         VOP_UNLOCK(vp, 0);
208         vn_finished_write(mp);
209         return (error);
210 }
211
212 int
213 sys_extattr_set_fd(td, uap)
214         struct thread *td;
215         struct extattr_set_fd_args /* {
216                 int fd;
217                 int attrnamespace;
218                 const char *attrname;
219                 void *data;
220                 size_t nbytes;
221         } */ *uap;
222 {
223         struct file *fp;
224         char attrname[EXTATTR_MAXNAMELEN];
225         int vfslocked, error;
226
227         AUDIT_ARG_FD(uap->fd);
228         AUDIT_ARG_VALUE(uap->attrnamespace);
229         error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
230         if (error)
231                 return (error);
232         AUDIT_ARG_TEXT(attrname);
233
234         error = getvnode(td->td_proc->p_fd, uap->fd, CAP_EXTATTR_SET, &fp);
235         if (error)
236                 return (error);
237
238         vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
239         error = extattr_set_vp(fp->f_vnode, uap->attrnamespace,
240             attrname, uap->data, uap->nbytes, td);
241         fdrop(fp, td);
242         VFS_UNLOCK_GIANT(vfslocked);
243
244         return (error);
245 }
246
247 int
248 sys_extattr_set_file(td, uap)
249         struct thread *td;
250         struct extattr_set_file_args /* {
251                 const char *path;
252                 int attrnamespace;
253                 const char *attrname;
254                 void *data;
255                 size_t nbytes;
256         } */ *uap;
257 {
258         struct nameidata nd;
259         char attrname[EXTATTR_MAXNAMELEN];
260         int vfslocked, error;
261
262         AUDIT_ARG_VALUE(uap->attrnamespace);
263         error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
264         if (error)
265                 return (error);
266         AUDIT_ARG_TEXT(attrname);
267
268         NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | AUDITVNODE1, UIO_USERSPACE,
269             uap->path, td);
270         error = namei(&nd);
271         if (error)
272                 return (error);
273         NDFREE(&nd, NDF_ONLY_PNBUF);
274
275         vfslocked = NDHASGIANT(&nd);
276         error = extattr_set_vp(nd.ni_vp, uap->attrnamespace, attrname,
277             uap->data, uap->nbytes, td);
278
279         vrele(nd.ni_vp);
280         VFS_UNLOCK_GIANT(vfslocked);
281         return (error);
282 }
283
284 int
285 sys_extattr_set_link(td, uap)
286         struct thread *td;
287         struct extattr_set_link_args /* {
288                 const char *path;
289                 int attrnamespace;
290                 const char *attrname;
291                 void *data;
292                 size_t nbytes;
293         } */ *uap;
294 {
295         struct nameidata nd;
296         char attrname[EXTATTR_MAXNAMELEN];
297         int vfslocked, error;
298
299         AUDIT_ARG_VALUE(uap->attrnamespace);
300         error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
301         if (error)
302                 return (error);
303         AUDIT_ARG_TEXT(attrname);
304
305         NDINIT(&nd, LOOKUP, MPSAFE | NOFOLLOW | AUDITVNODE1, UIO_USERSPACE,
306             uap->path, td);
307         error = namei(&nd);
308         if (error)
309                 return (error);
310         NDFREE(&nd, NDF_ONLY_PNBUF);
311
312         vfslocked = NDHASGIANT(&nd);
313         error = extattr_set_vp(nd.ni_vp, uap->attrnamespace, attrname,
314             uap->data, uap->nbytes, td);
315
316         vrele(nd.ni_vp);
317         VFS_UNLOCK_GIANT(vfslocked);
318         return (error);
319 }
320
321 /*-
322  * Get a named extended attribute on a file or directory
323  *
324  * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
325  *            kernelspace string pointer "attrname", userspace buffer
326  *            pointer "data", buffer length "nbytes", thread "td".
327  * Returns: 0 on success, an error number otherwise
328  * Locks: none
329  * References: vp must be a valid reference for the duration of the call
330  */
331 static int
332 extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname,
333     void *data, size_t nbytes, struct thread *td)
334 {
335         struct uio auio, *auiop;
336         struct iovec aiov;
337         ssize_t cnt;
338         size_t size, *sizep;
339         int error;
340
341         VFS_ASSERT_GIANT(vp->v_mount);
342         vn_lock(vp, LK_SHARED | LK_RETRY);
343
344         /*
345          * Slightly unusual semantics: if the user provides a NULL data
346          * pointer, they don't want to receive the data, just the maximum
347          * read length.
348          */
349         auiop = NULL;
350         sizep = NULL;
351         cnt = 0;
352         if (data != NULL) {
353                 aiov.iov_base = data;
354                 aiov.iov_len = nbytes;
355                 auio.uio_iov = &aiov;
356                 auio.uio_iovcnt = 1;
357                 auio.uio_offset = 0;
358                 if (nbytes > IOSIZE_MAX) {
359                         error = EINVAL;
360                         goto done;
361                 }
362                 auio.uio_resid = nbytes;
363                 auio.uio_rw = UIO_READ;
364                 auio.uio_segflg = UIO_USERSPACE;
365                 auio.uio_td = td;
366                 auiop = &auio;
367                 cnt = nbytes;
368         } else
369                 sizep = &size;
370
371 #ifdef MAC
372         error = mac_vnode_check_getextattr(td->td_ucred, vp, attrnamespace,
373             attrname);
374         if (error)
375                 goto done;
376 #endif
377
378         error = VOP_GETEXTATTR(vp, attrnamespace, attrname, auiop, sizep,
379             td->td_ucred, td);
380
381         if (auiop != NULL) {
382                 cnt -= auio.uio_resid;
383                 td->td_retval[0] = cnt;
384         } else
385                 td->td_retval[0] = size;
386
387 done:
388         VOP_UNLOCK(vp, 0);
389         return (error);
390 }
391
392 int
393 sys_extattr_get_fd(td, uap)
394         struct thread *td;
395         struct extattr_get_fd_args /* {
396                 int fd;
397                 int attrnamespace;
398                 const char *attrname;
399                 void *data;
400                 size_t nbytes;
401         } */ *uap;
402 {
403         struct file *fp;
404         char attrname[EXTATTR_MAXNAMELEN];
405         int vfslocked, error;
406
407         AUDIT_ARG_FD(uap->fd);
408         AUDIT_ARG_VALUE(uap->attrnamespace);
409         error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
410         if (error)
411                 return (error);
412         AUDIT_ARG_TEXT(attrname);
413
414         error = getvnode(td->td_proc->p_fd, uap->fd, CAP_EXTATTR_GET, &fp);
415         if (error)
416                 return (error);
417
418         vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
419         error = extattr_get_vp(fp->f_vnode, uap->attrnamespace,
420             attrname, uap->data, uap->nbytes, td);
421
422         fdrop(fp, td);
423         VFS_UNLOCK_GIANT(vfslocked);
424         return (error);
425 }
426
427 int
428 sys_extattr_get_file(td, uap)
429         struct thread *td;
430         struct extattr_get_file_args /* {
431                 const char *path;
432                 int attrnamespace;
433                 const char *attrname;
434                 void *data;
435                 size_t nbytes;
436         } */ *uap;
437 {
438         struct nameidata nd;
439         char attrname[EXTATTR_MAXNAMELEN];
440         int vfslocked, error;
441
442         AUDIT_ARG_VALUE(uap->attrnamespace);
443         error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
444         if (error)
445                 return (error);
446         AUDIT_ARG_TEXT(attrname);
447
448         NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | AUDITVNODE1, UIO_USERSPACE,
449             uap->path, td);
450         error = namei(&nd);
451         if (error)
452                 return (error);
453         NDFREE(&nd, NDF_ONLY_PNBUF);
454
455         vfslocked = NDHASGIANT(&nd);
456         error = extattr_get_vp(nd.ni_vp, uap->attrnamespace, attrname,
457             uap->data, uap->nbytes, td);
458
459         vrele(nd.ni_vp);
460         VFS_UNLOCK_GIANT(vfslocked);
461         return (error);
462 }
463
464 int
465 sys_extattr_get_link(td, uap)
466         struct thread *td;
467         struct extattr_get_link_args /* {
468                 const char *path;
469                 int attrnamespace;
470                 const char *attrname;
471                 void *data;
472                 size_t nbytes;
473         } */ *uap;
474 {
475         struct nameidata nd;
476         char attrname[EXTATTR_MAXNAMELEN];
477         int vfslocked, error;
478
479         AUDIT_ARG_VALUE(uap->attrnamespace);
480         error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
481         if (error)
482                 return (error);
483         AUDIT_ARG_TEXT(attrname);
484
485         NDINIT(&nd, LOOKUP, MPSAFE | NOFOLLOW | AUDITVNODE1, UIO_USERSPACE,
486             uap->path, td);
487         error = namei(&nd);
488         if (error)
489                 return (error);
490         NDFREE(&nd, NDF_ONLY_PNBUF);
491
492         vfslocked = NDHASGIANT(&nd);
493         error = extattr_get_vp(nd.ni_vp, uap->attrnamespace, attrname,
494             uap->data, uap->nbytes, td);
495
496         vrele(nd.ni_vp);
497         VFS_UNLOCK_GIANT(vfslocked);
498         return (error);
499 }
500
501 /*
502  * extattr_delete_vp(): Delete a named extended attribute on a file or
503  *                      directory
504  *
505  * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
506  *            kernelspace string pointer "attrname", proc "p"
507  * Returns: 0 on success, an error number otherwise
508  * Locks: none
509  * References: vp must be a valid reference for the duration of the call
510  */
511 static int
512 extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname,
513     struct thread *td)
514 {
515         struct mount *mp;
516         int error;
517
518         VFS_ASSERT_GIANT(vp->v_mount);
519         error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
520         if (error)
521                 return (error);
522         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
523
524 #ifdef MAC
525         error = mac_vnode_check_deleteextattr(td->td_ucred, vp, attrnamespace,
526             attrname);
527         if (error)
528                 goto done;
529 #endif
530
531         error = VOP_DELETEEXTATTR(vp, attrnamespace, attrname, td->td_ucred,
532             td);
533         if (error == EOPNOTSUPP)
534                 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL,
535                     td->td_ucred, td);
536 #ifdef MAC
537 done:
538 #endif
539         VOP_UNLOCK(vp, 0);
540         vn_finished_write(mp);
541         return (error);
542 }
543
544 int
545 sys_extattr_delete_fd(td, uap)
546         struct thread *td;
547         struct extattr_delete_fd_args /* {
548                 int fd;
549                 int attrnamespace;
550                 const char *attrname;
551         } */ *uap;
552 {
553         struct file *fp;
554         char attrname[EXTATTR_MAXNAMELEN];
555         int vfslocked, error;
556
557         AUDIT_ARG_FD(uap->fd);
558         AUDIT_ARG_VALUE(uap->attrnamespace);
559         error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
560         if (error)
561                 return (error);
562         AUDIT_ARG_TEXT(attrname);
563
564         error = getvnode(td->td_proc->p_fd, uap->fd, CAP_EXTATTR_DELETE,
565             &fp);
566         if (error)
567                 return (error);
568
569         vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
570         error = extattr_delete_vp(fp->f_vnode, uap->attrnamespace,
571             attrname, td);
572         fdrop(fp, td);
573         VFS_UNLOCK_GIANT(vfslocked);
574         return (error);
575 }
576
577 int
578 sys_extattr_delete_file(td, uap)
579         struct thread *td;
580         struct extattr_delete_file_args /* {
581                 const char *path;
582                 int attrnamespace;
583                 const char *attrname;
584         } */ *uap;
585 {
586         struct nameidata nd;
587         char attrname[EXTATTR_MAXNAMELEN];
588         int vfslocked, error;
589
590         AUDIT_ARG_VALUE(uap->attrnamespace);
591         error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
592         if (error)
593                 return(error);
594         AUDIT_ARG_TEXT(attrname);
595
596         NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | AUDITVNODE1, UIO_USERSPACE,
597             uap->path, td);
598         error = namei(&nd);
599         if (error)
600                 return(error);
601         NDFREE(&nd, NDF_ONLY_PNBUF);
602
603         vfslocked = NDHASGIANT(&nd);
604         error = extattr_delete_vp(nd.ni_vp, uap->attrnamespace, attrname, td);
605         vrele(nd.ni_vp);
606         VFS_UNLOCK_GIANT(vfslocked);
607         return(error);
608 }
609
610 int
611 sys_extattr_delete_link(td, uap)
612         struct thread *td;
613         struct extattr_delete_link_args /* {
614                 const char *path;
615                 int attrnamespace;
616                 const char *attrname;
617         } */ *uap;
618 {
619         struct nameidata nd;
620         char attrname[EXTATTR_MAXNAMELEN];
621         int vfslocked, error;
622
623         AUDIT_ARG_VALUE(uap->attrnamespace);
624         error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
625         if (error)
626                 return(error);
627         AUDIT_ARG_TEXT(attrname);
628
629         NDINIT(&nd, LOOKUP, MPSAFE | NOFOLLOW | AUDITVNODE1, UIO_USERSPACE,
630             uap->path, td);
631         error = namei(&nd);
632         if (error)
633                 return(error);
634         NDFREE(&nd, NDF_ONLY_PNBUF);
635
636         vfslocked = NDHASGIANT(&nd);
637         error = extattr_delete_vp(nd.ni_vp, uap->attrnamespace, attrname, td);
638         vrele(nd.ni_vp);
639         VFS_UNLOCK_GIANT(vfslocked);
640         return(error);
641 }
642
643 /*-
644  * Retrieve a list of extended attributes on a file or directory.
645  *
646  * Arguments: unlocked vnode "vp", attribute namespace 'attrnamespace",
647  *            userspace buffer pointer "data", buffer length "nbytes",
648  *            thread "td".
649  * Returns: 0 on success, an error number otherwise
650  * Locks: none
651  * References: vp must be a valid reference for the duration of the call
652  */
653 static int
654 extattr_list_vp(struct vnode *vp, int attrnamespace, void *data,
655     size_t nbytes, struct thread *td)
656 {
657         struct uio auio, *auiop;
658         size_t size, *sizep;
659         struct iovec aiov;
660         ssize_t cnt;
661         int error;
662
663         VFS_ASSERT_GIANT(vp->v_mount);
664         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
665
666         auiop = NULL;
667         sizep = NULL;
668         cnt = 0;
669         if (data != NULL) {
670                 aiov.iov_base = data;
671                 aiov.iov_len = nbytes;
672                 auio.uio_iov = &aiov;
673                 auio.uio_iovcnt = 1;
674                 auio.uio_offset = 0;
675                 if (nbytes > IOSIZE_MAX) {
676                         error = EINVAL;
677                         goto done;
678                 }
679                 auio.uio_resid = nbytes;
680                 auio.uio_rw = UIO_READ;
681                 auio.uio_segflg = UIO_USERSPACE;
682                 auio.uio_td = td;
683                 auiop = &auio;
684                 cnt = nbytes;
685         } else
686                 sizep = &size;
687
688 #ifdef MAC
689         error = mac_vnode_check_listextattr(td->td_ucred, vp, attrnamespace);
690         if (error)
691                 goto done;
692 #endif
693
694         error = VOP_LISTEXTATTR(vp, attrnamespace, auiop, sizep,
695             td->td_ucred, td);
696
697         if (auiop != NULL) {
698                 cnt -= auio.uio_resid;
699                 td->td_retval[0] = cnt;
700         } else
701                 td->td_retval[0] = size;
702
703 done:
704         VOP_UNLOCK(vp, 0);
705         return (error);
706 }
707
708
709 int
710 sys_extattr_list_fd(td, uap)
711         struct thread *td;
712         struct extattr_list_fd_args /* {
713                 int fd;
714                 int attrnamespace;
715                 void *data;
716                 size_t nbytes;
717         } */ *uap;
718 {
719         struct file *fp;
720         int vfslocked, error;
721
722         AUDIT_ARG_FD(uap->fd);
723         AUDIT_ARG_VALUE(uap->attrnamespace);
724         error = getvnode(td->td_proc->p_fd, uap->fd, CAP_EXTATTR_LIST, &fp);
725         if (error)
726                 return (error);
727
728         vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount);
729         error = extattr_list_vp(fp->f_vnode, uap->attrnamespace, uap->data,
730             uap->nbytes, td);
731
732         fdrop(fp, td);
733         VFS_UNLOCK_GIANT(vfslocked);
734         return (error);
735 }
736
737 int
738 sys_extattr_list_file(td, uap)
739         struct thread*td;
740         struct extattr_list_file_args /* {
741                 const char *path;
742                 int attrnamespace;
743                 void *data;
744                 size_t nbytes;
745         } */ *uap;
746 {
747         struct nameidata nd;
748         int vfslocked, error;
749
750         AUDIT_ARG_VALUE(uap->attrnamespace);
751         NDINIT(&nd, LOOKUP, MPSAFE | FOLLOW | AUDITVNODE1, UIO_USERSPACE,
752             uap->path, td);
753         error = namei(&nd);
754         if (error)
755                 return (error);
756         NDFREE(&nd, NDF_ONLY_PNBUF);
757
758         vfslocked = NDHASGIANT(&nd);
759         error = extattr_list_vp(nd.ni_vp, uap->attrnamespace, uap->data,
760             uap->nbytes, td);
761
762         vrele(nd.ni_vp);
763         VFS_UNLOCK_GIANT(vfslocked);
764         return (error);
765 }
766
767 int
768 sys_extattr_list_link(td, uap)
769         struct thread*td;
770         struct extattr_list_link_args /* {
771                 const char *path;
772                 int attrnamespace;
773                 void *data;
774                 size_t nbytes;
775         } */ *uap;
776 {
777         struct nameidata nd;
778         int vfslocked, error;
779
780         AUDIT_ARG_VALUE(uap->attrnamespace);
781         NDINIT(&nd, LOOKUP, MPSAFE | NOFOLLOW | AUDITVNODE1, UIO_USERSPACE,
782             uap->path, td);
783         error = namei(&nd);
784         if (error)
785                 return (error);
786         NDFREE(&nd, NDF_ONLY_PNBUF);
787
788         vfslocked = NDHASGIANT(&nd);
789         error = extattr_list_vp(nd.ni_vp, uap->attrnamespace, uap->data,
790             uap->nbytes, td);
791
792         vrele(nd.ni_vp);
793         VFS_UNLOCK_GIANT(vfslocked);
794         return (error);
795 }