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