xref: /netbsd/sys/kern/vfs_xattr.c (revision 6550d01e)
1 /*	$NetBSD: vfs_xattr.c,v 1.23 2010/11/19 06:44:45 dholland Exp $	*/
2 
3 /*-
4  * Copyright (c) 2005, 2008 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jason R. Thorpe.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * Copyright (c) 1989, 1993
34  *	The Regents of the University of California.  All rights reserved.
35  * (c) UNIX System Laboratories, Inc.
36  * All or some portions of this file are derived from material licensed
37  * to the University of California by American Telephone and Telegraph
38  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
39  * the permission of UNIX System Laboratories, Inc.
40  *
41  * Redistribution and use in source and binary forms, with or without
42  * modification, are permitted provided that the following conditions
43  * are met:
44  * 1. Redistributions of source code must retain the above copyright
45  *    notice, this list of conditions and the following disclaimer.
46  * 2. Redistributions in binary form must reproduce the above copyright
47  *    notice, this list of conditions and the following disclaimer in the
48  *    documentation and/or other materials provided with the distribution.
49  * 3. Neither the name of the University nor the names of its contributors
50  *    may be used to endorse or promote products derived from this software
51  *    without specific prior written permission.
52  *
53  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63  * SUCH DAMAGE.
64  */
65 
66 /*
67  * VFS extended attribute support.
68  */
69 
70 #include <sys/cdefs.h>
71 __KERNEL_RCSID(0, "$NetBSD: vfs_xattr.c,v 1.23 2010/11/19 06:44:45 dholland Exp $");
72 
73 #include <sys/param.h>
74 #include <sys/systm.h>
75 #include <sys/namei.h>
76 #include <sys/filedesc.h>
77 #include <sys/kernel.h>
78 #include <sys/file.h>
79 #include <sys/vnode.h>
80 #include <sys/mount.h>
81 #include <sys/proc.h>
82 #include <sys/uio.h>
83 #include <sys/extattr.h>
84 #include <sys/xattr.h>
85 #include <sys/sysctl.h>
86 #include <sys/syscallargs.h>
87 #include <sys/kauth.h>
88 
89 /*
90  * Credential check based on process requesting service, and per-attribute
91  * permissions.
92  *
93  * NOTE: Vnode must be locked.
94  */
95 int
96 extattr_check_cred(struct vnode *vp, int attrnamespace,
97     kauth_cred_t cred, struct lwp *l, int access)
98 {
99 
100 	if (cred == NOCRED)
101 		return (0);
102 
103 	switch (attrnamespace) {
104 	case EXTATTR_NAMESPACE_SYSTEM:
105 		/*
106 		 * Do we really want to allow this, or just require that
107 		 * these requests come from kernel code (NOCRED case above)?
108 		 */
109 		return (kauth_authorize_generic(cred, KAUTH_GENERIC_ISSUSER,
110 		    NULL));
111 
112 	case EXTATTR_NAMESPACE_USER:
113 		return (VOP_ACCESS(vp, access, cred));
114 
115 	default:
116 		return (EPERM);
117 	}
118 }
119 
120 /*
121  * Default vfs_extattrctl routine for file systems that do not support
122  * it.
123  */
124 /*ARGSUSED*/
125 int
126 vfs_stdextattrctl(struct mount *mp, int cmt, struct vnode *vp,
127     int attrnamespace, const char *attrname)
128 {
129 
130 	if (vp != NULL)
131 		VOP_UNLOCK(vp);
132 	return (EOPNOTSUPP);
133 }
134 
135 /*
136  * Push extended attribute configuration information into the file
137  * system.
138  *
139  * NOTE: Not all file systems that support extended attributes will
140  * require the use of this system call.
141  */
142 int
143 sys_extattrctl(struct lwp *l, const struct sys_extattrctl_args *uap, register_t *retval)
144 {
145 	/* {
146 		syscallarg(const char *) path;
147 		syscallarg(int) cmd;
148 		syscallarg(const char *) filename;
149 		syscallarg(int) attrnamespace;
150 		syscallarg(const char *) attrname;
151 	} */
152 	struct vnode *path_vp, *file_vp;
153 	struct pathbuf *file_pb;
154 	struct nameidata file_nd;
155 	char attrname[EXTATTR_MAXNAMELEN];
156 	int error;
157 
158 	if (SCARG(uap, attrname) != NULL) {
159 		error = copyinstr(SCARG(uap, attrname), attrname,
160 		    sizeof(attrname), NULL);
161 		if (error)
162 			return (error);
163 	}
164 
165 	error = namei_simple_user(SCARG(uap, path),
166 				NSM_FOLLOW_NOEMULROOT, &path_vp);
167 	if (error) {
168 		return (error);
169 	}
170 
171 	file_vp = NULL;
172 	if (SCARG(uap, filename) != NULL) {
173 		error = pathbuf_copyin(SCARG(uap, filename), &file_pb);
174 		if (error) {
175 			vrele(path_vp);
176 			return (error);
177 		}
178 		NDINIT(&file_nd, LOOKUP, FOLLOW | LOCKLEAF, file_pb);
179 		error = namei(&file_nd);
180 		if (error) {
181 			pathbuf_destroy(file_pb);
182 			vrele(path_vp);
183 			return (error);
184 		}
185 		file_vp = file_nd.ni_vp;
186 		pathbuf_destroy(file_pb);
187 	}
188 
189 	error = VFS_EXTATTRCTL(path_vp->v_mount, SCARG(uap, cmd), file_vp,
190 	    SCARG(uap, attrnamespace),
191 	    SCARG(uap, attrname) != NULL ? attrname : NULL);
192 
193 	if (file_vp != NULL)
194 		vrele(file_vp);
195 	vrele(path_vp);
196 
197 	return (error);
198 }
199 
200 /*****************************************************************************
201  * Internal routines to manipulate file system extended attributes:
202  *	- set
203  *	- get
204  *	- delete
205  *	- list
206  *****************************************************************************/
207 
208 /*
209  * extattr_set_vp:
210  *
211  *	Set a named extended attribute on a file or directory.
212  */
213 static int
214 extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname,
215     const void *data, size_t nbytes, struct lwp *l, register_t *retval)
216 {
217 	struct uio auio;
218 	struct iovec aiov;
219 	ssize_t cnt;
220 	int error;
221 
222 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
223 
224 	aiov.iov_base = __UNCONST(data);	/* XXXUNCONST kills const */
225 	aiov.iov_len = nbytes;
226 	auio.uio_iov = &aiov;
227 	auio.uio_iovcnt = 1;
228 	auio.uio_offset = 0;
229 	if (nbytes > INT_MAX) {
230 		error = EINVAL;
231 		goto done;
232 	}
233 	auio.uio_resid = nbytes;
234 	auio.uio_rw = UIO_WRITE;
235 	KASSERT(l == curlwp);
236 	auio.uio_vmspace = l->l_proc->p_vmspace;
237 	cnt = nbytes;
238 
239 	error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio, l->l_cred);
240 	cnt -= auio.uio_resid;
241 	retval[0] = cnt;
242 
243  done:
244 	VOP_UNLOCK(vp);
245 	return (error);
246 }
247 
248 /*
249  * extattr_get_vp:
250  *
251  *	Get a named extended attribute on a file or directory.
252  */
253 static int
254 extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname,
255     void *data, size_t nbytes, struct lwp *l, register_t *retval)
256 {
257 	struct uio auio, *auiop;
258 	struct iovec aiov;
259 	ssize_t cnt;
260 	size_t size, *sizep;
261 	int error;
262 
263 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
264 
265 	/*
266 	 * Slightly unusual semantics: if the user provides a NULL data
267 	 * pointer, they don't want to receive the data, just the maximum
268 	 * read length.
269 	 */
270 	auiop = NULL;
271 	sizep = NULL;
272 	cnt = 0;
273 	if (data != NULL) {
274 		aiov.iov_base = data;
275 		aiov.iov_len = nbytes;
276 		auio.uio_iov = &aiov;
277 		auio.uio_offset = 0;
278 		if (nbytes > INT_MAX) {
279 			error = EINVAL;
280 			goto done;
281 		}
282 		auio.uio_resid = nbytes;
283 		auio.uio_rw = UIO_READ;
284 		KASSERT(l == curlwp);
285 		auio.uio_vmspace = l->l_proc->p_vmspace;
286 		auiop = &auio;
287 		cnt = nbytes;
288 	} else
289 		sizep = &size;
290 
291 	error = VOP_GETEXTATTR(vp, attrnamespace, attrname, auiop, sizep,
292 	    l->l_cred);
293 
294 	if (auiop != NULL) {
295 		cnt -= auio.uio_resid;
296 		retval[0] = cnt;
297 	} else
298 		retval[0] = size;
299 
300  done:
301 	VOP_UNLOCK(vp);
302 	return (error);
303 }
304 
305 /*
306  * extattr_delete_vp:
307  *
308  *	Delete a named extended attribute on a file or directory.
309  */
310 static int
311 extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname,
312     struct lwp *l)
313 {
314 	int error;
315 
316 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
317 
318 	error = VOP_DELETEEXTATTR(vp, attrnamespace, attrname, l->l_cred);
319 	if (error == EOPNOTSUPP)
320 		error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL,
321 		    l->l_cred);
322 
323 	VOP_UNLOCK(vp);
324 	return (error);
325 }
326 
327 /*
328  * extattr_list_vp:
329  *
330  *	Retrieve a list of extended attributes on a file or directory.
331  */
332 static int
333 extattr_list_vp(struct vnode *vp, int attrnamespace, void *data, size_t nbytes,
334     struct lwp *l, register_t *retval)
335 {
336 	struct uio auio, *auiop;
337 	size_t size, *sizep;
338 	struct iovec aiov;
339 	ssize_t cnt;
340 	int error;
341 
342 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
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_offset = 0;
352 		if (nbytes > INT_MAX) {
353 			error = EINVAL;
354 			goto done;
355 		}
356 		auio.uio_resid = nbytes;
357 		auio.uio_rw = UIO_READ;
358 		KASSERT(l == curlwp);
359 		auio.uio_vmspace = l->l_proc->p_vmspace;
360 		auiop = &auio;
361 		cnt = nbytes;
362 	} else
363 		sizep = &size;
364 
365 	error = VOP_LISTEXTATTR(vp, attrnamespace, auiop, sizep, l->l_cred);
366 
367 	if (auiop != NULL) {
368 		cnt -= auio.uio_resid;
369 		retval[0] = cnt;
370 	} else
371 		retval[0] = size;
372 
373  done:
374 	VOP_UNLOCK(vp);
375 	return (error);
376 }
377 
378 /*****************************************************************************
379  * BSD <sys/extattr.h> API for file system extended attributes
380  *****************************************************************************/
381 
382 int
383 sys_extattr_set_fd(struct lwp *l, const struct sys_extattr_set_fd_args *uap, register_t *retval)
384 {
385 	/* {
386 		syscallarg(int) fd;
387 		syscallarg(int) attrnamespace;
388 		syscallarg(const char *) attrname;
389 		syscallarg(const void *) data;
390 		syscallarg(size_t) nbytes;
391 	} */
392 	struct file *fp;
393 	struct vnode *vp;
394 	char attrname[EXTATTR_MAXNAMELEN];
395 	int error;
396 
397 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
398 	    NULL);
399 	if (error)
400 		return (error);
401 
402 	error = fd_getvnode(SCARG(uap, fd), &fp);
403 	if (error)
404 		return (error);
405 	vp = (struct vnode *) fp->f_data;
406 
407 	error = extattr_set_vp(vp, SCARG(uap, attrnamespace), attrname,
408 	    SCARG(uap, data), SCARG(uap, nbytes), l, retval);
409 
410 	fd_putfile(SCARG(uap, fd));
411 	return (error);
412 }
413 
414 int
415 sys_extattr_set_file(struct lwp *l, const struct sys_extattr_set_file_args *uap, register_t *retval)
416 {
417 	/* {
418 		syscallarg(const char *) path;
419 		syscallarg(int) attrnamespace;
420 		syscallarg(const char *) attrname;
421 		syscallarg(const void *) data;
422 		syscallarg(size_t) nbytes;
423 	} */
424 	struct vnode *vp;
425 	char attrname[EXTATTR_MAXNAMELEN];
426 	int error;
427 
428 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
429 	    NULL);
430 	if (error)
431 		return (error);
432 
433 	error = namei_simple_user(SCARG(uap, path),
434 				NSM_FOLLOW_NOEMULROOT, &vp);
435 	if (error)
436 		return (error);
437 
438 	error = extattr_set_vp(vp, SCARG(uap, attrnamespace), attrname,
439 	    SCARG(uap, data), SCARG(uap, nbytes), l, retval);
440 
441 	vrele(vp);
442 	return (error);
443 }
444 
445 int
446 sys_extattr_set_link(struct lwp *l, const struct sys_extattr_set_link_args *uap, register_t *retval)
447 {
448 	/* {
449 		syscallarg(const char *) path;
450 		syscallarg(int) attrnamespace;
451 		syscallarg(const char *) attrname;
452 		syscallarg(const void *) data;
453 		syscallarg(size_t) nbytes;
454 	} */
455 	struct vnode *vp;
456 	char attrname[EXTATTR_MAXNAMELEN];
457 	int error;
458 
459 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
460 	    NULL);
461 	if (error)
462 		return (error);
463 
464 	error = namei_simple_user(SCARG(uap, path),
465 				NSM_NOFOLLOW_NOEMULROOT, &vp);
466 	if (error)
467 		return (error);
468 
469 	error = extattr_set_vp(vp, SCARG(uap, attrnamespace), attrname,
470 	    SCARG(uap, data), SCARG(uap, nbytes), l, retval);
471 
472 	vrele(vp);
473 	return (error);
474 }
475 
476 int
477 sys_extattr_get_fd(struct lwp *l, const struct sys_extattr_get_fd_args *uap, register_t *retval)
478 {
479 	/* {
480 		syscallarg(int) fd;
481 		syscallarg(int) attrnamespace;
482 		syscallarg(const char *) attrname;
483 		syscallarg(void *) data;
484 		syscallarg(size_t) nbytes;
485 	} */
486 	struct file *fp;
487 	struct vnode *vp;
488 	char attrname[EXTATTR_MAXNAMELEN];
489 	int error;
490 
491 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
492 	    NULL);
493 	if (error)
494 		return (error);
495 
496 	error = fd_getvnode(SCARG(uap, fd), &fp);
497 	if (error)
498 		return (error);
499 	vp = (struct vnode *) fp->f_data;
500 
501 	error = extattr_get_vp(vp, SCARG(uap, attrnamespace), attrname,
502 	    SCARG(uap, data), SCARG(uap, nbytes), l, retval);
503 
504 	fd_putfile(SCARG(uap, fd));
505 	return (error);
506 }
507 
508 int
509 sys_extattr_get_file(struct lwp *l, const struct sys_extattr_get_file_args *uap, register_t *retval)
510 {
511 	/* {
512 		syscallarg(const char *) path;
513 		syscallarg(int) attrnamespace;
514 		syscallarg(const char *) attrname;
515 		syscallarg(void *) data;
516 		syscallarg(size_t) nbytes;
517 	} */
518 	struct vnode *vp;
519 	char attrname[EXTATTR_MAXNAMELEN];
520 	int error;
521 
522 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
523 	    NULL);
524 	if (error)
525 		return (error);
526 
527 	error = namei_simple_user(SCARG(uap, path),
528 				NSM_FOLLOW_NOEMULROOT, &vp);
529 	if (error)
530 		return (error);
531 
532 	error = extattr_get_vp(vp, SCARG(uap, attrnamespace), attrname,
533 	    SCARG(uap, data), SCARG(uap, nbytes), l, retval);
534 
535 	vrele(vp);
536 	return (error);
537 }
538 
539 int
540 sys_extattr_get_link(struct lwp *l, const struct sys_extattr_get_link_args *uap, register_t *retval)
541 {
542 	/* {
543 		syscallarg(const char *) path;
544 		syscallarg(int) attrnamespace;
545 		syscallarg(const char *) attrname;
546 		syscallarg(void *) data;
547 		syscallarg(size_t) nbytes;
548 	} */
549 	struct vnode *vp;
550 	char attrname[EXTATTR_MAXNAMELEN];
551 	int error;
552 
553 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
554 	    NULL);
555 	if (error)
556 		return (error);
557 
558 	error = namei_simple_user(SCARG(uap, path),
559 				NSM_NOFOLLOW_NOEMULROOT, &vp);
560 	if (error)
561 		return (error);
562 
563 	error = extattr_get_vp(vp, SCARG(uap, attrnamespace), attrname,
564 	    SCARG(uap, data), SCARG(uap, nbytes), l, retval);
565 
566 	vrele(vp);
567 	return (error);
568 }
569 
570 int
571 sys_extattr_delete_fd(struct lwp *l, const struct sys_extattr_delete_fd_args *uap, register_t *retval)
572 {
573 	/* {
574 		syscallarg(int) fd;
575 		syscallarg(int) attrnamespace;
576 		syscallarg(const char *) attrname;
577 	} */
578 	struct file *fp;
579 	struct vnode *vp;
580 	char attrname[EXTATTR_MAXNAMELEN];
581 	int error;
582 
583 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
584 	    NULL);
585 	if (error)
586 		return (error);
587 
588 	error = fd_getvnode(SCARG(uap, fd), &fp);
589 	if (error)
590 		return (error);
591 	vp = (struct vnode *) fp->f_data;
592 
593 	error = extattr_delete_vp(vp, SCARG(uap, attrnamespace), attrname, l);
594 
595 	fd_putfile(SCARG(uap, fd));
596 	return (error);
597 }
598 
599 int
600 sys_extattr_delete_file(struct lwp *l, const struct sys_extattr_delete_file_args *uap, register_t *retval)
601 {
602 	/* {
603 		syscallarg(const char *) path;
604 		syscallarg(int) attrnamespace;
605 		syscallarg(const char *) attrname;
606 	} */
607 	struct vnode *vp;
608 	char attrname[EXTATTR_MAXNAMELEN];
609 	int error;
610 
611 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
612 	    NULL);
613 	if (error)
614 		return (error);
615 
616 	error = namei_simple_user(SCARG(uap, path),
617 				NSM_FOLLOW_NOEMULROOT, &vp);
618 	if (error)
619 		return (error);
620 
621 	error = extattr_delete_vp(vp, SCARG(uap, attrnamespace), attrname, l);
622 
623 	vrele(vp);
624 	return (error);
625 }
626 
627 int
628 sys_extattr_delete_link(struct lwp *l, const struct sys_extattr_delete_link_args *uap, register_t *retval)
629 {
630 	/* {
631 		syscallarg(const char *) path;
632 		syscallarg(int) attrnamespace;
633 		syscallarg(const char *) attrname;
634 	} */
635 	struct vnode *vp;
636 	char attrname[EXTATTR_MAXNAMELEN];
637 	int error;
638 
639 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
640 	    NULL);
641 	if (error)
642 		return (error);
643 
644 	error = namei_simple_user(SCARG(uap, path),
645 				NSM_NOFOLLOW_NOEMULROOT, &vp);
646 	if (error)
647 		return (error);
648 
649 	error = extattr_delete_vp(vp, SCARG(uap, attrnamespace), attrname, l);
650 
651 	vrele(vp);
652 	return (error);
653 }
654 
655 int
656 sys_extattr_list_fd(struct lwp *l, const struct sys_extattr_list_fd_args *uap, register_t *retval)
657 {
658 	/* {
659 		syscallarg(int) fd;
660 		syscallarg(int) attrnamespace;
661 		syscallarg(void *) data;
662 		syscallarg(size_t) nbytes;
663 	} */
664 	struct file *fp;
665 	struct vnode *vp;
666 	int error;
667 
668 	error = fd_getvnode(SCARG(uap, fd), &fp);
669 	if (error)
670 		return (error);
671 	vp = (struct vnode *) fp->f_data;
672 
673 	error = extattr_list_vp(vp, SCARG(uap, attrnamespace),
674 	    SCARG(uap, data), SCARG(uap, nbytes), l, retval);
675 
676 	fd_putfile(SCARG(uap, fd));
677 	return (error);
678 }
679 
680 int
681 sys_extattr_list_file(struct lwp *l, const struct sys_extattr_list_file_args *uap, register_t *retval)
682 {
683 	/* {
684 		syscallarg(const char *) path;
685 		syscallarg(int) attrnamespace;
686 		syscallarg(void *) data;
687 		syscallarg(size_t) nbytes;
688 	} */
689 	struct vnode *vp;
690 	int error;
691 
692 	error = namei_simple_user(SCARG(uap, path),
693 				NSM_FOLLOW_NOEMULROOT, &vp);
694 	if (error)
695 		return (error);
696 
697 	error = extattr_list_vp(vp, SCARG(uap, attrnamespace),
698 	    SCARG(uap, data), SCARG(uap, nbytes), l, retval);
699 
700 	vrele(vp);
701 	return (error);
702 }
703 
704 int
705 sys_extattr_list_link(struct lwp *l, const struct sys_extattr_list_link_args *uap, register_t *retval)
706 {
707 	/* {
708 		syscallarg(const char *) path;
709 		syscallarg(int) attrnamespace;
710 		syscallarg(void *) data;
711 		syscallarg(size_t) nbytes;
712 	} */
713 	struct vnode *vp;
714 	int error;
715 
716 	error = namei_simple_user(SCARG(uap, path),
717 				NSM_NOFOLLOW_NOEMULROOT, &vp);
718 	if (error)
719 		return (error);
720 
721 	error = extattr_list_vp(vp, SCARG(uap, attrnamespace),
722 	    SCARG(uap, data), SCARG(uap, nbytes), l, retval);
723 
724 	vrele(vp);
725 	return (error);
726 }
727 
728 /*****************************************************************************
729  * Linux-compatible <sys/xattr.h> API for file system extended attributes
730  *****************************************************************************/
731 
732 int
733 sys_setxattr(struct lwp *l, const struct sys_setxattr_args *uap, register_t *retval)
734 {
735 	/* {
736 		syscallarg(const char *) path;
737 		syscallarg(const char *) name;
738 		syscallarg(void *) value;
739 		syscallarg(size_t) size;
740 		syscallarg(int) flags;
741 	} */
742 	struct vnode *vp;
743 	char attrname[XATTR_NAME_MAX];
744 	int error;
745 
746 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
747 	    NULL);
748 	if (error)
749 		return (error);
750 
751 	error = namei_simple_user(SCARG(uap, path),
752 				NSM_FOLLOW_NOEMULROOT, &vp);
753 	if (error)
754 		return (error);
755 
756 	/* XXX flags */
757 
758 	error = extattr_set_vp(vp, EXTATTR_NAMESPACE_USER,
759 	    attrname, SCARG(uap, value), SCARG(uap, size), l, retval);
760 
761 	vrele(vp);
762 	return (error);
763 }
764 
765 int
766 sys_lsetxattr(struct lwp *l, const struct sys_lsetxattr_args *uap, register_t *retval)
767 {
768 	/* {
769 		syscallarg(const char *) path;
770 		syscallarg(const char *) name;
771 		syscallarg(void *) value;
772 		syscallarg(size_t) size;
773 		syscallarg(int) flags;
774 	} */
775 	struct vnode *vp;
776 	char attrname[XATTR_NAME_MAX];
777 	int error;
778 
779 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
780 	    NULL);
781 	if (error)
782 		return (error);
783 
784 	error = namei_simple_user(SCARG(uap, path),
785 				NSM_NOFOLLOW_NOEMULROOT, &vp);
786 	if (error)
787 		return (error);
788 
789 	/* XXX flags */
790 
791 	error = extattr_set_vp(vp, EXTATTR_NAMESPACE_USER,
792 	    attrname, SCARG(uap, value), SCARG(uap, size), l, retval);
793 
794 	vrele(vp);
795 	return (error);
796 }
797 
798 int
799 sys_fsetxattr(struct lwp *l, const struct sys_fsetxattr_args *uap, register_t *retval)
800 {
801 	/* {
802 		syscallarg(int) fd;
803 		syscallarg(const char *) name;
804 		syscallarg(void *) value;
805 		syscallarg(size_t) size;
806 		syscallarg(int) flags;
807 	} */
808 	struct file *fp;
809 	struct vnode *vp;
810 	char attrname[XATTR_NAME_MAX];
811 	int error;
812 
813 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
814 	    NULL);
815 	if (error)
816 		return (error);
817 
818 	error = fd_getvnode(SCARG(uap, fd), &fp);
819 	if (error)
820 		return (error);
821 	vp = (struct vnode *) fp->f_data;
822 
823 	/* XXX flags */
824 
825 	error = extattr_set_vp(vp, EXTATTR_NAMESPACE_USER,
826 	    attrname, SCARG(uap, value), SCARG(uap, size), l, retval);
827 
828 	fd_putfile(SCARG(uap, fd));
829 	return (error);
830 }
831 
832 int
833 sys_getxattr(struct lwp *l, const struct sys_getxattr_args *uap, register_t *retval)
834 {
835 	/* {
836 		syscallarg(const char *) path;
837 		syscallarg(const char *) name;
838 		syscallarg(void *) value;
839 		syscallarg(size_t) size;
840 	} */
841 	struct vnode *vp;
842 	char attrname[XATTR_NAME_MAX];
843 	int error;
844 
845 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
846 	    NULL);
847 	if (error)
848 		return (error);
849 
850 	error = namei_simple_user(SCARG(uap, path),
851 				NSM_FOLLOW_NOEMULROOT, &vp);
852 	if (error)
853 		return (error);
854 
855 	error = extattr_get_vp(vp, EXTATTR_NAMESPACE_USER,
856 	    attrname, SCARG(uap, value), SCARG(uap, size), l, retval);
857 
858 	vrele(vp);
859 	return (error);
860 }
861 
862 int
863 sys_lgetxattr(struct lwp *l, const struct sys_lgetxattr_args *uap, register_t *retval)
864 {
865 	/* {
866 		syscallarg(const char *) path;
867 		syscallarg(const char *) name;
868 		syscallarg(void *) value;
869 		syscallarg(size_t) size;
870 	} */
871 	struct vnode *vp;
872 	char attrname[XATTR_NAME_MAX];
873 	int error;
874 
875 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
876 	    NULL);
877 	if (error)
878 		return (error);
879 
880 	error = namei_simple_user(SCARG(uap, path),
881 				NSM_NOFOLLOW_NOEMULROOT, &vp);
882 	if (error)
883 		return (error);
884 
885 	error = extattr_get_vp(vp, EXTATTR_NAMESPACE_USER,
886 	    attrname, SCARG(uap, value), SCARG(uap, size), l, retval);
887 
888 	vrele(vp);
889 	return (error);
890 }
891 
892 int
893 sys_fgetxattr(struct lwp *l, const struct sys_fgetxattr_args *uap, register_t *retval)
894 {
895 	/* {
896 		syscallarg(int) fd;
897 		syscallarg(const char *) name;
898 		syscallarg(void *) value;
899 		syscallarg(size_t) size;
900 	} */
901 	struct file *fp;
902 	struct vnode *vp;
903 	char attrname[XATTR_NAME_MAX];
904 	int error;
905 
906 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
907 	    NULL);
908 	if (error)
909 		return (error);
910 
911 	error = fd_getvnode(SCARG(uap, fd), &fp);
912 	if (error)
913 		return (error);
914 	vp = (struct vnode *) fp->f_data;
915 
916 	error = extattr_get_vp(vp, EXTATTR_NAMESPACE_USER,
917 	    attrname, SCARG(uap, value), SCARG(uap, size), l, retval);
918 
919 	fd_putfile(SCARG(uap, fd));
920 	return (error);
921 }
922 
923 int
924 sys_listxattr(struct lwp *l, const struct sys_listxattr_args *uap, register_t *retval)
925 {
926 	/* {
927 		syscallarg(const char *) path;
928 		syscallarg(char *) list;
929 		syscallarg(size_t) size;
930 	} */
931 	struct vnode *vp;
932 	int error;
933 
934 	error = namei_simple_user(SCARG(uap, path),
935 				NSM_FOLLOW_NOEMULROOT, &vp);
936 	if (error)
937 		return (error);
938 
939 	error = extattr_list_vp(vp, EXTATTR_NAMESPACE_USER,
940 	    SCARG(uap, list), SCARG(uap, size), l, retval);
941 
942 	vrele(vp);
943 	return (error);
944 }
945 
946 int
947 sys_llistxattr(struct lwp *l, const struct sys_llistxattr_args *uap, register_t *retval)
948 {
949 	/* {
950 		syscallarg(const char *) path;
951 		syscallarg(char *) list;
952 		syscallarg(size_t) size;
953 	} */
954 	struct vnode *vp;
955 	int error;
956 
957 	error = namei_simple_user(SCARG(uap, path),
958 				NSM_NOFOLLOW_NOEMULROOT, &vp);
959 	if (error)
960 		return (error);
961 
962 	error = extattr_list_vp(vp, EXTATTR_NAMESPACE_USER,
963 	    SCARG(uap, list), SCARG(uap, size), l, retval);
964 
965 	vrele(vp);
966 	return (error);
967 }
968 
969 int
970 sys_flistxattr(struct lwp *l, const struct sys_flistxattr_args *uap, register_t *retval)
971 {
972 	/* {
973 		syscallarg(int) fd;
974 		syscallarg(char *) list;
975 		syscallarg(size_t) size;
976 	} */
977 	struct file *fp;
978 	struct vnode *vp;
979 	int error;
980 
981 	error = fd_getvnode(SCARG(uap, fd), &fp);
982 	if (error)
983 		return (error);
984 	vp = (struct vnode *) fp->f_data;
985 
986 	error = extattr_list_vp(vp, EXTATTR_NAMESPACE_USER,
987 	    SCARG(uap, list), SCARG(uap, size), l, retval);
988 
989 	fd_putfile(SCARG(uap, fd));
990 	return (error);
991 }
992 
993 int
994 sys_removexattr(struct lwp *l, const struct sys_removexattr_args *uap, register_t *retval)
995 {
996 	/* {
997 		syscallarg(const char *) path;
998 		syscallarg(const char *) name;
999 	} */
1000 	struct vnode *vp;
1001 	char attrname[XATTR_NAME_MAX];
1002 	int error;
1003 
1004 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
1005 	    NULL);
1006 	if (error)
1007 		return (error);
1008 
1009 	error = namei_simple_user(SCARG(uap, path),
1010 				NSM_FOLLOW_NOEMULROOT, &vp);
1011 	if (error)
1012 		return (error);
1013 
1014 	error = extattr_delete_vp(vp, EXTATTR_NAMESPACE_USER,
1015 	    attrname, l);
1016 
1017 	vrele(vp);
1018 	return (error);
1019 }
1020 
1021 int
1022 sys_lremovexattr(struct lwp *l, const struct sys_lremovexattr_args *uap, register_t *retval)
1023 {
1024 	/* {
1025 		syscallarg(const char *) path;
1026 		syscallarg(const char *) name;
1027 	} */
1028 	struct vnode *vp;
1029 	char attrname[XATTR_NAME_MAX];
1030 	int error;
1031 
1032 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
1033 	    NULL);
1034 	if (error)
1035 		return (error);
1036 
1037 	error = namei_simple_user(SCARG(uap, path),
1038 				NSM_NOFOLLOW_NOEMULROOT, &vp);
1039 	if (error)
1040 		return (error);
1041 
1042 	error = extattr_delete_vp(vp, EXTATTR_NAMESPACE_USER,
1043 	    attrname, l);
1044 
1045 	vrele(vp);
1046 	return (error);
1047 }
1048 
1049 int
1050 sys_fremovexattr(struct lwp *l, const struct sys_fremovexattr_args *uap, register_t *retval)
1051 {
1052 	/* {
1053 		syscallarg(int) fd;
1054 		syscallarg(const char *) name;
1055 	} */
1056 	struct file *fp;
1057 	struct vnode *vp;
1058 	char attrname[XATTR_NAME_MAX];
1059 	int error;
1060 
1061 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
1062 	    NULL);
1063 	if (error)
1064 		return (error);
1065 
1066 	error = fd_getvnode(SCARG(uap, fd), &fp);
1067 	if (error)
1068 		return (error);
1069 	vp = (struct vnode *) fp->f_data;
1070 
1071 	error = extattr_delete_vp(vp, EXTATTR_NAMESPACE_USER,
1072 	    attrname, l);
1073 
1074 	fd_putfile(SCARG(uap, fd));
1075 	return (error);
1076 }
1077