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