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