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