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