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