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