xref: /netbsd-src/sys/kern/vfs_xattr.c (revision b5677b36047b601b9addaaa494a58ceae82c2a6c)
1 /*	$NetBSD: vfs_xattr.c,v 1.19 2008/06/23 11:30:41 ad 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.19 2008/06/23 11:30:41 ad 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