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