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