xref: /netbsd-src/sys/kern/vfs_xattr.c (revision e5548b402ae4c44fb816de42c7bba9581ce23ef5)
1 /*	$NetBSD: vfs_xattr.c,v 1.4 2005/12/11 12:24:30 christos Exp $	*/
2 
3 /*-
4  * Copyright (c) 2005 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.4 2005/12/11 12:24:30 christos 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/sa.h>
94 #include <sys/syscallargs.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     struct ucred *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 (suser(cred, &l->l_proc->p_acflag));
117 
118 	case EXTATTR_NAMESPACE_USER:
119 		return (VOP_ACCESS(vp, access, cred, l));
120 
121 	default:
122 		return (EPERM);
123 	}
124 }
125 
126 /*
127  * Default vfs_extattrctl routine for file systems that do not support
128  * it.
129  */
130 /*ARGSUSED*/
131 int
132 vfs_stdextattrctl(struct mount *mp, int cmt, struct vnode *vp,
133     int attrnamespace, const char *attrname, struct lwp *l)
134 {
135 
136 	if (vp != NULL)
137 		VOP_UNLOCK(vp, 0);
138 	return (EOPNOTSUPP);
139 }
140 
141 /*
142  * Push extended attribute configuration information into the file
143  * system.
144  *
145  * NOTE: Not all file systems that support extended attributes will
146  * require the use of this system call.
147  */
148 int
149 sys_extattrctl(struct lwp *l, void *v, register_t *retval)
150 {
151 	struct sys_extattrctl_args /* {
152 		syscallarg(const char *) path;
153 		syscallarg(int) cmd;
154 		syscallarg(const char *) filename;
155 		syscallarg(int) attrnamespace;
156 		syscallarg(const char *) attrname;
157 	} */ *uap = v;
158 	struct vnode *vp;
159 	struct nameidata nd;
160 	struct mount *mp;
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), l);
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), l);
182 	error = namei(&nd);
183 	if (error) {
184 		if (vp != NULL)
185 			vput(vp);
186 		return (error);
187 	}
188 
189 	error = vn_start_write(nd.ni_vp, &mp, V_WAIT | V_PCATCH);
190 	if (error) {
191 		if (vp != NULL)
192 			vput(vp);
193 		return (error);
194 	}
195 
196 	error = VFS_EXTATTRCTL(mp, SCARG(uap, cmd), vp,
197 	    SCARG(uap, attrnamespace),
198 	    SCARG(uap, attrname) != NULL ? attrname : NULL, l);
199 
200 	vn_finished_write(mp, 0);
201 
202 	if (vp != NULL)
203 		vrele(vp);
204 
205 	return (error);
206 }
207 
208 /*****************************************************************************
209  * Internal routines to manipulate file system extended attributes:
210  *	- set
211  *	- get
212  *	- delete
213  *	- list
214  *****************************************************************************/
215 
216 /*
217  * extattr_set_vp:
218  *
219  *	Set a named extended attribute on a file or directory.
220  */
221 static int
222 extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname,
223     const void *data, size_t nbytes, struct lwp *l, register_t *retval)
224 {
225 	struct mount *mp;
226 	struct uio auio;
227 	struct iovec aiov;
228 	ssize_t cnt;
229 	int error;
230 
231 	error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH);
232 	if (error)
233 		return (error);
234 	VOP_LEASE(vp, l, l->l_proc->p_ucred, LEASE_WRITE);
235 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
236 
237 	aiov.iov_base = __UNCONST(data);	/* XXXUNCONST kills const */
238 	aiov.iov_len = nbytes;
239 	auio.uio_iov = &aiov;
240 	auio.uio_iovcnt = 1;
241 	auio.uio_offset = 0;
242 	if (nbytes > INT_MAX) {
243 		error = EINVAL;
244 		goto done;
245 	}
246 	auio.uio_resid = nbytes;
247 	auio.uio_rw = UIO_WRITE;
248 	auio.uio_segflg = UIO_USERSPACE;
249 	auio.uio_lwp = l;
250 	cnt = nbytes;
251 
252 	error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio,
253 	    l->l_proc->p_ucred, l);
254 	cnt -= auio.uio_resid;
255 	retval[0] = cnt;
256 
257  done:
258 	VOP_UNLOCK(vp, 0);
259 	vn_finished_write(mp, 0);
260 	return (error);
261 }
262 
263 /*
264  * extattr_get_vp:
265  *
266  *	Get a named extended attribute on a file or directory.
267  */
268 static int
269 extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname,
270     void *data, size_t nbytes, struct lwp *l, register_t *retval)
271 {
272 	struct uio auio, *auiop;
273 	struct iovec aiov;
274 	ssize_t cnt;
275 	size_t size, *sizep;
276 	int error;
277 
278 	VOP_LEASE(vp, l, l->l_proc->p_ucred, LEASE_READ);
279 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
280 
281 	/*
282 	 * Slightly unusual semantics: if the user provides a NULL data
283 	 * pointer, they don't want to receive the data, just the maximum
284 	 * read length.
285 	 */
286 	auiop = NULL;
287 	sizep = NULL;
288 	cnt = 0;
289 	if (data != NULL) {
290 		aiov.iov_base = data;
291 		aiov.iov_len = nbytes;
292 		auio.uio_iov = &aiov;
293 		auio.uio_offset = 0;
294 		if (nbytes > INT_MAX) {
295 			error = EINVAL;
296 			goto done;
297 		}
298 		auio.uio_resid = nbytes;
299 		auio.uio_rw = UIO_READ;
300 		auio.uio_segflg = UIO_USERSPACE;
301 		auio.uio_lwp = l;
302 		auiop = &auio;
303 		cnt = nbytes;
304 	} else
305 		sizep = &size;
306 
307 	error = VOP_GETEXTATTR(vp, attrnamespace, attrname, auiop, sizep,
308 	    l->l_proc->p_ucred, l);
309 
310 	if (auiop != NULL) {
311 		cnt -= auio.uio_resid;
312 		retval[0] = cnt;
313 	} else
314 		retval[0] = size;
315 
316  done:
317 	VOP_UNLOCK(vp, 0);
318 	return (error);
319 }
320 
321 /*
322  * extattr_delete_vp:
323  *
324  *	Delete a named extended attribute on a file or directory.
325  */
326 static int
327 extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname,
328     struct lwp *l)
329 {
330 	struct mount *mp;
331 	int error;
332 
333 	error = vn_start_write(vp, &mp, V_WAIT | V_PCATCH);
334 	if (error)
335 		return (error);
336 	VOP_LEASE(vp, l, l->l_proc->p_ucred, LEASE_WRITE);
337 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
338 
339 	error = VOP_DELETEEXTATTR(vp, attrnamespace, attrname, l->l_proc->p_ucred, l);
340 	if (error == EOPNOTSUPP)
341 		error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL,
342 		    l->l_proc->p_ucred, l);
343 
344 	VOP_UNLOCK(vp, 0);
345 	vn_finished_write(mp, 0);
346 	return (error);
347 }
348 
349 /*
350  * extattr_list_vp:
351  *
352  *	Retrieve a list of extended attributes on a file or directory.
353  */
354 static int
355 extattr_list_vp(struct vnode *vp, int attrnamespace, void *data, size_t nbytes,
356     struct lwp *l, register_t *retval)
357 {
358 	struct uio auio, *auiop;
359 	size_t size, *sizep;
360 	struct iovec aiov;
361 	ssize_t cnt;
362 	int error;
363 
364 	VOP_LEASE(vp, l, l->l_proc->p_ucred, LEASE_READ);
365 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
366 
367 	auiop = NULL;
368 	sizep = NULL;
369 	cnt = 0;
370 	if (data != NULL) {
371 		aiov.iov_base = data;
372 		aiov.iov_len = nbytes;
373 		auio.uio_iov = &aiov;
374 		auio.uio_offset = 0;
375 		if (nbytes > INT_MAX) {
376 			error = EINVAL;
377 			goto done;
378 		}
379 		auio.uio_resid = nbytes;
380 		auio.uio_rw = UIO_READ;
381 		auio.uio_segflg = UIO_USERSPACE;
382 		auio.uio_lwp = l;
383 		auiop = &auio;
384 		cnt = nbytes;
385 	} else
386 		sizep = &size;
387 
388 	error = VOP_LISTEXTATTR(vp, attrnamespace, auiop, sizep,
389 	    l->l_proc->p_ucred, l);
390 
391 	if (auiop != NULL) {
392 		cnt -= auio.uio_resid;
393 		retval[0] = cnt;
394 	} else
395 		retval[0] = size;
396 
397  done:
398 	VOP_UNLOCK(vp, 0);
399 	return (error);
400 }
401 
402 /*****************************************************************************
403  * BSD <sys/extattr.h> API for file system extended attributes
404  *****************************************************************************/
405 
406 int
407 sys_extattr_set_fd(struct lwp *l, void *v, register_t *retval)
408 {
409 	struct sys_extattr_set_fd_args /* {
410 		syscallarg(int) fd;
411 		syscallarg(int) attrnamespace;
412 		syscallarg(const char *) attrname;
413 		syscallarg(const void *) data;
414 		syscallarg(size_t) nbytes;
415 	} */ *uap = v;
416 	struct file *fp;
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 = getvnode(l->l_proc->p_fd, SCARG(uap, fd), &fp);
427 	if (error)
428 		return (error);
429 	vp = (struct vnode *) fp->f_data;
430 
431 	error = extattr_set_vp(vp, SCARG(uap, attrnamespace), attrname,
432 	    SCARG(uap, data), SCARG(uap, nbytes), l, retval);
433 
434 	FILE_UNUSE(fp, l);
435 	return (error);
436 }
437 
438 int
439 sys_extattr_set_file(struct lwp *l, void *v, register_t *retval)
440 {
441 	struct sys_extattr_set_file_args /* {
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 	} */ *uap = v;
448 	struct nameidata nd;
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 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
458 	error = namei(&nd);
459 	if (error)
460 		return (error);
461 
462 	error = extattr_set_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
463 	    SCARG(uap, data), SCARG(uap, nbytes), l, retval);
464 
465 	vrele(nd.ni_vp);
466 	return (error);
467 }
468 
469 int
470 sys_extattr_set_link(struct lwp *l, void *v, register_t *retval)
471 {
472 	struct sys_extattr_set_link_args /* {
473 		syscallarg(const char *) path;
474 		syscallarg(int) attrnamespace;
475 		syscallarg(const char *) attrname;
476 		syscallarg(const void *) data;
477 		syscallarg(size_t) nbytes;
478 	} */ *uap = v;
479 	struct nameidata nd;
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 	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
489 	error = namei(&nd);
490 	if (error)
491 		return (error);
492 
493 	error = extattr_set_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
494 	    SCARG(uap, data), SCARG(uap, nbytes), l, retval);
495 
496 	vrele(nd.ni_vp);
497 	return (error);
498 }
499 
500 int
501 sys_extattr_get_fd(struct lwp *l, void *v, register_t *retval)
502 {
503 	struct sys_extattr_get_fd_args /* {
504 		syscallarg(int) fd;
505 		syscallarg(int) attrnamespace;
506 		syscallarg(const char *) attrname;
507 		syscallarg(void *) data;
508 		syscallarg(size_t) nbytes;
509 	} */ *uap = v;
510 	struct file *fp;
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 = getvnode(l->l_proc->p_fd, SCARG(uap, fd), &fp);
521 	if (error)
522 		return (error);
523 	vp = (struct vnode *) fp->f_data;
524 
525 	error = extattr_get_vp(vp, SCARG(uap, attrnamespace), attrname,
526 	    SCARG(uap, data), SCARG(uap, nbytes), l, retval);
527 
528 	FILE_UNUSE(fp, l);
529 	return (error);
530 }
531 
532 int
533 sys_extattr_get_file(struct lwp *l, void *v, register_t *retval)
534 {
535 	struct sys_extattr_get_file_args /* {
536 		syscallarg(const char *) path;
537 		syscallarg(int) attrnamespace;
538 		syscallarg(const char *) attrname;
539 		syscallarg(void *) data;
540 		syscallarg(size_t) nbytes;
541 	} */ *uap = v;
542 	struct nameidata nd;
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 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
552 	error = namei(&nd);
553 	if (error)
554 		return (error);
555 
556 	error = extattr_get_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
557 	    SCARG(uap, data), SCARG(uap, nbytes), l, retval);
558 
559 	vrele(nd.ni_vp);
560 	return (error);
561 }
562 
563 int
564 sys_extattr_get_link(struct lwp *l, void *v, register_t *retval)
565 {
566 	struct sys_extattr_get_link_args /* {
567 		syscallarg(const char *) path;
568 		syscallarg(int) attrnamespace;
569 		syscallarg(const char *) attrname;
570 		syscallarg(void *) data;
571 		syscallarg(size_t) nbytes;
572 	} */ *uap = v;
573 	struct nameidata nd;
574 	char attrname[EXTATTR_MAXNAMELEN];
575 	int error;
576 
577 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
578 	    NULL);
579 	if (error)
580 		return (error);
581 
582 	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
583 	error = namei(&nd);
584 	if (error)
585 		return (error);
586 
587 	error = extattr_get_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
588 	    SCARG(uap, data), SCARG(uap, nbytes), l, retval);
589 
590 	vrele(nd.ni_vp);
591 	return (error);
592 }
593 
594 int
595 sys_extattr_delete_fd(struct lwp *l, void *v, register_t *retval)
596 {
597 	struct sys_extattr_delete_fd_args /* {
598 		syscallarg(int) fd;
599 		syscallarg(int) attrnamespace;
600 		syscallarg(const char *) attrname;
601 	} */ *uap = v;
602 	struct file *fp;
603 	struct vnode *vp;
604 	char attrname[EXTATTR_MAXNAMELEN];
605 	int error;
606 
607 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
608 	    NULL);
609 	if (error)
610 		return (error);
611 
612 	error = getvnode(l->l_proc->p_fd, SCARG(uap, fd), &fp);
613 	if (error)
614 		return (error);
615 	vp = (struct vnode *) fp->f_data;
616 
617 	error = extattr_delete_vp(vp, SCARG(uap, attrnamespace), attrname, l);
618 
619 	FILE_UNUSE(fp, l);
620 	return (error);
621 }
622 
623 int
624 sys_extattr_delete_file(struct lwp *l, void *v, register_t *retval)
625 {
626 	struct sys_extattr_delete_file_args /* {
627 		syscallarg(const char *) path;
628 		syscallarg(int) attrnamespace;
629 		syscallarg(const char *) attrname;
630 	} */ *uap = v;
631 	struct nameidata nd;
632 	char attrname[EXTATTR_MAXNAMELEN];
633 	int error;
634 
635 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
636 	    NULL);
637 	if (error)
638 		return (error);
639 
640 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
641 	error = namei(&nd);
642 	if (error)
643 		return (error);
644 
645 	error = extattr_delete_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
646 	    l);
647 
648 	vrele(nd.ni_vp);
649 	return (error);
650 }
651 
652 int
653 sys_extattr_delete_link(struct lwp *l, void *v, register_t *retval)
654 {
655 	struct sys_extattr_delete_link_args /* {
656 		syscallarg(const char *) path;
657 		syscallarg(int) attrnamespace;
658 		syscallarg(const char *) attrname;
659 	} */ *uap = v;
660 	struct nameidata nd;
661 	char attrname[EXTATTR_MAXNAMELEN];
662 	int error;
663 
664 	error = copyinstr(SCARG(uap, attrname), attrname, sizeof(attrname),
665 	    NULL);
666 	if (error)
667 		return (error);
668 
669 	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
670 	error = namei(&nd);
671 	if (error)
672 		return (error);
673 
674 	error = extattr_delete_vp(nd.ni_vp, SCARG(uap, attrnamespace), attrname,
675 	    l);
676 
677 	vrele(nd.ni_vp);
678 	return (error);
679 }
680 
681 int
682 sys_extattr_list_fd(struct lwp *l, void *v, register_t *retval)
683 {
684 	struct sys_extattr_list_fd_args /* {
685 		syscallarg(int) fd;
686 		syscallarg(int) attrnamespace;
687 		syscallarg(void *) data;
688 		syscallarg(size_t) nbytes;
689 	} */ *uap = v;
690 	struct file *fp;
691 	struct vnode *vp;
692 	int error;
693 
694 	error = getvnode(l->l_proc->p_fd, SCARG(uap, fd), &fp);
695 	if (error)
696 		return (error);
697 	vp = (struct vnode *) fp->f_data;
698 
699 	error = extattr_list_vp(vp, SCARG(uap, attrnamespace),
700 	    SCARG(uap, data), SCARG(uap, nbytes), l, retval);
701 
702 	FILE_UNUSE(fp, l);
703 	return (error);
704 }
705 
706 int
707 sys_extattr_list_file(struct lwp *l, void *v, register_t *retval)
708 {
709 	struct sys_extattr_list_file_args /* {
710 		syscallarg(const char *) path;
711 		syscallarg(int) attrnamespace;
712 		syscallarg(void *) data;
713 		syscallarg(size_t) nbytes;
714 	} */ *uap = v;
715 	struct nameidata nd;
716 	int error;
717 
718 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
719 	error = namei(&nd);
720 	if (error)
721 		return (error);
722 
723 	error = extattr_list_vp(nd.ni_vp, SCARG(uap, attrnamespace),
724 	    SCARG(uap, data), SCARG(uap, nbytes), l, retval);
725 
726 	vrele(nd.ni_vp);
727 	return (error);
728 }
729 
730 int
731 sys_extattr_list_link(struct lwp *l, void *v, register_t *retval)
732 {
733 	struct sys_extattr_list_link_args /* {
734 		syscallarg(const char *) path;
735 		syscallarg(int) attrnamespace;
736 		syscallarg(void *) data;
737 		syscallarg(size_t) nbytes;
738 	} */ *uap = v;
739 	struct nameidata nd;
740 	int error;
741 
742 	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
743 	error = namei(&nd);
744 	if (error)
745 		return (error);
746 
747 	error = extattr_list_vp(nd.ni_vp, SCARG(uap, attrnamespace),
748 	    SCARG(uap, data), SCARG(uap, nbytes), l, retval);
749 
750 	vrele(nd.ni_vp);
751 	return (error);
752 }
753 
754 /*****************************************************************************
755  * Linux-compatible <sys/xattr.h> API for file system extended attributes
756  *****************************************************************************/
757 
758 int
759 sys_setxattr(struct lwp *l, void *v, register_t *retval)
760 {
761 	struct sys_setxattr_args /* {
762 		syscallarg(const char *) path;
763 		syscallarg(const char *) name;
764 		syscallarg(void *) value;
765 		syscallarg(size_t) size;
766 		syscallarg(int) flags;
767 	} */ *uap = v;
768 	struct nameidata nd;
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 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
778 	error = namei(&nd);
779 	if (error)
780 		return (error);
781 
782 	/* XXX flags */
783 
784 	error = extattr_set_vp(nd.ni_vp, EXTATTR_NAMESPACE_USER,
785 	    attrname, SCARG(uap, value), SCARG(uap, size), l, retval);
786 
787 	vrele(nd.ni_vp);
788 	return (error);
789 }
790 
791 int
792 sys_lsetxattr(struct lwp *l, void *v, register_t *retval)
793 {
794 	struct sys_lsetxattr_args /* {
795 		syscallarg(const char *) path;
796 		syscallarg(const char *) name;
797 		syscallarg(void *) value;
798 		syscallarg(size_t) size;
799 		syscallarg(int) flags;
800 	} */ *uap = v;
801 	struct nameidata nd;
802 	char attrname[XATTR_NAME_MAX];
803 	int error;
804 
805 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
806 	    NULL);
807 	if (error)
808 		return (error);
809 
810 	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
811 	error = namei(&nd);
812 	if (error)
813 		return (error);
814 
815 	/* XXX flags */
816 
817 	error = extattr_set_vp(nd.ni_vp, EXTATTR_NAMESPACE_USER,
818 	    attrname, SCARG(uap, value), SCARG(uap, size), l, retval);
819 
820 	vrele(nd.ni_vp);
821 	return (error);
822 }
823 
824 int
825 sys_fsetxattr(struct lwp *l, void *v, register_t *retval)
826 {
827 	struct sys_fsetxattr_args /* {
828 		syscallarg(int) fd;
829 		syscallarg(const char *) name;
830 		syscallarg(void *) value;
831 		syscallarg(size_t) size;
832 		syscallarg(int) flags;
833 	} */ *uap = v;
834 	struct file *fp;
835 	struct vnode *vp;
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 	error = getvnode(l->l_proc->p_fd, SCARG(uap, fd), &fp);
845 	if (error)
846 		return (error);
847 	vp = (struct vnode *) fp->f_data;
848 
849 	/* XXX flags */
850 
851 	error = extattr_set_vp(vp, EXTATTR_NAMESPACE_USER,
852 	    attrname, SCARG(uap, value), SCARG(uap, size), l, retval);
853 
854 	FILE_UNUSE(fp, l);
855 	return (error);
856 }
857 
858 int
859 sys_getxattr(struct lwp *l, void *v, register_t *retval)
860 {
861 	struct sys_getxattr_args /* {
862 		syscallarg(const char *) path;
863 		syscallarg(const char *) name;
864 		syscallarg(void *) value;
865 		syscallarg(size_t) size;
866 	} */ *uap = v;
867 	struct nameidata nd;
868 	char attrname[XATTR_NAME_MAX];
869 	int error;
870 
871 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
872 	    NULL);
873 	if (error)
874 		return (error);
875 
876 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
877 	error = namei(&nd);
878 	if (error)
879 		return (error);
880 
881 	error = extattr_get_vp(nd.ni_vp, EXTATTR_NAMESPACE_USER,
882 	    attrname, SCARG(uap, value), SCARG(uap, size), l, retval);
883 
884 	vrele(nd.ni_vp);
885 	return (error);
886 }
887 
888 int
889 sys_lgetxattr(struct lwp *l, void *v, register_t *retval)
890 {
891 	struct sys_lgetxattr_args /* {
892 		syscallarg(const char *) path;
893 		syscallarg(const char *) name;
894 		syscallarg(void *) value;
895 		syscallarg(size_t) size;
896 	} */ *uap = v;
897 	struct nameidata nd;
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 	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
907 	error = namei(&nd);
908 	if (error)
909 		return (error);
910 
911 	error = extattr_get_vp(nd.ni_vp, EXTATTR_NAMESPACE_USER,
912 	    attrname, SCARG(uap, value), SCARG(uap, size), l, retval);
913 
914 	vrele(nd.ni_vp);
915 	return (error);
916 }
917 
918 int
919 sys_fgetxattr(struct lwp *l, void *v, register_t *retval)
920 {
921 	struct sys_fgetxattr_args /* {
922 		syscallarg(int) fd;
923 		syscallarg(const char *) name;
924 		syscallarg(void *) value;
925 		syscallarg(size_t) size;
926 	} */ *uap = v;
927 	struct file *fp;
928 	struct vnode *vp;
929 	char attrname[XATTR_NAME_MAX];
930 	int error;
931 
932 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
933 	    NULL);
934 	if (error)
935 		return (error);
936 
937 	error = getvnode(l->l_proc->p_fd, SCARG(uap, fd), &fp);
938 	if (error)
939 		return (error);
940 	vp = (struct vnode *) fp->f_data;
941 
942 	error = extattr_get_vp(vp, EXTATTR_NAMESPACE_USER,
943 	    attrname, SCARG(uap, value), SCARG(uap, size), l, retval);
944 
945 	FILE_UNUSE(fp, l);
946 	return (error);
947 }
948 
949 int
950 sys_listxattr(struct lwp *l, void *v, register_t *retval)
951 {
952 	struct sys_listxattr_args /* {
953 		syscallarg(const char *) path;
954 		syscallarg(char *) list;
955 		syscallarg(size_t) size;
956 	} */ *uap = v;
957 	struct nameidata nd;
958 	int error;
959 
960 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
961 	error = namei(&nd);
962 	if (error)
963 		return (error);
964 
965 	error = extattr_list_vp(nd.ni_vp, EXTATTR_NAMESPACE_USER,
966 	    SCARG(uap, list), SCARG(uap, size), l, retval);
967 
968 	vrele(nd.ni_vp);
969 	return (error);
970 }
971 
972 int
973 sys_llistxattr(struct lwp *l, void *v, register_t *retval)
974 {
975 	struct sys_llistxattr_args /* {
976 		syscallarg(const char *) path;
977 		syscallarg(char *) list;
978 		syscallarg(size_t) size;
979 	} */ *uap = v;
980 	struct nameidata nd;
981 	int error;
982 
983 	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
984 	error = namei(&nd);
985 	if (error)
986 		return (error);
987 
988 	error = extattr_list_vp(nd.ni_vp, EXTATTR_NAMESPACE_USER,
989 	    SCARG(uap, list), SCARG(uap, size), l, retval);
990 
991 	vrele(nd.ni_vp);
992 	return (error);
993 }
994 
995 int
996 sys_flistxattr(struct lwp *l, void *v, register_t *retval)
997 {
998 	struct sys_flistxattr_args /* {
999 		syscallarg(int) fd;
1000 		syscallarg(char *) list;
1001 		syscallarg(size_t) size;
1002 	} */ *uap = v;
1003 	struct file *fp;
1004 	struct vnode *vp;
1005 	int error;
1006 
1007 	error = getvnode(l->l_proc->p_fd, SCARG(uap, fd), &fp);
1008 	if (error)
1009 		return (error);
1010 	vp = (struct vnode *) fp->f_data;
1011 
1012 	error = extattr_list_vp(vp, EXTATTR_NAMESPACE_USER,
1013 	    SCARG(uap, list), SCARG(uap, size), l, retval);
1014 
1015 	FILE_UNUSE(fp, l);
1016 	return (error);
1017 }
1018 
1019 int
1020 sys_removexattr(struct lwp *l, void *v, register_t *retval)
1021 {
1022 	struct sys_removexattr_args /* {
1023 		syscallarg(const char *) path;
1024 		syscallarg(const char *) name;
1025 	} */ *uap = v;
1026 	struct nameidata nd;
1027 	char attrname[XATTR_NAME_MAX];
1028 	int error;
1029 
1030 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
1031 	    NULL);
1032 	if (error)
1033 		return (error);
1034 
1035 	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
1036 	error = namei(&nd);
1037 	if (error)
1038 		return (error);
1039 
1040 	error = extattr_delete_vp(nd.ni_vp, EXTATTR_NAMESPACE_USER,
1041 	    attrname, l);
1042 
1043 	vrele(nd.ni_vp);
1044 	return (error);
1045 }
1046 
1047 int
1048 sys_lremovexattr(struct lwp *l, void *v, register_t *retval)
1049 {
1050 	struct sys_lremovexattr_args /* {
1051 		syscallarg(const char *) path;
1052 		syscallarg(const char *) name;
1053 	} */ *uap = v;
1054 	struct nameidata nd;
1055 	char attrname[XATTR_NAME_MAX];
1056 	int error;
1057 
1058 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
1059 	    NULL);
1060 	if (error)
1061 		return (error);
1062 
1063 	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, SCARG(uap, path), l);
1064 	error = namei(&nd);
1065 	if (error)
1066 		return (error);
1067 
1068 	error = extattr_delete_vp(nd.ni_vp, EXTATTR_NAMESPACE_USER,
1069 	    attrname, l);
1070 
1071 	vrele(nd.ni_vp);
1072 	return (error);
1073 }
1074 
1075 int
1076 sys_fremovexattr(struct lwp *l, void *v, register_t *retval)
1077 {
1078 	struct sys_fremovexattr_args /* {
1079 		syscallarg(int) fd;
1080 		syscallarg(const char *) name;
1081 	} */ *uap = v;
1082 	struct file *fp;
1083 	struct vnode *vp;
1084 	char attrname[XATTR_NAME_MAX];
1085 	int error;
1086 
1087 	error = copyinstr(SCARG(uap, name), attrname, sizeof(attrname),
1088 	    NULL);
1089 	if (error)
1090 		return (error);
1091 
1092 	error = getvnode(l->l_proc->p_fd, SCARG(uap, fd), &fp);
1093 	if (error)
1094 		return (error);
1095 	vp = (struct vnode *) fp->f_data;
1096 
1097 	error = extattr_delete_vp(vp, EXTATTR_NAMESPACE_USER,
1098 	    attrname, l);
1099 
1100 	FILE_UNUSE(fp, l);
1101 	return (error);
1102 }
1103