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