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