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