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