]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/kern/vfs_extattr.c
Replace one more LINK_MAX with NFS_LINK_MAX missed in r326991.
[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         if (nbytes > IOSIZE_MAX)
171                 return (EINVAL);
172
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         auio.uio_resid = nbytes;
184         auio.uio_rw = UIO_WRITE;
185         auio.uio_segflg = UIO_USERSPACE;
186         auio.uio_td = td;
187         cnt = nbytes;
188
189 #ifdef MAC
190         error = mac_vnode_check_setextattr(td->td_ucred, vp, attrnamespace,
191             attrname);
192         if (error)
193                 goto done;
194 #endif
195
196         error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio,
197             td->td_ucred, td);
198         cnt -= auio.uio_resid;
199         td->td_retval[0] = cnt;
200
201 #ifdef MAC
202 done:
203 #endif
204         VOP_UNLOCK(vp, 0);
205         vn_finished_write(mp);
206         return (error);
207 }
208
209 int
210 sys_extattr_set_fd(td, uap)
211         struct thread *td;
212         struct extattr_set_fd_args /* {
213                 int fd;
214                 int attrnamespace;
215                 const char *attrname;
216                 void *data;
217                 size_t nbytes;
218         } */ *uap;
219 {
220         struct file *fp;
221         char attrname[EXTATTR_MAXNAMELEN];
222         cap_rights_t rights;
223         int error;
224
225         AUDIT_ARG_FD(uap->fd);
226         AUDIT_ARG_VALUE(uap->attrnamespace);
227         error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
228         if (error)
229                 return (error);
230         AUDIT_ARG_TEXT(attrname);
231
232         error = getvnode(td, uap->fd,
233             cap_rights_init(&rights, CAP_EXTATTR_SET), &fp);
234         if (error)
235                 return (error);
236
237         error = extattr_set_vp(fp->f_vnode, uap->attrnamespace,
238             attrname, uap->data, uap->nbytes, td);
239         fdrop(fp, td);
240
241         return (error);
242 }
243
244 int
245 sys_extattr_set_file(td, uap)
246         struct thread *td;
247         struct extattr_set_file_args /* {
248                 const char *path;
249                 int attrnamespace;
250                 const char *attrname;
251                 void *data;
252                 size_t nbytes;
253         } */ *uap;
254 {
255         struct nameidata nd;
256         char attrname[EXTATTR_MAXNAMELEN];
257         int error;
258
259         AUDIT_ARG_VALUE(uap->attrnamespace);
260         error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
261         if (error)
262                 return (error);
263         AUDIT_ARG_TEXT(attrname);
264
265         NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1, UIO_USERSPACE,
266             uap->path, td);
267         error = namei(&nd);
268         if (error)
269                 return (error);
270         NDFREE(&nd, NDF_ONLY_PNBUF);
271
272         error = extattr_set_vp(nd.ni_vp, uap->attrnamespace, attrname,
273             uap->data, uap->nbytes, td);
274
275         vrele(nd.ni_vp);
276         return (error);
277 }
278
279 int
280 sys_extattr_set_link(td, uap)
281         struct thread *td;
282         struct extattr_set_link_args /* {
283                 const char *path;
284                 int attrnamespace;
285                 const char *attrname;
286                 void *data;
287                 size_t nbytes;
288         } */ *uap;
289 {
290         struct nameidata nd;
291         char attrname[EXTATTR_MAXNAMELEN];
292         int error;
293
294         AUDIT_ARG_VALUE(uap->attrnamespace);
295         error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
296         if (error)
297                 return (error);
298         AUDIT_ARG_TEXT(attrname);
299
300         NDINIT(&nd, LOOKUP, NOFOLLOW | AUDITVNODE1, UIO_USERSPACE,
301             uap->path, td);
302         error = namei(&nd);
303         if (error)
304                 return (error);
305         NDFREE(&nd, NDF_ONLY_PNBUF);
306
307         error = extattr_set_vp(nd.ni_vp, uap->attrnamespace, attrname,
308             uap->data, uap->nbytes, td);
309
310         vrele(nd.ni_vp);
311         return (error);
312 }
313
314 /*-
315  * Get a named extended attribute on a file or directory
316  *
317  * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
318  *            kernelspace string pointer "attrname", userspace buffer
319  *            pointer "data", buffer length "nbytes", thread "td".
320  * Returns: 0 on success, an error number otherwise
321  * Locks: none
322  * References: vp must be a valid reference for the duration of the call
323  */
324 static int
325 extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname,
326     void *data, size_t nbytes, struct thread *td)
327 {
328         struct uio auio, *auiop;
329         struct iovec aiov;
330         ssize_t cnt;
331         size_t size, *sizep;
332         int error;
333
334         if (nbytes > IOSIZE_MAX)
335                 return (EINVAL);
336
337         vn_lock(vp, LK_SHARED | LK_RETRY);
338
339         /*
340          * Slightly unusual semantics: if the user provides a NULL data
341          * pointer, they don't want to receive the data, just the maximum
342          * read length.
343          */
344         auiop = NULL;
345         sizep = NULL;
346         cnt = 0;
347         if (data != NULL) {
348                 aiov.iov_base = data;
349                 aiov.iov_len = nbytes;
350                 auio.uio_iov = &aiov;
351                 auio.uio_iovcnt = 1;
352                 auio.uio_offset = 0;
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 #ifdef MAC
378 done:
379 #endif
380         VOP_UNLOCK(vp, 0);
381         return (error);
382 }
383
384 int
385 sys_extattr_get_fd(td, uap)
386         struct thread *td;
387         struct extattr_get_fd_args /* {
388                 int fd;
389                 int attrnamespace;
390                 const char *attrname;
391                 void *data;
392                 size_t nbytes;
393         } */ *uap;
394 {
395         struct file *fp;
396         char attrname[EXTATTR_MAXNAMELEN];
397         cap_rights_t rights;
398         int error;
399
400         AUDIT_ARG_FD(uap->fd);
401         AUDIT_ARG_VALUE(uap->attrnamespace);
402         error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
403         if (error)
404                 return (error);
405         AUDIT_ARG_TEXT(attrname);
406
407         error = getvnode(td, uap->fd,
408             cap_rights_init(&rights, CAP_EXTATTR_GET), &fp);
409         if (error)
410                 return (error);
411
412         error = extattr_get_vp(fp->f_vnode, uap->attrnamespace,
413             attrname, uap->data, uap->nbytes, td);
414
415         fdrop(fp, td);
416         return (error);
417 }
418
419 int
420 sys_extattr_get_file(td, uap)
421         struct thread *td;
422         struct extattr_get_file_args /* {
423                 const char *path;
424                 int attrnamespace;
425                 const char *attrname;
426                 void *data;
427                 size_t nbytes;
428         } */ *uap;
429 {
430         struct nameidata nd;
431         char attrname[EXTATTR_MAXNAMELEN];
432         int error;
433
434         AUDIT_ARG_VALUE(uap->attrnamespace);
435         error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
436         if (error)
437                 return (error);
438         AUDIT_ARG_TEXT(attrname);
439
440         NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path, td);
441         error = namei(&nd);
442         if (error)
443                 return (error);
444         NDFREE(&nd, NDF_ONLY_PNBUF);
445
446         error = extattr_get_vp(nd.ni_vp, uap->attrnamespace, attrname,
447             uap->data, uap->nbytes, td);
448
449         vrele(nd.ni_vp);
450         return (error);
451 }
452
453 int
454 sys_extattr_get_link(td, uap)
455         struct thread *td;
456         struct extattr_get_link_args /* {
457                 const char *path;
458                 int attrnamespace;
459                 const char *attrname;
460                 void *data;
461                 size_t nbytes;
462         } */ *uap;
463 {
464         struct nameidata nd;
465         char attrname[EXTATTR_MAXNAMELEN];
466         int error;
467
468         AUDIT_ARG_VALUE(uap->attrnamespace);
469         error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
470         if (error)
471                 return (error);
472         AUDIT_ARG_TEXT(attrname);
473
474         NDINIT(&nd, LOOKUP, NOFOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path,
475             td);
476         error = namei(&nd);
477         if (error)
478                 return (error);
479         NDFREE(&nd, NDF_ONLY_PNBUF);
480
481         error = extattr_get_vp(nd.ni_vp, uap->attrnamespace, attrname,
482             uap->data, uap->nbytes, td);
483
484         vrele(nd.ni_vp);
485         return (error);
486 }
487
488 /*
489  * extattr_delete_vp(): Delete a named extended attribute on a file or
490  *                      directory
491  *
492  * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
493  *            kernelspace string pointer "attrname", proc "p"
494  * Returns: 0 on success, an error number otherwise
495  * Locks: none
496  * References: vp must be a valid reference for the duration of the call
497  */
498 static int
499 extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname,
500     struct thread *td)
501 {
502         struct mount *mp;
503         int error;
504
505         error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
506         if (error)
507                 return (error);
508         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
509
510 #ifdef MAC
511         error = mac_vnode_check_deleteextattr(td->td_ucred, vp, attrnamespace,
512             attrname);
513         if (error)
514                 goto done;
515 #endif
516
517         error = VOP_DELETEEXTATTR(vp, attrnamespace, attrname, td->td_ucred,
518             td);
519         if (error == EOPNOTSUPP)
520                 error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL,
521                     td->td_ucred, td);
522 #ifdef MAC
523 done:
524 #endif
525         VOP_UNLOCK(vp, 0);
526         vn_finished_write(mp);
527         return (error);
528 }
529
530 int
531 sys_extattr_delete_fd(td, uap)
532         struct thread *td;
533         struct extattr_delete_fd_args /* {
534                 int fd;
535                 int attrnamespace;
536                 const char *attrname;
537         } */ *uap;
538 {
539         struct file *fp;
540         char attrname[EXTATTR_MAXNAMELEN];
541         cap_rights_t rights;
542         int error;
543
544         AUDIT_ARG_FD(uap->fd);
545         AUDIT_ARG_VALUE(uap->attrnamespace);
546         error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
547         if (error)
548                 return (error);
549         AUDIT_ARG_TEXT(attrname);
550
551         error = getvnode(td, uap->fd,
552             cap_rights_init(&rights, CAP_EXTATTR_DELETE), &fp);
553         if (error)
554                 return (error);
555
556         error = extattr_delete_vp(fp->f_vnode, uap->attrnamespace,
557             attrname, td);
558         fdrop(fp, td);
559         return (error);
560 }
561
562 int
563 sys_extattr_delete_file(td, uap)
564         struct thread *td;
565         struct extattr_delete_file_args /* {
566                 const char *path;
567                 int attrnamespace;
568                 const char *attrname;
569         } */ *uap;
570 {
571         struct nameidata nd;
572         char attrname[EXTATTR_MAXNAMELEN];
573         int error;
574
575         AUDIT_ARG_VALUE(uap->attrnamespace);
576         error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
577         if (error)
578                 return(error);
579         AUDIT_ARG_TEXT(attrname);
580
581         NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path, td);
582         error = namei(&nd);
583         if (error)
584                 return(error);
585         NDFREE(&nd, NDF_ONLY_PNBUF);
586
587         error = extattr_delete_vp(nd.ni_vp, uap->attrnamespace, attrname, td);
588         vrele(nd.ni_vp);
589         return(error);
590 }
591
592 int
593 sys_extattr_delete_link(td, uap)
594         struct thread *td;
595         struct extattr_delete_link_args /* {
596                 const char *path;
597                 int attrnamespace;
598                 const char *attrname;
599         } */ *uap;
600 {
601         struct nameidata nd;
602         char attrname[EXTATTR_MAXNAMELEN];
603         int error;
604
605         AUDIT_ARG_VALUE(uap->attrnamespace);
606         error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
607         if (error)
608                 return(error);
609         AUDIT_ARG_TEXT(attrname);
610
611         NDINIT(&nd, LOOKUP, NOFOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path, td);
612         error = namei(&nd);
613         if (error)
614                 return(error);
615         NDFREE(&nd, NDF_ONLY_PNBUF);
616
617         error = extattr_delete_vp(nd.ni_vp, uap->attrnamespace, attrname, td);
618         vrele(nd.ni_vp);
619         return(error);
620 }
621
622 /*-
623  * Retrieve a list of extended attributes on a file or directory.
624  *
625  * Arguments: unlocked vnode "vp", attribute namespace 'attrnamespace",
626  *            userspace buffer pointer "data", buffer length "nbytes",
627  *            thread "td".
628  * Returns: 0 on success, an error number otherwise
629  * Locks: none
630  * References: vp must be a valid reference for the duration of the call
631  */
632 static int
633 extattr_list_vp(struct vnode *vp, int attrnamespace, void *data,
634     size_t nbytes, struct thread *td)
635 {
636         struct uio auio, *auiop;
637         size_t size, *sizep;
638         struct iovec aiov;
639         ssize_t cnt;
640         int error;
641
642         if (nbytes > IOSIZE_MAX)
643                 return (EINVAL);
644
645         vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
646
647         auiop = NULL;
648         sizep = NULL;
649         cnt = 0;
650         if (data != NULL) {
651                 aiov.iov_base = data;
652                 aiov.iov_len = nbytes;
653                 auio.uio_iov = &aiov;
654                 auio.uio_iovcnt = 1;
655                 auio.uio_offset = 0;
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 #ifdef MAC
680 done:
681 #endif
682         VOP_UNLOCK(vp, 0);
683         return (error);
684 }
685
686
687 int
688 sys_extattr_list_fd(td, uap)
689         struct thread *td;
690         struct extattr_list_fd_args /* {
691                 int fd;
692                 int attrnamespace;
693                 void *data;
694                 size_t nbytes;
695         } */ *uap;
696 {
697         struct file *fp;
698         cap_rights_t rights;
699         int error;
700
701         AUDIT_ARG_FD(uap->fd);
702         AUDIT_ARG_VALUE(uap->attrnamespace);
703         error = getvnode(td, uap->fd,
704             cap_rights_init(&rights, CAP_EXTATTR_LIST), &fp);
705         if (error)
706                 return (error);
707
708         error = extattr_list_vp(fp->f_vnode, uap->attrnamespace, uap->data,
709             uap->nbytes, td);
710
711         fdrop(fp, td);
712         return (error);
713 }
714
715 int
716 sys_extattr_list_file(td, uap)
717         struct thread*td;
718         struct extattr_list_file_args /* {
719                 const char *path;
720                 int attrnamespace;
721                 void *data;
722                 size_t nbytes;
723         } */ *uap;
724 {
725         struct nameidata nd;
726         int error;
727
728         AUDIT_ARG_VALUE(uap->attrnamespace);
729         NDINIT(&nd, LOOKUP, FOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path, td);
730         error = namei(&nd);
731         if (error)
732                 return (error);
733         NDFREE(&nd, NDF_ONLY_PNBUF);
734
735         error = extattr_list_vp(nd.ni_vp, uap->attrnamespace, uap->data,
736             uap->nbytes, td);
737
738         vrele(nd.ni_vp);
739         return (error);
740 }
741
742 int
743 sys_extattr_list_link(td, uap)
744         struct thread*td;
745         struct extattr_list_link_args /* {
746                 const char *path;
747                 int attrnamespace;
748                 void *data;
749                 size_t nbytes;
750         } */ *uap;
751 {
752         struct nameidata nd;
753         int error;
754
755         AUDIT_ARG_VALUE(uap->attrnamespace);
756         NDINIT(&nd, LOOKUP, NOFOLLOW | AUDITVNODE1, UIO_USERSPACE, uap->path,
757             td);
758         error = namei(&nd);
759         if (error)
760                 return (error);
761         NDFREE(&nd, NDF_ONLY_PNBUF);
762
763         error = extattr_list_vp(nd.ni_vp, uap->attrnamespace, uap->data,
764             uap->nbytes, td);
765
766         vrele(nd.ni_vp);
767         return (error);
768 }