Home | History | Annotate | Line # | Download | only in kern
vfs_xattr.c revision 1.17.4.4
      1 /*	$NetBSD: vfs_xattr.c,v 1.17.4.4 2010/08/11 22:54:45 yamt 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.17.4.4 2010/08/11 22:54:45 yamt 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 nameidata file_nd;
    154 	char attrname[EXTATTR_MAXNAMELEN];
    155 	int error;
    156 
    157 	if (SCARG(uap, attrname) != NULL) {
    158 		error = copyinstr(SCARG(uap, attrname), attrname,
    159 		    sizeof(attrname), NULL);
    160 		if (error)
    161 			return (error);
    162 	}
    163 
    164 	error = namei_simple_user(SCARG(uap, path),
    165 				NSM_FOLLOW_NOEMULROOT, &path_vp);
    166 	if (error) {
    167 		return (error);
    168 	}
    169 
    170 	file_vp = NULL;
    171 	if (SCARG(uap, filename) != NULL) {
    172 		NDINIT(&file_nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
    173 		    SCARG(uap, filename));
    174 		error = namei(&file_nd);
    175 		if (error) {
    176 			vrele(path_vp);
    177 			return (error);
    178 		}
    179 		file_vp = file_nd.ni_vp;
    180 	}
    181 
    182 	error = VFS_EXTATTRCTL(path_vp->v_mount, SCARG(uap, cmd), file_vp,
    183 	    SCARG(uap, attrnamespace),
    184 	    SCARG(uap, attrname) != NULL ? attrname : NULL);
    185 
    186 	if (file_vp != NULL)
    187 		vrele(file_vp);
    188 	vrele(path_vp);
    189 
    190 	return (error);
    191 }
    192 
    193 /*****************************************************************************
    194  * Internal routines to manipulate file system extended attributes:
    195  *	- set
    196  *	- get
    197  *	- delete
    198  *	- list
    199  *****************************************************************************/
    200 
    201 /*
    202  * extattr_set_vp:
    203  *
    204  *	Set a named extended attribute on a file or directory.
    205  */
    206 static int
    207 extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname,
    208     const void *data, size_t nbytes, struct lwp *l, register_t *retval)
    209 {
    210 	struct uio auio;
    211 	struct iovec aiov;
    212 	ssize_t cnt;
    213 	int error;
    214 
    215 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
    216 
    217 	aiov.iov_base = __UNCONST(data);	/* XXXUNCONST kills const */
    218 	aiov.iov_len = nbytes;
    219 	auio.uio_iov = &aiov;
    220 	auio.uio_iovcnt = 1;
    221 	auio.uio_offset = 0;
    222 	if (nbytes > INT_MAX) {
    223 		error = EINVAL;
    224 		goto done;
    225 	}
    226 	auio.uio_resid = nbytes;
    227 	auio.uio_rw = UIO_WRITE;
    228 	KASSERT(l == curlwp);
    229 	auio.uio_vmspace = l->l_proc->p_vmspace;
    230 	cnt = nbytes;
    231 
    232 	error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio, l->l_cred);
    233 	cnt -= auio.uio_resid;
    234 	retval[0] = cnt;
    235 
    236  done:
    237 	VOP_UNLOCK(vp);
    238 	return (error);
    239 }
    240 
    241 /*
    242  * extattr_get_vp:
    243  *
    244  *	Get a named extended attribute on a file or directory.
    245  */
    246 static int
    247 extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname,
    248     void *data, size_t nbytes, struct lwp *l, register_t *retval)
    249 {
    250 	struct uio auio, *auiop;
    251 	struct iovec aiov;
    252 	ssize_t cnt;
    253 	size_t size, *sizep;
    254 	int error;
    255 
    256 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
    257 
    258 	/*
    259 	 * Slightly unusual semantics: if the user provides a NULL data
    260 	 * pointer, they don't want to receive the data, just the maximum
    261 	 * read length.
    262 	 */
    263 	auiop = NULL;
    264 	sizep = NULL;
    265 	cnt = 0;
    266 	if (data != NULL) {
    267 		aiov.iov_base = data;
    268 		aiov.iov_len = nbytes;
    269 		auio.uio_iov = &aiov;
    270 		auio.uio_offset = 0;
    271 		if (nbytes > INT_MAX) {
    272 			error = EINVAL;
    273 			goto done;
    274 		}
    275 		auio.uio_resid = nbytes;
    276 		auio.uio_rw = UIO_READ;
    277 		KASSERT(l == curlwp);
    278 		auio.uio_vmspace = l->l_proc->p_vmspace;
    279 		auiop = &auio;
    280 		cnt = nbytes;
    281 	} else
    282 		sizep = &size;
    283 
    284 	error = VOP_GETEXTATTR(vp, attrnamespace, attrname, auiop, sizep,
    285 	    l->l_cred);
    286 
    287 	if (auiop != NULL) {
    288 		cnt -= auio.uio_resid;
    289 		retval[0] = cnt;
    290 	} else
    291 		retval[0] = size;
    292 
    293  done:
    294 	VOP_UNLOCK(vp);
    295 	return (error);
    296 }
    297 
    298 /*
    299  * extattr_delete_vp:
    300  *
    301  *	Delete a named extended attribute on a file or directory.
    302  */
    303 static int
    304 extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname,
    305     struct lwp *l)
    306 {
    307 	int error;
    308 
    309 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
    310 
    311 	error = VOP_DELETEEXTATTR(vp, attrnamespace, attrname, l->l_cred);
    312 	if (error == EOPNOTSUPP)
    313 		error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL,
    314 		    l->l_cred);
    315 
    316 	VOP_UNLOCK(vp);
    317 	return (error);
    318 }
    319 
    320 /*
    321  * extattr_list_vp:
    322  *
    323  *	Retrieve a list of extended attributes on a file or directory.
    324  */
    325 static int
    326 extattr_list_vp(struct vnode *vp, int attrnamespace, void *data, size_t nbytes,
    327     struct lwp *l, register_t *retval)
    328 {
    329 	struct uio auio, *auiop;
    330 	size_t size, *sizep;
    331 	struct iovec aiov;
    332 	ssize_t cnt;
    333 	int error;
    334 
    335 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
    336 
    337 	auiop = NULL;
    338 	sizep = NULL;
    339 	cnt = 0;
    340 	if (data != NULL) {
    341 		aiov.iov_base = data;
    342 		aiov.iov_len = nbytes;
    343 		auio.uio_iov = &aiov;
    344 		auio.uio_offset = 0;
    345 		if (nbytes > INT_MAX) {
    346 			error = EINVAL;
    347 			goto done;
    348 		}
    349 		auio.uio_resid = nbytes;
    350 		auio.uio_rw = UIO_READ;
    351 		KASSERT(l == curlwp);
    352 		auio.uio_vmspace = l->l_proc->p_vmspace;
    353 		auiop = &auio;
    354 		cnt = nbytes;
    355 	} else
    356 		sizep = &size;
    357 
    358 	error = VOP_LISTEXTATTR(vp, attrnamespace, auiop, sizep, l->l_cred);
    359 
    360 	if (auiop != NULL) {
    361 		cnt -= auio.uio_resid;
    362 		retval[0] = cnt;
    363 	} else
    364 		retval[0] = size;
    365 
    366  done:
    367 	VOP_UNLOCK(vp);
    368 	return (error);
    369 }
    370 
    371 /*****************************************************************************
    372  * BSD <sys/extattr.h> API for file system extended attributes
    373  *****************************************************************************/
    374 
    375 int
    376 sys_extattr_set_fd(struct lwp *l, const struct sys_extattr_set_fd_args *uap, register_t *retval)
    377 {
    378 	/* {
    379 		syscallarg(int) fd;
    380 		syscallarg(int) attrnamespace;
    381 		syscallarg(const char *) attrname;
    382 		syscallarg(const void *) data;
    383 		syscallarg(size_t) nbytes;
    384 	} */
    385 	struct file *fp;
    386 	struct vnode *vp;
    387 	char attrname[EXTATTR_MAXNAMELEN];
    388 	int error;
    389 
    390 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
    391 	    NULL);
    392 	if (error)
    393 		return (error);
    394 
    395 	error = fd_getvnode(SCARG(uap, fd), &fp);
    396 	if (error)
    397 		return (error);
    398 	vp = (struct vnode *) fp->f_data;
    399 
    400 	error = extattr_set_vp(vp, SCARG(uap, attrnamespace), attrname,
    401 	    SCARG(uap, data), SCARG(uap, nbytes), l, retval);
    402 
    403 	fd_putfile(SCARG(uap, fd));
    404 	return (error);
    405 }
    406 
    407 int
    408 sys_extattr_set_file(struct lwp *l, const struct sys_extattr_set_file_args *uap, register_t *retval)
    409 {
    410 	/* {
    411 		syscallarg(const char *) path;
    412 		syscallarg(int) attrnamespace;
    413 		syscallarg(const char *) attrname;
    414 		syscallarg(const void *) data;
    415 		syscallarg(size_t) nbytes;
    416 	} */
    417 	struct vnode *vp;
    418 	char attrname[EXTATTR_MAXNAMELEN];
    419 	int error;
    420 
    421 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
    422 	    NULL);
    423 	if (error)
    424 		return (error);
    425 
    426 	error = namei_simple_user(SCARG(uap, path),
    427 				NSM_FOLLOW_NOEMULROOT, &vp);
    428 	if (error)
    429 		return (error);
    430 
    431 	error = extattr_set_vp(vp, SCARG(uap, attrnamespace), attrname,
    432 	    SCARG(uap, data), SCARG(uap, nbytes), l, retval);
    433 
    434 	vrele(vp);
    435 	return (error);
    436 }
    437 
    438 int
    439 sys_extattr_set_link(struct lwp *l, const struct sys_extattr_set_link_args *uap, register_t *retval)
    440 {
    441 	/* {
    442 		syscallarg(const char *) path;
    443 		syscallarg(int) attrnamespace;
    444 		syscallarg(const char *) attrname;
    445 		syscallarg(const void *) data;
    446 		syscallarg(size_t) nbytes;
    447 	} */
    448 	struct vnode *vp;
    449 	char attrname[EXTATTR_MAXNAMELEN];
    450 	int error;
    451 
    452 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
    453 	    NULL);
    454 	if (error)
    455 		return (error);
    456 
    457 	error = namei_simple_user(SCARG(uap, path),
    458 				NSM_NOFOLLOW_NOEMULROOT, &vp);
    459 	if (error)
    460 		return (error);
    461 
    462 	error = extattr_set_vp(vp, SCARG(uap, attrnamespace), attrname,
    463 	    SCARG(uap, data), SCARG(uap, nbytes), l, retval);
    464 
    465 	vrele(vp);
    466 	return (error);
    467 }
    468 
    469 int
    470 sys_extattr_get_fd(struct lwp *l, const struct sys_extattr_get_fd_args *uap, register_t *retval)
    471 {
    472 	/* {
    473 		syscallarg(int) fd;
    474 		syscallarg(int) attrnamespace;
    475 		syscallarg(const char *) attrname;
    476 		syscallarg(void *) data;
    477 		syscallarg(size_t) nbytes;
    478 	} */
    479 	struct file *fp;
    480 	struct vnode *vp;
    481 	char attrname[EXTATTR_MAXNAMELEN];
    482 	int error;
    483 
    484 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
    485 	    NULL);
    486 	if (error)
    487 		return (error);
    488 
    489 	error = fd_getvnode(SCARG(uap, fd), &fp);
    490 	if (error)
    491 		return (error);
    492 	vp = (struct vnode *) fp->f_data;
    493 
    494 	error = extattr_get_vp(vp, SCARG(uap, attrnamespace), attrname,
    495 	    SCARG(uap, data), SCARG(uap, nbytes), l, retval);
    496 
    497 	fd_putfile(SCARG(uap, fd));
    498 	return (error);
    499 }
    500 
    501 int
    502 sys_extattr_get_file(struct lwp *l, const struct sys_extattr_get_file_args *uap, register_t *retval)
    503 {
    504 	/* {
    505 		syscallarg(const char *) path;
    506 		syscallarg(int) attrnamespace;
    507 		syscallarg(const char *) attrname;
    508 		syscallarg(void *) data;
    509 		syscallarg(size_t) nbytes;
    510 	} */
    511 	struct vnode *vp;
    512 	char attrname[EXTATTR_MAXNAMELEN];
    513 	int error;
    514 
    515 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
    516 	    NULL);
    517 	if (error)
    518 		return (error);
    519 
    520 	error = namei_simple_user(SCARG(uap, path),
    521 				NSM_FOLLOW_NOEMULROOT, &vp);
    522 	if (error)
    523 		return (error);
    524 
    525 	error = extattr_get_vp(vp, SCARG(uap, attrnamespace), attrname,
    526 	    SCARG(uap, data), SCARG(uap, nbytes), l, retval);
    527 
    528 	vrele(vp);
    529 	return (error);
    530 }
    531 
    532 int
    533 sys_extattr_get_link(struct lwp *l, const struct sys_extattr_get_link_args *uap, register_t *retval)
    534 {
    535 	/* {
    536 		syscallarg(const char *) path;
    537 		syscallarg(int) attrnamespace;
    538 		syscallarg(const char *) attrname;
    539 		syscallarg(void *) data;
    540 		syscallarg(size_t) nbytes;
    541 	} */
    542 	struct vnode *vp;
    543 	char attrname[EXTATTR_MAXNAMELEN];
    544 	int error;
    545 
    546 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
    547 	    NULL);
    548 	if (error)
    549 		return (error);
    550 
    551 	error = namei_simple_user(SCARG(uap, path),
    552 				NSM_NOFOLLOW_NOEMULROOT, &vp);
    553 	if (error)
    554 		return (error);
    555 
    556 	error = extattr_get_vp(vp, SCARG(uap, attrnamespace), attrname,
    557 	    SCARG(uap, data), SCARG(uap, nbytes), l, retval);
    558 
    559 	vrele(vp);
    560 	return (error);
    561 }
    562 
    563 int
    564 sys_extattr_delete_fd(struct lwp *l, const struct sys_extattr_delete_fd_args *uap, register_t *retval)
    565 {
    566 	/* {
    567 		syscallarg(int) fd;
    568 		syscallarg(int) attrnamespace;
    569 		syscallarg(const char *) attrname;
    570 	} */
    571 	struct file *fp;
    572 	struct vnode *vp;
    573 	char attrname[EXTATTR_MAXNAMELEN];
    574 	int error;
    575 
    576 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
    577 	    NULL);
    578 	if (error)
    579 		return (error);
    580 
    581 	error = fd_getvnode(SCARG(uap, fd), &fp);
    582 	if (error)
    583 		return (error);
    584 	vp = (struct vnode *) fp->f_data;
    585 
    586 	error = extattr_delete_vp(vp, SCARG(uap, attrnamespace), attrname, l);
    587 
    588 	fd_putfile(SCARG(uap, fd));
    589 	return (error);
    590 }
    591 
    592 int
    593 sys_extattr_delete_file(struct lwp *l, const struct sys_extattr_delete_file_args *uap, register_t *retval)
    594 {
    595 	/* {
    596 		syscallarg(const char *) path;
    597 		syscallarg(int) attrnamespace;
    598 		syscallarg(const char *) attrname;
    599 	} */
    600 	struct vnode *vp;
    601 	char attrname[EXTATTR_MAXNAMELEN];
    602 	int error;
    603 
    604 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
    605 	    NULL);
    606 	if (error)
    607 		return (error);
    608 
    609 	error = namei_simple_user(SCARG(uap, path),
    610 				NSM_FOLLOW_NOEMULROOT, &vp);
    611 	if (error)
    612 		return (error);
    613 
    614 	error = extattr_delete_vp(vp, SCARG(uap, attrnamespace), attrname, l);
    615 
    616 	vrele(vp);
    617 	return (error);
    618 }
    619 
    620 int
    621 sys_extattr_delete_link(struct lwp *l, const struct sys_extattr_delete_link_args *uap, register_t *retval)
    622 {
    623 	/* {
    624 		syscallarg(const char *) path;
    625 		syscallarg(int) attrnamespace;
    626 		syscallarg(const char *) attrname;
    627 	} */
    628 	struct vnode *vp;
    629 	char attrname[EXTATTR_MAXNAMELEN];
    630 	int error;
    631 
    632 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
    633 	    NULL);
    634 	if (error)
    635 		return (error);
    636 
    637 	error = namei_simple_user(SCARG(uap, path),
    638 				NSM_NOFOLLOW_NOEMULROOT, &vp);
    639 	if (error)
    640 		return (error);
    641 
    642 	error = extattr_delete_vp(vp, SCARG(uap, attrnamespace), attrname, l);
    643 
    644 	vrele(vp);
    645 	return (error);
    646 }
    647 
    648 int
    649 sys_extattr_list_fd(struct lwp *l, const struct sys_extattr_list_fd_args *uap, register_t *retval)
    650 {
    651 	/* {
    652 		syscallarg(int) fd;
    653 		syscallarg(int) attrnamespace;
    654 		syscallarg(void *) data;
    655 		syscallarg(size_t) nbytes;
    656 	} */
    657 	struct file *fp;
    658 	struct vnode *vp;
    659 	int error;
    660 
    661 	error = fd_getvnode(SCARG(uap, fd), &fp);
    662 	if (error)
    663 		return (error);
    664 	vp = (struct vnode *) fp->f_data;
    665 
    666 	error = extattr_list_vp(vp, SCARG(uap, attrnamespace),
    667 	    SCARG(uap, data), SCARG(uap, nbytes), l, retval);
    668 
    669 	fd_putfile(SCARG(uap, fd));
    670 	return (error);
    671 }
    672 
    673 int
    674 sys_extattr_list_file(struct lwp *l, const struct sys_extattr_list_file_args *uap, register_t *retval)
    675 {
    676 	/* {
    677 		syscallarg(const char *) path;
    678 		syscallarg(int) attrnamespace;
    679 		syscallarg(void *) data;
    680 		syscallarg(size_t) nbytes;
    681 	} */
    682 	struct vnode *vp;
    683 	int error;
    684 
    685 	error = namei_simple_user(SCARG(uap, path),
    686 				NSM_FOLLOW_NOEMULROOT, &vp);
    687 	if (error)
    688 		return (error);
    689 
    690 	error = extattr_list_vp(vp, SCARG(uap, attrnamespace),
    691 	    SCARG(uap, data), SCARG(uap, nbytes), l, retval);
    692 
    693 	vrele(vp);
    694 	return (error);
    695 }
    696 
    697 int
    698 sys_extattr_list_link(struct lwp *l, const struct sys_extattr_list_link_args *uap, register_t *retval)
    699 {
    700 	/* {
    701 		syscallarg(const char *) path;
    702 		syscallarg(int) attrnamespace;
    703 		syscallarg(void *) data;
    704 		syscallarg(size_t) nbytes;
    705 	} */
    706 	struct vnode *vp;
    707 	int error;
    708 
    709 	error = namei_simple_user(SCARG(uap, path),
    710 				NSM_NOFOLLOW_NOEMULROOT, &vp);
    711 	if (error)
    712 		return (error);
    713 
    714 	error = extattr_list_vp(vp, SCARG(uap, attrnamespace),
    715 	    SCARG(uap, data), SCARG(uap, nbytes), l, retval);
    716 
    717 	vrele(vp);
    718 	return (error);
    719 }
    720 
    721 /*****************************************************************************
    722  * Linux-compatible <sys/xattr.h> API for file system extended attributes
    723  *****************************************************************************/
    724 
    725 int
    726 sys_setxattr(struct lwp *l, const struct sys_setxattr_args *uap, register_t *retval)
    727 {
    728 	/* {
    729 		syscallarg(const char *) path;
    730 		syscallarg(const char *) name;
    731 		syscallarg(void *) value;
    732 		syscallarg(size_t) size;
    733 		syscallarg(int) flags;
    734 	} */
    735 	struct vnode *vp;
    736 	char attrname[XATTR_NAME_MAX];
    737 	int error;
    738 
    739 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
    740 	    NULL);
    741 	if (error)
    742 		return (error);
    743 
    744 	error = namei_simple_user(SCARG(uap, path),
    745 				NSM_FOLLOW_NOEMULROOT, &vp);
    746 	if (error)
    747 		return (error);
    748 
    749 	/* XXX flags */
    750 
    751 	error = extattr_set_vp(vp, EXTATTR_NAMESPACE_USER,
    752 	    attrname, SCARG(uap, value), SCARG(uap, size), l, retval);
    753 
    754 	vrele(vp);
    755 	return (error);
    756 }
    757 
    758 int
    759 sys_lsetxattr(struct lwp *l, const struct sys_lsetxattr_args *uap, register_t *retval)
    760 {
    761 	/* {
    762 		syscallarg(const char *) path;
    763 		syscallarg(const char *) name;
    764 		syscallarg(void *) value;
    765 		syscallarg(size_t) size;
    766 		syscallarg(int) flags;
    767 	} */
    768 	struct vnode *vp;
    769 	char attrname[XATTR_NAME_MAX];
    770 	int error;
    771 
    772 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
    773 	    NULL);
    774 	if (error)
    775 		return (error);
    776 
    777 	error = namei_simple_user(SCARG(uap, path),
    778 				NSM_NOFOLLOW_NOEMULROOT, &vp);
    779 	if (error)
    780 		return (error);
    781 
    782 	/* XXX flags */
    783 
    784 	error = extattr_set_vp(vp, EXTATTR_NAMESPACE_USER,
    785 	    attrname, SCARG(uap, value), SCARG(uap, size), l, retval);
    786 
    787 	vrele(vp);
    788 	return (error);
    789 }
    790 
    791 int
    792 sys_fsetxattr(struct lwp *l, const struct sys_fsetxattr_args *uap, register_t *retval)
    793 {
    794 	/* {
    795 		syscallarg(int) fd;
    796 		syscallarg(const char *) name;
    797 		syscallarg(void *) value;
    798 		syscallarg(size_t) size;
    799 		syscallarg(int) flags;
    800 	} */
    801 	struct file *fp;
    802 	struct vnode *vp;
    803 	char attrname[XATTR_NAME_MAX];
    804 	int error;
    805 
    806 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
    807 	    NULL);
    808 	if (error)
    809 		return (error);
    810 
    811 	error = fd_getvnode(SCARG(uap, fd), &fp);
    812 	if (error)
    813 		return (error);
    814 	vp = (struct vnode *) fp->f_data;
    815 
    816 	/* XXX flags */
    817 
    818 	error = extattr_set_vp(vp, EXTATTR_NAMESPACE_USER,
    819 	    attrname, SCARG(uap, value), SCARG(uap, size), l, retval);
    820 
    821 	fd_putfile(SCARG(uap, fd));
    822 	return (error);
    823 }
    824 
    825 int
    826 sys_getxattr(struct lwp *l, const struct sys_getxattr_args *uap, register_t *retval)
    827 {
    828 	/* {
    829 		syscallarg(const char *) path;
    830 		syscallarg(const char *) name;
    831 		syscallarg(void *) value;
    832 		syscallarg(size_t) size;
    833 	} */
    834 	struct vnode *vp;
    835 	char attrname[XATTR_NAME_MAX];
    836 	int error;
    837 
    838 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
    839 	    NULL);
    840 	if (error)
    841 		return (error);
    842 
    843 	error = namei_simple_user(SCARG(uap, path),
    844 				NSM_FOLLOW_NOEMULROOT, &vp);
    845 	if (error)
    846 		return (error);
    847 
    848 	error = extattr_get_vp(vp, EXTATTR_NAMESPACE_USER,
    849 	    attrname, SCARG(uap, value), SCARG(uap, size), l, retval);
    850 
    851 	vrele(vp);
    852 	return (error);
    853 }
    854 
    855 int
    856 sys_lgetxattr(struct lwp *l, const struct sys_lgetxattr_args *uap, register_t *retval)
    857 {
    858 	/* {
    859 		syscallarg(const char *) path;
    860 		syscallarg(const char *) name;
    861 		syscallarg(void *) value;
    862 		syscallarg(size_t) size;
    863 	} */
    864 	struct vnode *vp;
    865 	char attrname[XATTR_NAME_MAX];
    866 	int error;
    867 
    868 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
    869 	    NULL);
    870 	if (error)
    871 		return (error);
    872 
    873 	error = namei_simple_user(SCARG(uap, path),
    874 				NSM_NOFOLLOW_NOEMULROOT, &vp);
    875 	if (error)
    876 		return (error);
    877 
    878 	error = extattr_get_vp(vp, EXTATTR_NAMESPACE_USER,
    879 	    attrname, SCARG(uap, value), SCARG(uap, size), l, retval);
    880 
    881 	vrele(vp);
    882 	return (error);
    883 }
    884 
    885 int
    886 sys_fgetxattr(struct lwp *l, const struct sys_fgetxattr_args *uap, register_t *retval)
    887 {
    888 	/* {
    889 		syscallarg(int) fd;
    890 		syscallarg(const char *) name;
    891 		syscallarg(void *) value;
    892 		syscallarg(size_t) size;
    893 	} */
    894 	struct file *fp;
    895 	struct vnode *vp;
    896 	char attrname[XATTR_NAME_MAX];
    897 	int error;
    898 
    899 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
    900 	    NULL);
    901 	if (error)
    902 		return (error);
    903 
    904 	error = fd_getvnode(SCARG(uap, fd), &fp);
    905 	if (error)
    906 		return (error);
    907 	vp = (struct vnode *) fp->f_data;
    908 
    909 	error = extattr_get_vp(vp, EXTATTR_NAMESPACE_USER,
    910 	    attrname, SCARG(uap, value), SCARG(uap, size), l, retval);
    911 
    912 	fd_putfile(SCARG(uap, fd));
    913 	return (error);
    914 }
    915 
    916 int
    917 sys_listxattr(struct lwp *l, const struct sys_listxattr_args *uap, register_t *retval)
    918 {
    919 	/* {
    920 		syscallarg(const char *) path;
    921 		syscallarg(char *) list;
    922 		syscallarg(size_t) size;
    923 	} */
    924 	struct vnode *vp;
    925 	int error;
    926 
    927 	error = namei_simple_user(SCARG(uap, path),
    928 				NSM_FOLLOW_NOEMULROOT, &vp);
    929 	if (error)
    930 		return (error);
    931 
    932 	error = extattr_list_vp(vp, EXTATTR_NAMESPACE_USER,
    933 	    SCARG(uap, list), SCARG(uap, size), l, retval);
    934 
    935 	vrele(vp);
    936 	return (error);
    937 }
    938 
    939 int
    940 sys_llistxattr(struct lwp *l, const struct sys_llistxattr_args *uap, register_t *retval)
    941 {
    942 	/* {
    943 		syscallarg(const char *) path;
    944 		syscallarg(char *) list;
    945 		syscallarg(size_t) size;
    946 	} */
    947 	struct vnode *vp;
    948 	int error;
    949 
    950 	error = namei_simple_user(SCARG(uap, path),
    951 				NSM_NOFOLLOW_NOEMULROOT, &vp);
    952 	if (error)
    953 		return (error);
    954 
    955 	error = extattr_list_vp(vp, EXTATTR_NAMESPACE_USER,
    956 	    SCARG(uap, list), SCARG(uap, size), l, retval);
    957 
    958 	vrele(vp);
    959 	return (error);
    960 }
    961 
    962 int
    963 sys_flistxattr(struct lwp *l, const struct sys_flistxattr_args *uap, register_t *retval)
    964 {
    965 	/* {
    966 		syscallarg(int) fd;
    967 		syscallarg(char *) list;
    968 		syscallarg(size_t) size;
    969 	} */
    970 	struct file *fp;
    971 	struct vnode *vp;
    972 	int error;
    973 
    974 	error = fd_getvnode(SCARG(uap, fd), &fp);
    975 	if (error)
    976 		return (error);
    977 	vp = (struct vnode *) fp->f_data;
    978 
    979 	error = extattr_list_vp(vp, EXTATTR_NAMESPACE_USER,
    980 	    SCARG(uap, list), SCARG(uap, size), l, retval);
    981 
    982 	fd_putfile(SCARG(uap, fd));
    983 	return (error);
    984 }
    985 
    986 int
    987 sys_removexattr(struct lwp *l, const struct sys_removexattr_args *uap, register_t *retval)
    988 {
    989 	/* {
    990 		syscallarg(const char *) path;
    991 		syscallarg(const char *) name;
    992 	} */
    993 	struct vnode *vp;
    994 	char attrname[XATTR_NAME_MAX];
    995 	int error;
    996 
    997 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
    998 	    NULL);
    999 	if (error)
   1000 		return (error);
   1001 
   1002 	error = namei_simple_user(SCARG(uap, path),
   1003 				NSM_FOLLOW_NOEMULROOT, &vp);
   1004 	if (error)
   1005 		return (error);
   1006 
   1007 	error = extattr_delete_vp(vp, EXTATTR_NAMESPACE_USER,
   1008 	    attrname, l);
   1009 
   1010 	vrele(vp);
   1011 	return (error);
   1012 }
   1013 
   1014 int
   1015 sys_lremovexattr(struct lwp *l, const struct sys_lremovexattr_args *uap, register_t *retval)
   1016 {
   1017 	/* {
   1018 		syscallarg(const char *) path;
   1019 		syscallarg(const char *) name;
   1020 	} */
   1021 	struct vnode *vp;
   1022 	char attrname[XATTR_NAME_MAX];
   1023 	int error;
   1024 
   1025 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
   1026 	    NULL);
   1027 	if (error)
   1028 		return (error);
   1029 
   1030 	error = namei_simple_user(SCARG(uap, path),
   1031 				NSM_NOFOLLOW_NOEMULROOT, &vp);
   1032 	if (error)
   1033 		return (error);
   1034 
   1035 	error = extattr_delete_vp(vp, EXTATTR_NAMESPACE_USER,
   1036 	    attrname, l);
   1037 
   1038 	vrele(vp);
   1039 	return (error);
   1040 }
   1041 
   1042 int
   1043 sys_fremovexattr(struct lwp *l, const struct sys_fremovexattr_args *uap, register_t *retval)
   1044 {
   1045 	/* {
   1046 		syscallarg(int) fd;
   1047 		syscallarg(const char *) name;
   1048 	} */
   1049 	struct file *fp;
   1050 	struct vnode *vp;
   1051 	char attrname[XATTR_NAME_MAX];
   1052 	int error;
   1053 
   1054 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
   1055 	    NULL);
   1056 	if (error)
   1057 		return (error);
   1058 
   1059 	error = fd_getvnode(SCARG(uap, fd), &fp);
   1060 	if (error)
   1061 		return (error);
   1062 	vp = (struct vnode *) fp->f_data;
   1063 
   1064 	error = extattr_delete_vp(vp, EXTATTR_NAMESPACE_USER,
   1065 	    attrname, l);
   1066 
   1067 	fd_putfile(SCARG(uap, fd));
   1068 	return (error);
   1069 }
   1070