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