vfs_extattr.c revision 116601
1/*
2 * Copyright (c) 1989, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 * (c) UNIX System Laboratories, Inc.
5 * All or some portions of this file are derived from material licensed
6 * to the University of California by American Telephone and Telegraph
7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8 * the permission of UNIX System Laboratories, Inc.
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 University of
21 *	California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 *    may be used to endorse or promote products derived from this software
24 *    without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 *	@(#)vfs_syscalls.c	8.13 (Berkeley) 4/15/94
39 */
40
41#include <sys/cdefs.h>
42__FBSDID("$FreeBSD: head/sys/kern/vfs_extattr.c 116601 2003-06-20 08:02:30Z phk $");
43
44/* For 4.3 integer FS ID compatibility */
45#include "opt_compat.h"
46#include "opt_mac.h"
47
48#include <sys/param.h>
49#include <sys/systm.h>
50#include <sys/bio.h>
51#include <sys/buf.h>
52#include <sys/sysent.h>
53#include <sys/mac.h>
54#include <sys/malloc.h>
55#include <sys/mount.h>
56#include <sys/mutex.h>
57#include <sys/sysproto.h>
58#include <sys/namei.h>
59#include <sys/filedesc.h>
60#include <sys/kernel.h>
61#include <sys/fcntl.h>
62#include <sys/file.h>
63#include <sys/limits.h>
64#include <sys/linker.h>
65#include <sys/stat.h>
66#include <sys/sx.h>
67#include <sys/unistd.h>
68#include <sys/vnode.h>
69#include <sys/proc.h>
70#include <sys/dirent.h>
71#include <sys/extattr.h>
72#include <sys/jail.h>
73#include <sys/syscallsubr.h>
74#include <sys/sysctl.h>
75
76#include <machine/stdarg.h>
77
78#include <vm/vm.h>
79#include <vm/vm_object.h>
80#include <vm/vm_page.h>
81#include <vm/uma.h>
82
83static int chroot_refuse_vdir_fds(struct filedesc *fdp);
84static int getutimes(const struct timeval *, enum uio_seg, struct timespec *);
85static int setfown(struct thread *td, struct vnode *, uid_t, gid_t);
86static int setfmode(struct thread *td, struct vnode *, int);
87static int setfflags(struct thread *td, struct vnode *, int);
88static int setutimes(struct thread *td, struct vnode *,
89    const struct timespec *, int, int);
90static int vn_access(struct vnode *vp, int user_flags, struct ucred *cred,
91    struct thread *td);
92
93static int extattr_list_vp(struct vnode *vp, int attrnamespace, void *data,
94    size_t nbytes, struct thread *td);
95
96int (*union_dircheckp)(struct thread *td, struct vnode **, struct file *);
97int (*softdep_fsync_hook)(struct vnode *);
98
99/*
100 * The module initialization routine for POSIX asynchronous I/O will
101 * set this to the version of AIO that it implements.  (Zero means
102 * that it is not implemented.)  This value is used here by pathconf()
103 * and in kern_descrip.c by fpathconf().
104 */
105int async_io_version;
106
107/*
108 * Sync each mounted filesystem.
109 */
110#ifndef _SYS_SYSPROTO_H_
111struct sync_args {
112        int     dummy;
113};
114#endif
115
116#ifdef DEBUG
117static int syncprt = 0;
118SYSCTL_INT(_debug, OID_AUTO, syncprt, CTLFLAG_RW, &syncprt, 0, "");
119#endif
120
121/* ARGSUSED */
122int
123sync(td, uap)
124	struct thread *td;
125	struct sync_args *uap;
126{
127	struct mount *mp, *nmp;
128	int asyncflag;
129
130	mtx_lock(&mountlist_mtx);
131	for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) {
132		if (vfs_busy(mp, LK_NOWAIT, &mountlist_mtx, td)) {
133			nmp = TAILQ_NEXT(mp, mnt_list);
134			continue;
135		}
136		if ((mp->mnt_flag & MNT_RDONLY) == 0 &&
137		    vn_start_write(NULL, &mp, V_NOWAIT) == 0) {
138			asyncflag = mp->mnt_flag & MNT_ASYNC;
139			mp->mnt_flag &= ~MNT_ASYNC;
140			vfs_msync(mp, MNT_NOWAIT);
141			VFS_SYNC(mp, MNT_NOWAIT,
142			    ((td != NULL) ? td->td_ucred : NOCRED), td);
143			mp->mnt_flag |= asyncflag;
144			vn_finished_write(mp);
145		}
146		mtx_lock(&mountlist_mtx);
147		nmp = TAILQ_NEXT(mp, mnt_list);
148		vfs_unbusy(mp, td);
149	}
150	mtx_unlock(&mountlist_mtx);
151#if 0
152/*
153 * XXX don't call vfs_bufstats() yet because that routine
154 * was not imported in the Lite2 merge.
155 */
156#ifdef DIAGNOSTIC
157	if (syncprt)
158		vfs_bufstats();
159#endif /* DIAGNOSTIC */
160#endif
161	return (0);
162}
163
164/* XXX PRISON: could be per prison flag */
165static int prison_quotas;
166#if 0
167SYSCTL_INT(_kern_prison, OID_AUTO, quotas, CTLFLAG_RW, &prison_quotas, 0, "");
168#endif
169
170/*
171 * Change filesystem quotas.
172 */
173#ifndef _SYS_SYSPROTO_H_
174struct quotactl_args {
175	char *path;
176	int cmd;
177	int uid;
178	caddr_t arg;
179};
180#endif
181/* ARGSUSED */
182int
183quotactl(td, uap)
184	struct thread *td;
185	register struct quotactl_args /* {
186		char *path;
187		int cmd;
188		int uid;
189		caddr_t arg;
190	} */ *uap;
191{
192	struct mount *mp;
193	int error;
194	struct nameidata nd;
195
196	if (jailed(td->td_ucred) && !prison_quotas)
197		return (EPERM);
198	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
199	if ((error = namei(&nd)) != 0)
200		return (error);
201	NDFREE(&nd, NDF_ONLY_PNBUF);
202	error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
203	vrele(nd.ni_vp);
204	if (error)
205		return (error);
206	error = VFS_QUOTACTL(mp, uap->cmd, uap->uid, uap->arg, td);
207	vn_finished_write(mp);
208	return (error);
209}
210
211/*
212 * Get filesystem statistics.
213 */
214#ifndef _SYS_SYSPROTO_H_
215struct statfs_args {
216	char *path;
217	struct statfs *buf;
218};
219#endif
220/* ARGSUSED */
221int
222statfs(td, uap)
223	struct thread *td;
224	register struct statfs_args /* {
225		char *path;
226		struct statfs *buf;
227	} */ *uap;
228{
229	register struct mount *mp;
230	register struct statfs *sp;
231	int error;
232	struct nameidata nd;
233	struct statfs sb;
234
235	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
236	if ((error = namei(&nd)) != 0)
237		return (error);
238	mp = nd.ni_vp->v_mount;
239	sp = &mp->mnt_stat;
240	NDFREE(&nd, NDF_ONLY_PNBUF);
241	vrele(nd.ni_vp);
242#ifdef MAC
243	error = mac_check_mount_stat(td->td_ucred, mp);
244	if (error)
245		return (error);
246#endif
247	error = VFS_STATFS(mp, sp, td);
248	if (error)
249		return (error);
250	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
251	if (suser(td)) {
252		bcopy(sp, &sb, sizeof(sb));
253		sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
254		sp = &sb;
255	}
256	return (copyout(sp, uap->buf, sizeof(*sp)));
257}
258
259/*
260 * Get filesystem statistics.
261 */
262#ifndef _SYS_SYSPROTO_H_
263struct fstatfs_args {
264	int fd;
265	struct statfs *buf;
266};
267#endif
268/* ARGSUSED */
269int
270fstatfs(td, uap)
271	struct thread *td;
272	register struct fstatfs_args /* {
273		int fd;
274		struct statfs *buf;
275	} */ *uap;
276{
277	struct file *fp;
278	struct mount *mp;
279	register struct statfs *sp;
280	int error;
281	struct statfs sb;
282
283	if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0)
284		return (error);
285	mp = ((struct vnode *)fp->f_data)->v_mount;
286	fdrop(fp, td);
287	if (mp == NULL)
288		return (EBADF);
289#ifdef MAC
290	error = mac_check_mount_stat(td->td_ucred, mp);
291	if (error)
292		return (error);
293#endif
294	sp = &mp->mnt_stat;
295	error = VFS_STATFS(mp, sp, td);
296	if (error)
297		return (error);
298	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
299	if (suser(td)) {
300		bcopy(sp, &sb, sizeof(sb));
301		sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
302		sp = &sb;
303	}
304	return (copyout(sp, uap->buf, sizeof(*sp)));
305}
306
307/*
308 * Get statistics on all filesystems.
309 */
310#ifndef _SYS_SYSPROTO_H_
311struct getfsstat_args {
312	struct statfs *buf;
313	long bufsize;
314	int flags;
315};
316#endif
317int
318getfsstat(td, uap)
319	struct thread *td;
320	register struct getfsstat_args /* {
321		struct statfs *buf;
322		long bufsize;
323		int flags;
324	} */ *uap;
325{
326	register struct mount *mp, *nmp;
327	register struct statfs *sp;
328	caddr_t sfsp;
329	long count, maxcount, error;
330
331	maxcount = uap->bufsize / sizeof(struct statfs);
332	sfsp = (caddr_t)uap->buf;
333	count = 0;
334	mtx_lock(&mountlist_mtx);
335	for (mp = TAILQ_FIRST(&mountlist); mp != NULL; mp = nmp) {
336#ifdef MAC
337		if (mac_check_mount_stat(td->td_ucred, mp) != 0) {
338			nmp = TAILQ_NEXT(mp, mnt_list);
339			continue;
340		}
341#endif
342		if (vfs_busy(mp, LK_NOWAIT, &mountlist_mtx, td)) {
343			nmp = TAILQ_NEXT(mp, mnt_list);
344			continue;
345		}
346		if (sfsp && count < maxcount) {
347			sp = &mp->mnt_stat;
348			/*
349			 * If MNT_NOWAIT or MNT_LAZY is specified, do not
350			 * refresh the fsstat cache. MNT_NOWAIT or MNT_LAZY
351			 * overrides MNT_WAIT.
352			 */
353			if (((uap->flags & (MNT_LAZY|MNT_NOWAIT)) == 0 ||
354			    (uap->flags & MNT_WAIT)) &&
355			    (error = VFS_STATFS(mp, sp, td))) {
356				mtx_lock(&mountlist_mtx);
357				nmp = TAILQ_NEXT(mp, mnt_list);
358				vfs_unbusy(mp, td);
359				continue;
360			}
361			sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
362			error = copyout(sp, sfsp, sizeof(*sp));
363			if (error) {
364				vfs_unbusy(mp, td);
365				return (error);
366			}
367			sfsp += sizeof(*sp);
368		}
369		count++;
370		mtx_lock(&mountlist_mtx);
371		nmp = TAILQ_NEXT(mp, mnt_list);
372		vfs_unbusy(mp, td);
373	}
374	mtx_unlock(&mountlist_mtx);
375	if (sfsp && count > maxcount)
376		td->td_retval[0] = maxcount;
377	else
378		td->td_retval[0] = count;
379	return (0);
380}
381
382/*
383 * Change current working directory to a given file descriptor.
384 */
385#ifndef _SYS_SYSPROTO_H_
386struct fchdir_args {
387	int	fd;
388};
389#endif
390/* ARGSUSED */
391int
392fchdir(td, uap)
393	struct thread *td;
394	struct fchdir_args /* {
395		int fd;
396	} */ *uap;
397{
398	register struct filedesc *fdp = td->td_proc->p_fd;
399	struct vnode *vp, *tdp, *vpold;
400	struct mount *mp;
401	struct file *fp;
402	int error;
403
404	if ((error = getvnode(fdp, uap->fd, &fp)) != 0)
405		return (error);
406	vp = fp->f_data;
407	VREF(vp);
408	fdrop(fp, td);
409	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
410	if (vp->v_type != VDIR)
411		error = ENOTDIR;
412#ifdef MAC
413	else if ((error = mac_check_vnode_chdir(td->td_ucred, vp)) != 0) {
414	}
415#endif
416	else
417		error = VOP_ACCESS(vp, VEXEC, td->td_ucred, td);
418	while (!error && (mp = vp->v_mountedhere) != NULL) {
419		if (vfs_busy(mp, 0, 0, td))
420			continue;
421		error = VFS_ROOT(mp, &tdp);
422		vfs_unbusy(mp, td);
423		if (error)
424			break;
425		vput(vp);
426		vp = tdp;
427	}
428	if (error) {
429		vput(vp);
430		return (error);
431	}
432	VOP_UNLOCK(vp, 0, td);
433	FILEDESC_LOCK(fdp);
434	vpold = fdp->fd_cdir;
435	fdp->fd_cdir = vp;
436	FILEDESC_UNLOCK(fdp);
437	vrele(vpold);
438	return (0);
439}
440
441/*
442 * Change current working directory (``.'').
443 */
444#ifndef _SYS_SYSPROTO_H_
445struct chdir_args {
446	char	*path;
447};
448#endif
449/* ARGSUSED */
450int
451chdir(td, uap)
452	struct thread *td;
453	struct chdir_args /* {
454		char *path;
455	} */ *uap;
456{
457
458	return (kern_chdir(td, uap->path, UIO_USERSPACE));
459}
460
461int
462kern_chdir(struct thread *td, char *path, enum uio_seg pathseg)
463{
464	register struct filedesc *fdp = td->td_proc->p_fd;
465	int error;
466	struct nameidata nd;
467	struct vnode *vp;
468
469	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, pathseg, path, td);
470	if ((error = namei(&nd)) != 0)
471		return (error);
472	if ((error = change_dir(nd.ni_vp, td)) != 0) {
473		vput(nd.ni_vp);
474		NDFREE(&nd, NDF_ONLY_PNBUF);
475		return (error);
476	}
477	VOP_UNLOCK(nd.ni_vp, 0, td);
478	NDFREE(&nd, NDF_ONLY_PNBUF);
479	FILEDESC_LOCK(fdp);
480	vp = fdp->fd_cdir;
481	fdp->fd_cdir = nd.ni_vp;
482	FILEDESC_UNLOCK(fdp);
483	vrele(vp);
484	return (0);
485}
486
487/*
488 * Helper function for raised chroot(2) security function:  Refuse if
489 * any filedescriptors are open directories.
490 */
491static int
492chroot_refuse_vdir_fds(fdp)
493	struct filedesc *fdp;
494{
495	struct vnode *vp;
496	struct file *fp;
497	int fd;
498
499	FILEDESC_LOCK_ASSERT(fdp, MA_OWNED);
500	for (fd = 0; fd < fdp->fd_nfiles ; fd++) {
501		fp = fget_locked(fdp, fd);
502		if (fp == NULL)
503			continue;
504		if (fp->f_type == DTYPE_VNODE) {
505			vp = fp->f_data;
506			if (vp->v_type == VDIR)
507				return (EPERM);
508		}
509	}
510	return (0);
511}
512
513/*
514 * This sysctl determines if we will allow a process to chroot(2) if it
515 * has a directory open:
516 *	0: disallowed for all processes.
517 *	1: allowed for processes that were not already chroot(2)'ed.
518 *	2: allowed for all processes.
519 */
520
521static int chroot_allow_open_directories = 1;
522
523SYSCTL_INT(_kern, OID_AUTO, chroot_allow_open_directories, CTLFLAG_RW,
524     &chroot_allow_open_directories, 0, "");
525
526/*
527 * Change notion of root (``/'') directory.
528 */
529#ifndef _SYS_SYSPROTO_H_
530struct chroot_args {
531	char	*path;
532};
533#endif
534/* ARGSUSED */
535int
536chroot(td, uap)
537	struct thread *td;
538	struct chroot_args /* {
539		char *path;
540	} */ *uap;
541{
542	int error;
543	struct nameidata nd;
544
545	error = suser_cred(td->td_ucred, PRISON_ROOT);
546	if (error)
547		return (error);
548	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, td);
549	mtx_lock(&Giant);
550	error = namei(&nd);
551	if (error)
552		goto error;
553	if ((error = change_dir(nd.ni_vp, td)) != 0)
554		goto e_vunlock;
555#ifdef MAC
556	if ((error = mac_check_vnode_chroot(td->td_ucred, nd.ni_vp)))
557		goto e_vunlock;
558#endif
559	VOP_UNLOCK(nd.ni_vp, 0, td);
560	error = change_root(nd.ni_vp, td);
561	vrele(nd.ni_vp);
562	NDFREE(&nd, NDF_ONLY_PNBUF);
563	mtx_unlock(&Giant);
564	return (error);
565e_vunlock:
566	vput(nd.ni_vp);
567error:
568	mtx_unlock(&Giant);
569	NDFREE(&nd, NDF_ONLY_PNBUF);
570	return (error);
571}
572
573/*
574 * Common routine for chroot and chdir.  Callers must provide a locked vnode
575 * instance.
576 */
577int
578change_dir(vp, td)
579	struct vnode *vp;
580	struct thread *td;
581{
582	int error;
583
584	ASSERT_VOP_LOCKED(vp, "change_dir(): vp not locked");
585	if (vp->v_type != VDIR)
586		return (ENOTDIR);
587#ifdef MAC
588	error = mac_check_vnode_chdir(td->td_ucred, vp);
589	if (error)
590		return (error);
591#endif
592	error = VOP_ACCESS(vp, VEXEC, td->td_ucred, td);
593	return (error);
594}
595
596/*
597 * Common routine for kern_chroot() and jail_attach().  The caller is
598 * responsible for invoking suser() and mac_check_chroot() to authorize this
599 * operation.
600 */
601int
602change_root(vp, td)
603	struct vnode *vp;
604	struct thread *td;
605{
606	struct filedesc *fdp;
607	struct vnode *oldvp;
608	int error;
609
610	mtx_assert(&Giant, MA_OWNED);
611	fdp = td->td_proc->p_fd;
612	FILEDESC_LOCK(fdp);
613	if (chroot_allow_open_directories == 0 ||
614	    (chroot_allow_open_directories == 1 && fdp->fd_rdir != rootvnode)) {
615		error = chroot_refuse_vdir_fds(fdp);
616		if (error) {
617			FILEDESC_UNLOCK(fdp);
618			return (error);
619		}
620	}
621	oldvp = fdp->fd_rdir;
622	fdp->fd_rdir = vp;
623	VREF(fdp->fd_rdir);
624	if (!fdp->fd_jdir) {
625		fdp->fd_jdir = vp;
626		VREF(fdp->fd_jdir);
627	}
628	FILEDESC_UNLOCK(fdp);
629	vrele(oldvp);
630	return (0);
631}
632
633/*
634 * Check permissions, allocate an open file structure,
635 * and call the device open routine if any.
636 */
637#ifndef _SYS_SYSPROTO_H_
638struct open_args {
639	char	*path;
640	int	flags;
641	int	mode;
642};
643#endif
644int
645open(td, uap)
646	struct thread *td;
647	register struct open_args /* {
648		char *path;
649		int flags;
650		int mode;
651	} */ *uap;
652{
653
654	return (kern_open(td, uap->path, UIO_USERSPACE, uap->flags, uap->mode));
655}
656
657int
658kern_open(struct thread *td, char *path, enum uio_seg pathseg, int flags,
659    int mode)
660{
661	struct proc *p = td->td_proc;
662	struct filedesc *fdp = p->p_fd;
663	struct file *fp;
664	struct vnode *vp;
665	struct vattr vat;
666	struct mount *mp;
667	int cmode;
668	struct file *nfp;
669	int type, indx, error;
670	struct flock lf;
671	struct nameidata nd;
672
673	if ((flags & O_ACCMODE) == O_ACCMODE)
674		return (EINVAL);
675	flags = FFLAGS(flags);
676	error = falloc(td, &nfp, &indx);
677	if (error)
678		return (error);
679	fp = nfp;
680	cmode = ((mode &~ fdp->fd_cmask) & ALLPERMS) &~ S_ISTXT;
681	NDINIT(&nd, LOOKUP, FOLLOW, pathseg, path, td);
682	td->td_dupfd = -indx - 1;		/* XXX check for fdopen */
683	/*
684	 * Bump the ref count to prevent another process from closing
685	 * the descriptor while we are blocked in vn_open()
686	 */
687	fhold(fp);
688	error = vn_open(&nd, &flags, cmode);
689	if (error) {
690		/*
691		 * release our own reference
692		 */
693		fdrop(fp, td);
694
695		/*
696		 * handle special fdopen() case.  bleh.  dupfdopen() is
697		 * responsible for dropping the old contents of ofiles[indx]
698		 * if it succeeds.
699		 */
700		if ((error == ENODEV || error == ENXIO) &&
701		    td->td_dupfd >= 0 &&		/* XXX from fdopen */
702		    (error =
703			dupfdopen(td, fdp, indx, td->td_dupfd, flags, error)) == 0) {
704			td->td_retval[0] = indx;
705			return (0);
706		}
707		/*
708		 * Clean up the descriptor, but only if another thread hadn't
709		 * replaced or closed it.
710		 */
711		FILEDESC_LOCK(fdp);
712		if (fdp->fd_ofiles[indx] == fp) {
713			fdp->fd_ofiles[indx] = NULL;
714			FILEDESC_UNLOCK(fdp);
715			fdrop(fp, td);
716		} else
717			FILEDESC_UNLOCK(fdp);
718
719		if (error == ERESTART)
720			error = EINTR;
721		return (error);
722	}
723	td->td_dupfd = 0;
724	NDFREE(&nd, NDF_ONLY_PNBUF);
725	vp = nd.ni_vp;
726
727	/*
728	 * There should be 2 references on the file, one from the descriptor
729	 * table, and one for us.
730	 *
731	 * Handle the case where someone closed the file (via its file
732	 * descriptor) while we were blocked.  The end result should look
733	 * like opening the file succeeded but it was immediately closed.
734	 */
735	FILEDESC_LOCK(fdp);
736	FILE_LOCK(fp);
737	if (fp->f_count == 1) {
738		KASSERT(fdp->fd_ofiles[indx] != fp,
739		    ("Open file descriptor lost all refs"));
740		FILEDESC_UNLOCK(fdp);
741		FILE_UNLOCK(fp);
742		VOP_UNLOCK(vp, 0, td);
743		vn_close(vp, flags & FMASK, fp->f_cred, td);
744		fdrop(fp, td);
745		td->td_retval[0] = indx;
746		return 0;
747	}
748	fp->f_data = vp;
749	fp->f_flag = flags & FMASK;
750	fp->f_ops = &vnops;
751	fp->f_seqcount = 1;
752	fp->f_type = (vp->v_type == VFIFO ? DTYPE_FIFO : DTYPE_VNODE);
753	FILEDESC_UNLOCK(fdp);
754	FILE_UNLOCK(fp);
755
756	/* assert that vn_open created a backing object if one is needed */
757	KASSERT(!vn_canvmio(vp) || VOP_GETVOBJECT(vp, NULL) == 0,
758		("open: vmio vnode has no backing object after vn_open"));
759
760	VOP_UNLOCK(vp, 0, td);
761	if (flags & (O_EXLOCK | O_SHLOCK)) {
762		lf.l_whence = SEEK_SET;
763		lf.l_start = 0;
764		lf.l_len = 0;
765		if (flags & O_EXLOCK)
766			lf.l_type = F_WRLCK;
767		else
768			lf.l_type = F_RDLCK;
769		type = F_FLOCK;
770		if ((flags & FNONBLOCK) == 0)
771			type |= F_WAIT;
772		if ((error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf,
773			    type)) != 0)
774			goto bad;
775		fp->f_flag |= FHASLOCK;
776	}
777	if (flags & O_TRUNC) {
778		if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
779			goto bad;
780		VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
781		VATTR_NULL(&vat);
782		vat.va_size = 0;
783		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
784#ifdef MAC
785		error = mac_check_vnode_write(td->td_ucred, fp->f_cred, vp);
786		if (error == 0)
787#endif
788			error = VOP_SETATTR(vp, &vat, td->td_ucred, td);
789		VOP_UNLOCK(vp, 0, td);
790		vn_finished_write(mp);
791		if (error)
792			goto bad;
793	}
794	/*
795	 * Release our private reference, leaving the one associated with
796	 * the descriptor table intact.
797	 */
798	fdrop(fp, td);
799	td->td_retval[0] = indx;
800	return (0);
801bad:
802	FILEDESC_LOCK(fdp);
803	if (fdp->fd_ofiles[indx] == fp) {
804		fdp->fd_ofiles[indx] = NULL;
805		FILEDESC_UNLOCK(fdp);
806		fdrop(fp, td);
807	} else
808		FILEDESC_UNLOCK(fdp);
809	fdrop(fp, td);
810	return (error);
811}
812
813#ifdef COMPAT_43
814/*
815 * Create a file.
816 */
817#ifndef _SYS_SYSPROTO_H_
818struct ocreat_args {
819	char	*path;
820	int	mode;
821};
822#endif
823int
824ocreat(td, uap)
825	struct thread *td;
826	register struct ocreat_args /* {
827		char *path;
828		int mode;
829	} */ *uap;
830{
831	struct open_args /* {
832		char *path;
833		int flags;
834		int mode;
835	} */ nuap;
836
837	nuap.path = uap->path;
838	nuap.mode = uap->mode;
839	nuap.flags = O_WRONLY | O_CREAT | O_TRUNC;
840	return (open(td, &nuap));
841}
842#endif /* COMPAT_43 */
843
844/*
845 * Create a special file.
846 */
847#ifndef _SYS_SYSPROTO_H_
848struct mknod_args {
849	char	*path;
850	int	mode;
851	int	dev;
852};
853#endif
854/* ARGSUSED */
855int
856mknod(td, uap)
857	struct thread *td;
858	register struct mknod_args /* {
859		char *path;
860		int mode;
861		int dev;
862	} */ *uap;
863{
864
865	return (kern_mknod(td, uap->path, UIO_USERSPACE, uap->mode, uap->dev));
866}
867
868int
869kern_mknod(struct thread *td, char *path, enum uio_seg pathseg, int mode,
870    int dev)
871{
872	struct vnode *vp;
873	struct mount *mp;
874	struct vattr vattr;
875	int error;
876	int whiteout = 0;
877	struct nameidata nd;
878
879	switch (mode & S_IFMT) {
880	case S_IFCHR:
881	case S_IFBLK:
882		error = suser(td);
883		break;
884	default:
885		error = suser_cred(td->td_ucred, PRISON_ROOT);
886		break;
887	}
888	if (error)
889		return (error);
890restart:
891	bwillwrite();
892	NDINIT(&nd, CREATE, LOCKPARENT | SAVENAME, pathseg, path, td);
893	if ((error = namei(&nd)) != 0)
894		return (error);
895	vp = nd.ni_vp;
896	if (vp != NULL) {
897		vrele(vp);
898		error = EEXIST;
899	} else {
900		VATTR_NULL(&vattr);
901		FILEDESC_LOCK(td->td_proc->p_fd);
902		vattr.va_mode = (mode & ALLPERMS) &
903		    ~td->td_proc->p_fd->fd_cmask;
904		FILEDESC_UNLOCK(td->td_proc->p_fd);
905		vattr.va_rdev = dev;
906		whiteout = 0;
907
908		switch (mode & S_IFMT) {
909		case S_IFMT:	/* used by badsect to flag bad sectors */
910			vattr.va_type = VBAD;
911			break;
912		case S_IFCHR:
913			vattr.va_type = VCHR;
914			break;
915		case S_IFBLK:
916			vattr.va_type = VBLK;
917			break;
918		case S_IFWHT:
919			whiteout = 1;
920			break;
921		default:
922			error = EINVAL;
923			break;
924		}
925	}
926	if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
927		NDFREE(&nd, NDF_ONLY_PNBUF);
928		vput(nd.ni_dvp);
929		if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
930			return (error);
931		goto restart;
932	}
933#ifdef MAC
934	if (error == 0 && !whiteout)
935		error = mac_check_vnode_create(td->td_ucred, nd.ni_dvp,
936		    &nd.ni_cnd, &vattr);
937#endif
938	if (!error) {
939		VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
940		if (whiteout)
941			error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, CREATE);
942		else {
943			error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp,
944						&nd.ni_cnd, &vattr);
945			if (error == 0)
946				vput(nd.ni_vp);
947		}
948	}
949	NDFREE(&nd, NDF_ONLY_PNBUF);
950	vput(nd.ni_dvp);
951	vn_finished_write(mp);
952	ASSERT_VOP_UNLOCKED(nd.ni_dvp, "mknod");
953	ASSERT_VOP_UNLOCKED(nd.ni_vp, "mknod");
954	return (error);
955}
956
957/*
958 * Create a named pipe.
959 */
960#ifndef _SYS_SYSPROTO_H_
961struct mkfifo_args {
962	char	*path;
963	int	mode;
964};
965#endif
966/* ARGSUSED */
967int
968mkfifo(td, uap)
969	struct thread *td;
970	register struct mkfifo_args /* {
971		char *path;
972		int mode;
973	} */ *uap;
974{
975
976	return (kern_mkfifo(td, uap->path, UIO_USERSPACE, uap->mode));
977}
978
979int
980kern_mkfifo(struct thread *td, char *path, enum uio_seg pathseg, int mode)
981{
982	struct mount *mp;
983	struct vattr vattr;
984	int error;
985	struct nameidata nd;
986
987restart:
988	bwillwrite();
989	NDINIT(&nd, CREATE, LOCKPARENT | SAVENAME, pathseg, path, td);
990	if ((error = namei(&nd)) != 0)
991		return (error);
992	if (nd.ni_vp != NULL) {
993		NDFREE(&nd, NDF_ONLY_PNBUF);
994		vrele(nd.ni_vp);
995		vput(nd.ni_dvp);
996		return (EEXIST);
997	}
998	if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
999		NDFREE(&nd, NDF_ONLY_PNBUF);
1000		vput(nd.ni_dvp);
1001		if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
1002			return (error);
1003		goto restart;
1004	}
1005	VATTR_NULL(&vattr);
1006	vattr.va_type = VFIFO;
1007	FILEDESC_LOCK(td->td_proc->p_fd);
1008	vattr.va_mode = (mode & ALLPERMS) & ~td->td_proc->p_fd->fd_cmask;
1009	FILEDESC_UNLOCK(td->td_proc->p_fd);
1010#ifdef MAC
1011	error = mac_check_vnode_create(td->td_ucred, nd.ni_dvp, &nd.ni_cnd,
1012	    &vattr);
1013	if (error)
1014		goto out;
1015#endif
1016	VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
1017	error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
1018	if (error == 0)
1019		vput(nd.ni_vp);
1020#ifdef MAC
1021out:
1022#endif
1023	NDFREE(&nd, NDF_ONLY_PNBUF);
1024	vput(nd.ni_dvp);
1025	vn_finished_write(mp);
1026	return (error);
1027}
1028
1029/*
1030 * Make a hard file link.
1031 */
1032#ifndef _SYS_SYSPROTO_H_
1033struct link_args {
1034	char	*path;
1035	char	*link;
1036};
1037#endif
1038/* ARGSUSED */
1039int
1040link(td, uap)
1041	struct thread *td;
1042	register struct link_args /* {
1043		char *path;
1044		char *link;
1045	} */ *uap;
1046{
1047
1048	return (kern_link(td, uap->path, uap->link, UIO_USERSPACE));
1049}
1050
1051int
1052kern_link(struct thread *td, char *path, char *link, enum uio_seg segflg)
1053{
1054	struct vnode *vp;
1055	struct mount *mp;
1056	struct nameidata nd;
1057	int error;
1058
1059	bwillwrite();
1060	NDINIT(&nd, LOOKUP, FOLLOW|NOOBJ, segflg, path, td);
1061	if ((error = namei(&nd)) != 0)
1062		return (error);
1063	NDFREE(&nd, NDF_ONLY_PNBUF);
1064	vp = nd.ni_vp;
1065	if (vp->v_type == VDIR) {
1066		vrele(vp);
1067		return (EPERM);		/* POSIX */
1068	}
1069	if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) {
1070		vrele(vp);
1071		return (error);
1072	}
1073	NDINIT(&nd, CREATE, LOCKPARENT | NOOBJ | SAVENAME, segflg, link, td);
1074	if ((error = namei(&nd)) == 0) {
1075		if (nd.ni_vp != NULL) {
1076			vrele(nd.ni_vp);
1077			error = EEXIST;
1078		} else if ((error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td))
1079		    == 0) {
1080			VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
1081			VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
1082#ifdef MAC
1083			error = mac_check_vnode_link(td->td_ucred, nd.ni_dvp,
1084			    vp, &nd.ni_cnd);
1085			if (error == 0)
1086#endif
1087				error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
1088			VOP_UNLOCK(vp, 0, td);
1089		}
1090		NDFREE(&nd, NDF_ONLY_PNBUF);
1091		vput(nd.ni_dvp);
1092	}
1093	vrele(vp);
1094	vn_finished_write(mp);
1095	ASSERT_VOP_UNLOCKED(nd.ni_dvp, "link");
1096	ASSERT_VOP_UNLOCKED(nd.ni_vp, "link");
1097	return (error);
1098}
1099
1100/*
1101 * Make a symbolic link.
1102 */
1103#ifndef _SYS_SYSPROTO_H_
1104struct symlink_args {
1105	char	*path;
1106	char	*link;
1107};
1108#endif
1109/* ARGSUSED */
1110int
1111symlink(td, uap)
1112	struct thread *td;
1113	register struct symlink_args /* {
1114		char *path;
1115		char *link;
1116	} */ *uap;
1117{
1118
1119	return (kern_symlink(td, uap->path, uap->link, UIO_USERSPACE));
1120}
1121
1122int
1123kern_symlink(struct thread *td, char *path, char *link, enum uio_seg segflg)
1124{
1125	struct mount *mp;
1126	struct vattr vattr;
1127	char *syspath;
1128	int error;
1129	struct nameidata nd;
1130
1131	if (segflg == UIO_SYSSPACE) {
1132		syspath = path;
1133	} else {
1134		syspath = uma_zalloc(namei_zone, M_WAITOK);
1135		if ((error = copyinstr(path, syspath, MAXPATHLEN, NULL)) != 0)
1136			goto out;
1137	}
1138restart:
1139	bwillwrite();
1140	NDINIT(&nd, CREATE, LOCKPARENT | NOOBJ | SAVENAME, segflg, link, td);
1141	if ((error = namei(&nd)) != 0)
1142		goto out;
1143	if (nd.ni_vp) {
1144		NDFREE(&nd, NDF_ONLY_PNBUF);
1145		vrele(nd.ni_vp);
1146		vput(nd.ni_dvp);
1147		error = EEXIST;
1148		goto out;
1149	}
1150	if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
1151		NDFREE(&nd, NDF_ONLY_PNBUF);
1152		vput(nd.ni_dvp);
1153		if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
1154			return (error);
1155		goto restart;
1156	}
1157	VATTR_NULL(&vattr);
1158	FILEDESC_LOCK(td->td_proc->p_fd);
1159	vattr.va_mode = ACCESSPERMS &~ td->td_proc->p_fd->fd_cmask;
1160	FILEDESC_UNLOCK(td->td_proc->p_fd);
1161#ifdef MAC
1162	vattr.va_type = VLNK;
1163	error = mac_check_vnode_create(td->td_ucred, nd.ni_dvp, &nd.ni_cnd,
1164	    &vattr);
1165	if (error)
1166		goto out2;
1167#endif
1168	VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
1169	error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr, syspath);
1170	if (error == 0)
1171		vput(nd.ni_vp);
1172#ifdef MAC
1173out2:
1174#endif
1175	NDFREE(&nd, NDF_ONLY_PNBUF);
1176	vput(nd.ni_dvp);
1177	vn_finished_write(mp);
1178	ASSERT_VOP_UNLOCKED(nd.ni_dvp, "symlink");
1179	ASSERT_VOP_UNLOCKED(nd.ni_vp, "symlink");
1180out:
1181	if (segflg != UIO_SYSSPACE)
1182		uma_zfree(namei_zone, syspath);
1183	return (error);
1184}
1185
1186/*
1187 * Delete a whiteout from the filesystem.
1188 */
1189/* ARGSUSED */
1190int
1191undelete(td, uap)
1192	struct thread *td;
1193	register struct undelete_args /* {
1194		char *path;
1195	} */ *uap;
1196{
1197	int error;
1198	struct mount *mp;
1199	struct nameidata nd;
1200
1201restart:
1202	bwillwrite();
1203	NDINIT(&nd, DELETE, LOCKPARENT|DOWHITEOUT, UIO_USERSPACE,
1204	    uap->path, td);
1205	error = namei(&nd);
1206	if (error)
1207		return (error);
1208
1209	if (nd.ni_vp != NULLVP || !(nd.ni_cnd.cn_flags & ISWHITEOUT)) {
1210		NDFREE(&nd, NDF_ONLY_PNBUF);
1211		if (nd.ni_vp)
1212			vrele(nd.ni_vp);
1213		vput(nd.ni_dvp);
1214		return (EEXIST);
1215	}
1216	if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
1217		NDFREE(&nd, NDF_ONLY_PNBUF);
1218		vput(nd.ni_dvp);
1219		if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
1220			return (error);
1221		goto restart;
1222	}
1223	VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
1224	error = VOP_WHITEOUT(nd.ni_dvp, &nd.ni_cnd, DELETE);
1225	NDFREE(&nd, NDF_ONLY_PNBUF);
1226	vput(nd.ni_dvp);
1227	vn_finished_write(mp);
1228	ASSERT_VOP_UNLOCKED(nd.ni_dvp, "undelete");
1229	ASSERT_VOP_UNLOCKED(nd.ni_vp, "undelete");
1230	return (error);
1231}
1232
1233/*
1234 * Delete a name from the filesystem.
1235 */
1236#ifndef _SYS_SYSPROTO_H_
1237struct unlink_args {
1238	char	*path;
1239};
1240#endif
1241/* ARGSUSED */
1242int
1243unlink(td, uap)
1244	struct thread *td;
1245	struct unlink_args /* {
1246		char *path;
1247	} */ *uap;
1248{
1249
1250	return (kern_unlink(td, uap->path, UIO_USERSPACE));
1251}
1252
1253int
1254kern_unlink(struct thread *td, char *path, enum uio_seg pathseg)
1255{
1256	struct mount *mp;
1257	struct vnode *vp;
1258	int error;
1259	struct nameidata nd;
1260
1261restart:
1262	bwillwrite();
1263	NDINIT(&nd, DELETE, LOCKPARENT|LOCKLEAF, pathseg, path, td);
1264	if ((error = namei(&nd)) != 0)
1265		return (error);
1266	vp = nd.ni_vp;
1267	if (vp->v_type == VDIR)
1268		error = EPERM;		/* POSIX */
1269	else {
1270		/*
1271		 * The root of a mounted filesystem cannot be deleted.
1272		 *
1273		 * XXX: can this only be a VDIR case?
1274		 */
1275		if (vp->v_vflag & VV_ROOT)
1276			error = EBUSY;
1277	}
1278	if (error == 0) {
1279		if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
1280			NDFREE(&nd, NDF_ONLY_PNBUF);
1281			if (vp == nd.ni_dvp)
1282				vrele(vp);
1283			else
1284				vput(vp);
1285			vput(nd.ni_dvp);
1286			if ((error = vn_start_write(NULL, &mp,
1287			    V_XSLEEP | PCATCH)) != 0)
1288				return (error);
1289			goto restart;
1290		}
1291#ifdef MAC
1292		error = mac_check_vnode_delete(td->td_ucred, nd.ni_dvp, vp,
1293		    &nd.ni_cnd);
1294		if (error)
1295			goto out;
1296#endif
1297		VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
1298		error = VOP_REMOVE(nd.ni_dvp, vp, &nd.ni_cnd);
1299#ifdef MAC
1300out:
1301#endif
1302		vn_finished_write(mp);
1303	}
1304	NDFREE(&nd, NDF_ONLY_PNBUF);
1305	if (vp == nd.ni_dvp)
1306		vrele(vp);
1307	else
1308		vput(vp);
1309	vput(nd.ni_dvp);
1310	ASSERT_VOP_UNLOCKED(nd.ni_dvp, "unlink");
1311	ASSERT_VOP_UNLOCKED(nd.ni_vp, "unlink");
1312	return (error);
1313}
1314
1315/*
1316 * Reposition read/write file offset.
1317 */
1318#ifndef _SYS_SYSPROTO_H_
1319struct lseek_args {
1320	int	fd;
1321	int	pad;
1322	off_t	offset;
1323	int	whence;
1324};
1325#endif
1326int
1327lseek(td, uap)
1328	struct thread *td;
1329	register struct lseek_args /* {
1330		int fd;
1331		int pad;
1332		off_t offset;
1333		int whence;
1334	} */ *uap;
1335{
1336	struct ucred *cred = td->td_ucred;
1337	struct file *fp;
1338	struct vnode *vp;
1339	struct vattr vattr;
1340	off_t offset;
1341	int error, noneg;
1342
1343	if ((error = fget(td, uap->fd, &fp)) != 0)
1344		return (error);
1345	if (!(fp->f_ops->fo_flags & DFLAG_SEEKABLE)) {
1346		fdrop(fp, td);
1347		return (ESPIPE);
1348	}
1349	vp = fp->f_data;
1350	noneg = (vp->v_type != VCHR);
1351	offset = uap->offset;
1352	switch (uap->whence) {
1353	case L_INCR:
1354		if (noneg &&
1355		    (fp->f_offset < 0 ||
1356		    (offset > 0 && fp->f_offset > OFF_MAX - offset))) {
1357			error = EOVERFLOW;
1358			break;
1359		}
1360		offset += fp->f_offset;
1361		break;
1362	case L_XTND:
1363		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
1364		error = VOP_GETATTR(vp, &vattr, cred, td);
1365		VOP_UNLOCK(vp, 0, td);
1366		if (error)
1367			break;
1368		if (noneg &&
1369		    (vattr.va_size > OFF_MAX ||
1370		    (offset > 0 && vattr.va_size > OFF_MAX - offset))) {
1371			error = EOVERFLOW;
1372			break;
1373		}
1374		offset += vattr.va_size;
1375		break;
1376	case L_SET:
1377		break;
1378	default:
1379		error = EINVAL;
1380	}
1381	if (error == 0 && noneg && offset < 0)
1382		error = EINVAL;
1383	if (error != 0) {
1384		fdrop(fp, td);
1385		return (error);
1386	}
1387	fp->f_offset = offset;
1388	*(off_t *)(td->td_retval) = fp->f_offset;
1389	fdrop(fp, td);
1390	return (0);
1391}
1392
1393#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1394/*
1395 * Reposition read/write file offset.
1396 */
1397#ifndef _SYS_SYSPROTO_H_
1398struct olseek_args {
1399	int	fd;
1400	long	offset;
1401	int	whence;
1402};
1403#endif
1404int
1405olseek(td, uap)
1406	struct thread *td;
1407	register struct olseek_args /* {
1408		int fd;
1409		long offset;
1410		int whence;
1411	} */ *uap;
1412{
1413	struct lseek_args /* {
1414		int fd;
1415		int pad;
1416		off_t offset;
1417		int whence;
1418	} */ nuap;
1419	int error;
1420
1421	nuap.fd = uap->fd;
1422	nuap.offset = uap->offset;
1423	nuap.whence = uap->whence;
1424	error = lseek(td, &nuap);
1425	return (error);
1426}
1427#endif /* COMPAT_43 */
1428
1429/*
1430 * Check access permissions using passed credentials.
1431 */
1432static int
1433vn_access(vp, user_flags, cred, td)
1434	struct vnode	*vp;
1435	int		user_flags;
1436	struct ucred	*cred;
1437	struct thread	*td;
1438{
1439	int error, flags;
1440
1441	/* Flags == 0 means only check for existence. */
1442	error = 0;
1443	if (user_flags) {
1444		flags = 0;
1445		if (user_flags & R_OK)
1446			flags |= VREAD;
1447		if (user_flags & W_OK)
1448			flags |= VWRITE;
1449		if (user_flags & X_OK)
1450			flags |= VEXEC;
1451#ifdef MAC
1452		error = mac_check_vnode_access(cred, vp, flags);
1453		if (error)
1454			return (error);
1455#endif
1456		if ((flags & VWRITE) == 0 || (error = vn_writechk(vp)) == 0)
1457			error = VOP_ACCESS(vp, flags, cred, td);
1458	}
1459	return (error);
1460}
1461
1462/*
1463 * Check access permissions using "real" credentials.
1464 */
1465#ifndef _SYS_SYSPROTO_H_
1466struct access_args {
1467	char	*path;
1468	int	flags;
1469};
1470#endif
1471int
1472access(td, uap)
1473	struct thread *td;
1474	register struct access_args /* {
1475		char *path;
1476		int flags;
1477	} */ *uap;
1478{
1479
1480	return (kern_access(td, uap->path, UIO_USERSPACE, uap->flags));
1481}
1482
1483int
1484kern_access(struct thread *td, char *path, enum uio_seg pathseg, int flags)
1485{
1486	struct ucred *cred, *tmpcred;
1487	register struct vnode *vp;
1488	int error;
1489	struct nameidata nd;
1490
1491	/*
1492	 * Create and modify a temporary credential instead of one that
1493	 * is potentially shared.  This could also mess up socket
1494	 * buffer accounting which can run in an interrupt context.
1495	 *
1496	 * XXX - Depending on how "threads" are finally implemented, it
1497	 * may be better to explicitly pass the credential to namei()
1498	 * rather than to modify the potentially shared process structure.
1499	 */
1500	cred = td->td_ucred;
1501	tmpcred = crdup(cred);
1502	tmpcred->cr_uid = cred->cr_ruid;
1503	tmpcred->cr_groups[0] = cred->cr_rgid;
1504	td->td_ucred = tmpcred;
1505	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, pathseg, path, td);
1506	if ((error = namei(&nd)) != 0)
1507		goto out1;
1508	vp = nd.ni_vp;
1509
1510	error = vn_access(vp, flags, tmpcred, td);
1511	NDFREE(&nd, NDF_ONLY_PNBUF);
1512	vput(vp);
1513out1:
1514	td->td_ucred = cred;
1515	crfree(tmpcred);
1516	return (error);
1517}
1518
1519/*
1520 * Check access permissions using "effective" credentials.
1521 */
1522#ifndef _SYS_SYSPROTO_H_
1523struct eaccess_args {
1524	char	*path;
1525	int	flags;
1526};
1527#endif
1528int
1529eaccess(td, uap)
1530	struct thread *td;
1531	register struct eaccess_args /* {
1532		char *path;
1533		int flags;
1534	} */ *uap;
1535{
1536	struct nameidata nd;
1537	struct vnode *vp;
1538	int error;
1539
1540	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1541	    uap->path, td);
1542	if ((error = namei(&nd)) != 0)
1543		return (error);
1544	vp = nd.ni_vp;
1545
1546	error = vn_access(vp, uap->flags, td->td_ucred, td);
1547	NDFREE(&nd, NDF_ONLY_PNBUF);
1548	vput(vp);
1549	return (error);
1550}
1551
1552#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
1553/*
1554 * Get file status; this version follows links.
1555 */
1556#ifndef _SYS_SYSPROTO_H_
1557struct ostat_args {
1558	char	*path;
1559	struct ostat *ub;
1560};
1561#endif
1562/* ARGSUSED */
1563int
1564ostat(td, uap)
1565	struct thread *td;
1566	register struct ostat_args /* {
1567		char *path;
1568		struct ostat *ub;
1569	} */ *uap;
1570{
1571	struct stat sb;
1572	struct ostat osb;
1573	int error;
1574	struct nameidata nd;
1575
1576	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1577	    uap->path, td);
1578	if ((error = namei(&nd)) != 0)
1579		return (error);
1580	NDFREE(&nd, NDF_ONLY_PNBUF);
1581	error = vn_stat(nd.ni_vp, &sb, td->td_ucred, NOCRED, td);
1582	vput(nd.ni_vp);
1583	if (error)
1584		return (error);
1585	cvtstat(&sb, &osb);
1586	error = copyout(&osb, uap->ub, sizeof (osb));
1587	return (error);
1588}
1589
1590/*
1591 * Get file status; this version does not follow links.
1592 */
1593#ifndef _SYS_SYSPROTO_H_
1594struct olstat_args {
1595	char	*path;
1596	struct ostat *ub;
1597};
1598#endif
1599/* ARGSUSED */
1600int
1601olstat(td, uap)
1602	struct thread *td;
1603	register struct olstat_args /* {
1604		char *path;
1605		struct ostat *ub;
1606	} */ *uap;
1607{
1608	struct vnode *vp;
1609	struct stat sb;
1610	struct ostat osb;
1611	int error;
1612	struct nameidata nd;
1613
1614	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1615	    uap->path, td);
1616	if ((error = namei(&nd)) != 0)
1617		return (error);
1618	vp = nd.ni_vp;
1619	error = vn_stat(vp, &sb, td->td_ucred, NOCRED, td);
1620	NDFREE(&nd, NDF_ONLY_PNBUF);
1621	vput(vp);
1622	if (error)
1623		return (error);
1624	cvtstat(&sb, &osb);
1625	error = copyout(&osb, uap->ub, sizeof (osb));
1626	return (error);
1627}
1628
1629/*
1630 * Convert from an old to a new stat structure.
1631 */
1632void
1633cvtstat(st, ost)
1634	struct stat *st;
1635	struct ostat *ost;
1636{
1637
1638	ost->st_dev = st->st_dev;
1639	ost->st_ino = st->st_ino;
1640	ost->st_mode = st->st_mode;
1641	ost->st_nlink = st->st_nlink;
1642	ost->st_uid = st->st_uid;
1643	ost->st_gid = st->st_gid;
1644	ost->st_rdev = st->st_rdev;
1645	if (st->st_size < (quad_t)1 << 32)
1646		ost->st_size = st->st_size;
1647	else
1648		ost->st_size = -2;
1649	ost->st_atime = st->st_atime;
1650	ost->st_mtime = st->st_mtime;
1651	ost->st_ctime = st->st_ctime;
1652	ost->st_blksize = st->st_blksize;
1653	ost->st_blocks = st->st_blocks;
1654	ost->st_flags = st->st_flags;
1655	ost->st_gen = st->st_gen;
1656}
1657#endif /* COMPAT_43 || COMPAT_SUNOS */
1658
1659/*
1660 * Get file status; this version follows links.
1661 */
1662#ifndef _SYS_SYSPROTO_H_
1663struct stat_args {
1664	char	*path;
1665	struct stat *ub;
1666};
1667#endif
1668/* ARGSUSED */
1669int
1670stat(td, uap)
1671	struct thread *td;
1672	register struct stat_args /* {
1673		char *path;
1674		struct stat *ub;
1675	} */ *uap;
1676{
1677	struct stat sb;
1678	int error;
1679	struct nameidata nd;
1680
1681#ifdef LOOKUP_SHARED
1682	NDINIT(&nd, LOOKUP, FOLLOW | LOCKSHARED | LOCKLEAF | NOOBJ,
1683	    UIO_USERSPACE, uap->path, td);
1684#else
1685	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1686	    uap->path, td);
1687#endif
1688	if ((error = namei(&nd)) != 0)
1689		return (error);
1690	error = vn_stat(nd.ni_vp, &sb, td->td_ucred, NOCRED, td);
1691	NDFREE(&nd, NDF_ONLY_PNBUF);
1692	vput(nd.ni_vp);
1693	if (error)
1694		return (error);
1695	error = copyout(&sb, uap->ub, sizeof (sb));
1696	return (error);
1697}
1698
1699/*
1700 * Get file status; this version does not follow links.
1701 */
1702#ifndef _SYS_SYSPROTO_H_
1703struct lstat_args {
1704	char	*path;
1705	struct stat *ub;
1706};
1707#endif
1708/* ARGSUSED */
1709int
1710lstat(td, uap)
1711	struct thread *td;
1712	register struct lstat_args /* {
1713		char *path;
1714		struct stat *ub;
1715	} */ *uap;
1716{
1717	int error;
1718	struct vnode *vp;
1719	struct stat sb;
1720	struct nameidata nd;
1721
1722	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1723	    uap->path, td);
1724	if ((error = namei(&nd)) != 0)
1725		return (error);
1726	vp = nd.ni_vp;
1727	error = vn_stat(vp, &sb, td->td_ucred, NOCRED, td);
1728	NDFREE(&nd, NDF_ONLY_PNBUF);
1729	vput(vp);
1730	if (error)
1731		return (error);
1732	error = copyout(&sb, uap->ub, sizeof (sb));
1733	return (error);
1734}
1735
1736/*
1737 * Implementation of the NetBSD stat() function.
1738 * XXX This should probably be collapsed with the FreeBSD version,
1739 * as the differences are only due to vn_stat() clearing spares at
1740 * the end of the structures.  vn_stat could be split to avoid this,
1741 * and thus collapse the following to close to zero code.
1742 */
1743void
1744cvtnstat(sb, nsb)
1745	struct stat *sb;
1746	struct nstat *nsb;
1747{
1748	bzero(nsb, sizeof *nsb);
1749	nsb->st_dev = sb->st_dev;
1750	nsb->st_ino = sb->st_ino;
1751	nsb->st_mode = sb->st_mode;
1752	nsb->st_nlink = sb->st_nlink;
1753	nsb->st_uid = sb->st_uid;
1754	nsb->st_gid = sb->st_gid;
1755	nsb->st_rdev = sb->st_rdev;
1756	nsb->st_atimespec = sb->st_atimespec;
1757	nsb->st_mtimespec = sb->st_mtimespec;
1758	nsb->st_ctimespec = sb->st_ctimespec;
1759	nsb->st_size = sb->st_size;
1760	nsb->st_blocks = sb->st_blocks;
1761	nsb->st_blksize = sb->st_blksize;
1762	nsb->st_flags = sb->st_flags;
1763	nsb->st_gen = sb->st_gen;
1764	nsb->st_birthtimespec = sb->st_birthtimespec;
1765}
1766
1767#ifndef _SYS_SYSPROTO_H_
1768struct nstat_args {
1769	char	*path;
1770	struct nstat *ub;
1771};
1772#endif
1773/* ARGSUSED */
1774int
1775nstat(td, uap)
1776	struct thread *td;
1777	register struct nstat_args /* {
1778		char *path;
1779		struct nstat *ub;
1780	} */ *uap;
1781{
1782	struct stat sb;
1783	struct nstat nsb;
1784	int error;
1785	struct nameidata nd;
1786
1787	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1788	    uap->path, td);
1789	if ((error = namei(&nd)) != 0)
1790		return (error);
1791	NDFREE(&nd, NDF_ONLY_PNBUF);
1792	error = vn_stat(nd.ni_vp, &sb, td->td_ucred, NOCRED, td);
1793	vput(nd.ni_vp);
1794	if (error)
1795		return (error);
1796	cvtnstat(&sb, &nsb);
1797	error = copyout(&nsb, uap->ub, sizeof (nsb));
1798	return (error);
1799}
1800
1801/*
1802 * NetBSD lstat.  Get file status; this version does not follow links.
1803 */
1804#ifndef _SYS_SYSPROTO_H_
1805struct lstat_args {
1806	char	*path;
1807	struct stat *ub;
1808};
1809#endif
1810/* ARGSUSED */
1811int
1812nlstat(td, uap)
1813	struct thread *td;
1814	register struct nlstat_args /* {
1815		char *path;
1816		struct nstat *ub;
1817	} */ *uap;
1818{
1819	int error;
1820	struct vnode *vp;
1821	struct stat sb;
1822	struct nstat nsb;
1823	struct nameidata nd;
1824
1825	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1826	    uap->path, td);
1827	if ((error = namei(&nd)) != 0)
1828		return (error);
1829	vp = nd.ni_vp;
1830	NDFREE(&nd, NDF_ONLY_PNBUF);
1831	error = vn_stat(vp, &sb, td->td_ucred, NOCRED, td);
1832	vput(vp);
1833	if (error)
1834		return (error);
1835	cvtnstat(&sb, &nsb);
1836	error = copyout(&nsb, uap->ub, sizeof (nsb));
1837	return (error);
1838}
1839
1840/*
1841 * Get configurable pathname variables.
1842 */
1843#ifndef _SYS_SYSPROTO_H_
1844struct pathconf_args {
1845	char	*path;
1846	int	name;
1847};
1848#endif
1849/* ARGSUSED */
1850int
1851pathconf(td, uap)
1852	struct thread *td;
1853	register struct pathconf_args /* {
1854		char *path;
1855		int name;
1856	} */ *uap;
1857{
1858	int error;
1859	struct nameidata nd;
1860
1861	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | NOOBJ, UIO_USERSPACE,
1862	    uap->path, td);
1863	if ((error = namei(&nd)) != 0)
1864		return (error);
1865	NDFREE(&nd, NDF_ONLY_PNBUF);
1866
1867	/* If asynchronous I/O is available, it works for all files. */
1868	if (uap->name == _PC_ASYNC_IO)
1869		td->td_retval[0] = async_io_version;
1870	else
1871		error = VOP_PATHCONF(nd.ni_vp, uap->name, td->td_retval);
1872	vput(nd.ni_vp);
1873	return (error);
1874}
1875
1876/*
1877 * Return target name of a symbolic link.
1878 */
1879#ifndef _SYS_SYSPROTO_H_
1880struct readlink_args {
1881	char	*path;
1882	char	*buf;
1883	int	count;
1884};
1885#endif
1886/* ARGSUSED */
1887int
1888readlink(td, uap)
1889	struct thread *td;
1890	register struct readlink_args /* {
1891		char *path;
1892		char *buf;
1893		int count;
1894	} */ *uap;
1895{
1896
1897	return (kern_readlink(td, uap->path, UIO_USERSPACE, uap->buf,
1898	    UIO_USERSPACE, uap->count));
1899}
1900
1901int
1902kern_readlink(struct thread *td, char *path, enum uio_seg pathseg, char *buf,
1903    enum uio_seg bufseg, int count)
1904{
1905	register struct vnode *vp;
1906	struct iovec aiov;
1907	struct uio auio;
1908	int error;
1909	struct nameidata nd;
1910
1911	NDINIT(&nd, LOOKUP, NOFOLLOW | LOCKLEAF | NOOBJ, pathseg, path, td);
1912	if ((error = namei(&nd)) != 0)
1913		return (error);
1914	NDFREE(&nd, NDF_ONLY_PNBUF);
1915	vp = nd.ni_vp;
1916#ifdef MAC
1917	error = mac_check_vnode_readlink(td->td_ucred, vp);
1918	if (error) {
1919		vput(vp);
1920		return (error);
1921	}
1922#endif
1923	if (vp->v_type != VLNK)
1924		error = EINVAL;
1925	else {
1926		aiov.iov_base = buf;
1927		aiov.iov_len = count;
1928		auio.uio_iov = &aiov;
1929		auio.uio_iovcnt = 1;
1930		auio.uio_offset = 0;
1931		auio.uio_rw = UIO_READ;
1932		auio.uio_segflg = bufseg;
1933		auio.uio_td = td;
1934		auio.uio_resid = count;
1935		error = VOP_READLINK(vp, &auio, td->td_ucred);
1936	}
1937	vput(vp);
1938	td->td_retval[0] = count - auio.uio_resid;
1939	return (error);
1940}
1941
1942/*
1943 * Common implementation code for chflags() and fchflags().
1944 */
1945static int
1946setfflags(td, vp, flags)
1947	struct thread *td;
1948	struct vnode *vp;
1949	int flags;
1950{
1951	int error;
1952	struct mount *mp;
1953	struct vattr vattr;
1954
1955	/*
1956	 * Prevent non-root users from setting flags on devices.  When
1957	 * a device is reused, users can retain ownership of the device
1958	 * if they are allowed to set flags and programs assume that
1959	 * chown can't fail when done as root.
1960	 */
1961	if (vp->v_type == VCHR || vp->v_type == VBLK) {
1962		error = suser_cred(td->td_ucred, PRISON_ROOT);
1963		if (error)
1964			return (error);
1965	}
1966
1967	if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
1968		return (error);
1969	VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
1970	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
1971	VATTR_NULL(&vattr);
1972	vattr.va_flags = flags;
1973#ifdef MAC
1974	error = mac_check_vnode_setflags(td->td_ucred, vp, vattr.va_flags);
1975	if (error == 0)
1976#endif
1977		error = VOP_SETATTR(vp, &vattr, td->td_ucred, td);
1978	VOP_UNLOCK(vp, 0, td);
1979	vn_finished_write(mp);
1980	return (error);
1981}
1982
1983/*
1984 * Change flags of a file given a path name.
1985 */
1986#ifndef _SYS_SYSPROTO_H_
1987struct chflags_args {
1988	char	*path;
1989	int	flags;
1990};
1991#endif
1992/* ARGSUSED */
1993int
1994chflags(td, uap)
1995	struct thread *td;
1996	register struct chflags_args /* {
1997		char *path;
1998		int flags;
1999	} */ *uap;
2000{
2001	int error;
2002	struct nameidata nd;
2003
2004	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
2005	if ((error = namei(&nd)) != 0)
2006		return (error);
2007	NDFREE(&nd, NDF_ONLY_PNBUF);
2008	error = setfflags(td, nd.ni_vp, uap->flags);
2009	vrele(nd.ni_vp);
2010	return error;
2011}
2012
2013/*
2014 * Same as chflags() but doesn't follow symlinks.
2015 */
2016int
2017lchflags(td, uap)
2018	struct thread *td;
2019	register struct lchflags_args /* {
2020		char *path;
2021		int flags;
2022	} */ *uap;
2023{
2024	int error;
2025	struct nameidata nd;
2026
2027	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, td);
2028	if ((error = namei(&nd)) != 0)
2029		return (error);
2030	NDFREE(&nd, NDF_ONLY_PNBUF);
2031	error = setfflags(td, nd.ni_vp, uap->flags);
2032	vrele(nd.ni_vp);
2033	return error;
2034}
2035
2036/*
2037 * Change flags of a file given a file descriptor.
2038 */
2039#ifndef _SYS_SYSPROTO_H_
2040struct fchflags_args {
2041	int	fd;
2042	int	flags;
2043};
2044#endif
2045/* ARGSUSED */
2046int
2047fchflags(td, uap)
2048	struct thread *td;
2049	register struct fchflags_args /* {
2050		int fd;
2051		int flags;
2052	} */ *uap;
2053{
2054	struct file *fp;
2055	int error;
2056
2057	if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0)
2058		return (error);
2059	error = setfflags(td, fp->f_data, uap->flags);
2060	fdrop(fp, td);
2061	return (error);
2062}
2063
2064/*
2065 * Common implementation code for chmod(), lchmod() and fchmod().
2066 */
2067static int
2068setfmode(td, vp, mode)
2069	struct thread *td;
2070	struct vnode *vp;
2071	int mode;
2072{
2073	int error;
2074	struct mount *mp;
2075	struct vattr vattr;
2076
2077	if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
2078		return (error);
2079	VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
2080	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
2081	VATTR_NULL(&vattr);
2082	vattr.va_mode = mode & ALLPERMS;
2083#ifdef MAC
2084	error = mac_check_vnode_setmode(td->td_ucred, vp, vattr.va_mode);
2085	if (error == 0)
2086#endif
2087		error = VOP_SETATTR(vp, &vattr, td->td_ucred, td);
2088	VOP_UNLOCK(vp, 0, td);
2089	vn_finished_write(mp);
2090	return error;
2091}
2092
2093/*
2094 * Change mode of a file given path name.
2095 */
2096#ifndef _SYS_SYSPROTO_H_
2097struct chmod_args {
2098	char	*path;
2099	int	mode;
2100};
2101#endif
2102/* ARGSUSED */
2103int
2104chmod(td, uap)
2105	struct thread *td;
2106	register struct chmod_args /* {
2107		char *path;
2108		int mode;
2109	} */ *uap;
2110{
2111
2112	return (kern_chmod(td, uap->path, UIO_USERSPACE, uap->mode));
2113}
2114
2115int
2116kern_chmod(struct thread *td, char *path, enum uio_seg pathseg, int mode)
2117{
2118	int error;
2119	struct nameidata nd;
2120
2121	NDINIT(&nd, LOOKUP, FOLLOW, pathseg, path, td);
2122	if ((error = namei(&nd)) != 0)
2123		return (error);
2124	NDFREE(&nd, NDF_ONLY_PNBUF);
2125	error = setfmode(td, nd.ni_vp, mode);
2126	vrele(nd.ni_vp);
2127	return error;
2128}
2129
2130/*
2131 * Change mode of a file given path name (don't follow links.)
2132 */
2133#ifndef _SYS_SYSPROTO_H_
2134struct lchmod_args {
2135	char	*path;
2136	int	mode;
2137};
2138#endif
2139/* ARGSUSED */
2140int
2141lchmod(td, uap)
2142	struct thread *td;
2143	register struct lchmod_args /* {
2144		char *path;
2145		int mode;
2146	} */ *uap;
2147{
2148	int error;
2149	struct nameidata nd;
2150
2151	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, td);
2152	if ((error = namei(&nd)) != 0)
2153		return (error);
2154	NDFREE(&nd, NDF_ONLY_PNBUF);
2155	error = setfmode(td, nd.ni_vp, uap->mode);
2156	vrele(nd.ni_vp);
2157	return error;
2158}
2159
2160/*
2161 * Change mode of a file given a file descriptor.
2162 */
2163#ifndef _SYS_SYSPROTO_H_
2164struct fchmod_args {
2165	int	fd;
2166	int	mode;
2167};
2168#endif
2169/* ARGSUSED */
2170int
2171fchmod(td, uap)
2172	struct thread *td;
2173	register struct fchmod_args /* {
2174		int fd;
2175		int mode;
2176	} */ *uap;
2177{
2178	struct file *fp;
2179	int error;
2180
2181	if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0)
2182		return (error);
2183	error = setfmode(td, fp->f_data, uap->mode);
2184	fdrop(fp, td);
2185	return (error);
2186}
2187
2188/*
2189 * Common implementation for chown(), lchown(), and fchown()
2190 */
2191static int
2192setfown(td, vp, uid, gid)
2193	struct thread *td;
2194	struct vnode *vp;
2195	uid_t uid;
2196	gid_t gid;
2197{
2198	int error;
2199	struct mount *mp;
2200	struct vattr vattr;
2201
2202	if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
2203		return (error);
2204	VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
2205	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
2206	VATTR_NULL(&vattr);
2207	vattr.va_uid = uid;
2208	vattr.va_gid = gid;
2209#ifdef MAC
2210	error = mac_check_vnode_setowner(td->td_ucred, vp, vattr.va_uid,
2211	    vattr.va_gid);
2212	if (error == 0)
2213#endif
2214		error = VOP_SETATTR(vp, &vattr, td->td_ucred, td);
2215	VOP_UNLOCK(vp, 0, td);
2216	vn_finished_write(mp);
2217	return error;
2218}
2219
2220/*
2221 * Set ownership given a path name.
2222 */
2223#ifndef _SYS_SYSPROTO_H_
2224struct chown_args {
2225	char	*path;
2226	int	uid;
2227	int	gid;
2228};
2229#endif
2230/* ARGSUSED */
2231int
2232chown(td, uap)
2233	struct thread *td;
2234	register struct chown_args /* {
2235		char *path;
2236		int uid;
2237		int gid;
2238	} */ *uap;
2239{
2240
2241	return (kern_chown(td, uap->path, UIO_USERSPACE, uap->uid, uap->gid));
2242}
2243
2244int
2245kern_chown(struct thread *td, char *path, enum uio_seg pathseg, int uid,
2246    int gid)
2247{
2248	int error;
2249	struct nameidata nd;
2250
2251	NDINIT(&nd, LOOKUP, FOLLOW, pathseg, path, td);
2252	if ((error = namei(&nd)) != 0)
2253		return (error);
2254	NDFREE(&nd, NDF_ONLY_PNBUF);
2255	error = setfown(td, nd.ni_vp, uid, gid);
2256	vrele(nd.ni_vp);
2257	return (error);
2258}
2259
2260/*
2261 * Set ownership given a path name, do not cross symlinks.
2262 */
2263#ifndef _SYS_SYSPROTO_H_
2264struct lchown_args {
2265	char	*path;
2266	int	uid;
2267	int	gid;
2268};
2269#endif
2270/* ARGSUSED */
2271int
2272lchown(td, uap)
2273	struct thread *td;
2274	register struct lchown_args /* {
2275		char *path;
2276		int uid;
2277		int gid;
2278	} */ *uap;
2279{
2280
2281	return (kern_lchown(td, uap->path, UIO_USERSPACE, uap->uid, uap->gid));
2282}
2283
2284int
2285kern_lchown(struct thread *td, char *path, enum uio_seg pathseg, int uid,
2286    int gid)
2287{
2288	int error;
2289	struct nameidata nd;
2290
2291	NDINIT(&nd, LOOKUP, NOFOLLOW, pathseg, path, td);
2292	if ((error = namei(&nd)) != 0)
2293		return (error);
2294	NDFREE(&nd, NDF_ONLY_PNBUF);
2295	error = setfown(td, nd.ni_vp, uid, gid);
2296	vrele(nd.ni_vp);
2297	return (error);
2298}
2299
2300/*
2301 * Set ownership given a file descriptor.
2302 */
2303#ifndef _SYS_SYSPROTO_H_
2304struct fchown_args {
2305	int	fd;
2306	int	uid;
2307	int	gid;
2308};
2309#endif
2310/* ARGSUSED */
2311int
2312fchown(td, uap)
2313	struct thread *td;
2314	register struct fchown_args /* {
2315		int fd;
2316		int uid;
2317		int gid;
2318	} */ *uap;
2319{
2320	struct file *fp;
2321	int error;
2322
2323	if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0)
2324		return (error);
2325	error = setfown(td, fp->f_data, uap->uid, uap->gid);
2326	fdrop(fp, td);
2327	return (error);
2328}
2329
2330/*
2331 * Common implementation code for utimes(), lutimes(), and futimes().
2332 */
2333static int
2334getutimes(usrtvp, tvpseg, tsp)
2335	const struct timeval *usrtvp;
2336	enum uio_seg tvpseg;
2337	struct timespec *tsp;
2338{
2339	struct timeval tv[2];
2340	const struct timeval *tvp;
2341	int error;
2342
2343	if (usrtvp == NULL) {
2344		microtime(&tv[0]);
2345		TIMEVAL_TO_TIMESPEC(&tv[0], &tsp[0]);
2346		tsp[1] = tsp[0];
2347	} else {
2348		if (tvpseg == UIO_SYSSPACE) {
2349			tvp = usrtvp;
2350		} else {
2351			if ((error = copyin(usrtvp, tv, sizeof(tv))) != 0)
2352				return (error);
2353			tvp = tv;
2354		}
2355
2356		TIMEVAL_TO_TIMESPEC(&tvp[0], &tsp[0]);
2357		TIMEVAL_TO_TIMESPEC(&tvp[1], &tsp[1]);
2358	}
2359	return 0;
2360}
2361
2362/*
2363 * Common implementation code for utimes(), lutimes(), and futimes().
2364 */
2365static int
2366setutimes(td, vp, ts, numtimes, nullflag)
2367	struct thread *td;
2368	struct vnode *vp;
2369	const struct timespec *ts;
2370	int numtimes;
2371	int nullflag;
2372{
2373	int error, setbirthtime;
2374	struct mount *mp;
2375	struct vattr vattr;
2376
2377	if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
2378		return (error);
2379	VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
2380	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
2381	setbirthtime = 0;
2382	if (numtimes < 3 && VOP_GETATTR(vp, &vattr, td->td_ucred, td) == 0 &&
2383	    timespeccmp(&ts[1], &vattr.va_birthtime, < ))
2384		setbirthtime = 1;
2385	VATTR_NULL(&vattr);
2386	vattr.va_atime = ts[0];
2387	vattr.va_mtime = ts[1];
2388	if (setbirthtime)
2389		vattr.va_birthtime = ts[1];
2390	if (numtimes > 2)
2391		vattr.va_birthtime = ts[2];
2392	if (nullflag)
2393		vattr.va_vaflags |= VA_UTIMES_NULL;
2394#ifdef MAC
2395	error = mac_check_vnode_setutimes(td->td_ucred, vp, vattr.va_atime,
2396	    vattr.va_mtime);
2397#endif
2398	if (error == 0)
2399		error = VOP_SETATTR(vp, &vattr, td->td_ucred, td);
2400	VOP_UNLOCK(vp, 0, td);
2401	vn_finished_write(mp);
2402	return error;
2403}
2404
2405/*
2406 * Set the access and modification times of a file.
2407 */
2408#ifndef _SYS_SYSPROTO_H_
2409struct utimes_args {
2410	char	*path;
2411	struct	timeval *tptr;
2412};
2413#endif
2414/* ARGSUSED */
2415int
2416utimes(td, uap)
2417	struct thread *td;
2418	register struct utimes_args /* {
2419		char *path;
2420		struct timeval *tptr;
2421	} */ *uap;
2422{
2423
2424	return (kern_utimes(td, uap->path, UIO_USERSPACE, uap->tptr,
2425	    UIO_USERSPACE));
2426}
2427
2428int
2429kern_utimes(struct thread *td, char *path, enum uio_seg pathseg,
2430    struct timeval *tptr, enum uio_seg tptrseg)
2431{
2432	struct timespec ts[2];
2433	int error;
2434	struct nameidata nd;
2435
2436	if ((error = getutimes(tptr, tptrseg, ts)) != 0)
2437		return (error);
2438	NDINIT(&nd, LOOKUP, FOLLOW, pathseg, path, td);
2439	if ((error = namei(&nd)) != 0)
2440		return (error);
2441	NDFREE(&nd, NDF_ONLY_PNBUF);
2442	error = setutimes(td, nd.ni_vp, ts, 2, tptr == NULL);
2443	vrele(nd.ni_vp);
2444	return (error);
2445}
2446
2447/*
2448 * Set the access and modification times of a file.
2449 */
2450#ifndef _SYS_SYSPROTO_H_
2451struct lutimes_args {
2452	char	*path;
2453	struct	timeval *tptr;
2454};
2455#endif
2456/* ARGSUSED */
2457int
2458lutimes(td, uap)
2459	struct thread *td;
2460	register struct lutimes_args /* {
2461		char *path;
2462		struct timeval *tptr;
2463	} */ *uap;
2464{
2465
2466	return (kern_lutimes(td, uap->path, UIO_USERSPACE, uap->tptr,
2467	    UIO_USERSPACE));
2468}
2469
2470int
2471kern_lutimes(struct thread *td, char *path, enum uio_seg pathseg,
2472    struct timeval *tptr, enum uio_seg tptrseg)
2473{
2474	struct timespec ts[2];
2475	int error;
2476	struct nameidata nd;
2477
2478	if ((error = getutimes(tptr, tptrseg, ts)) != 0)
2479		return (error);
2480	NDINIT(&nd, LOOKUP, NOFOLLOW, pathseg, path, td);
2481	if ((error = namei(&nd)) != 0)
2482		return (error);
2483	NDFREE(&nd, NDF_ONLY_PNBUF);
2484	error = setutimes(td, nd.ni_vp, ts, 2, tptr == NULL);
2485	vrele(nd.ni_vp);
2486	return (error);
2487}
2488
2489/*
2490 * Set the access and modification times of a file.
2491 */
2492#ifndef _SYS_SYSPROTO_H_
2493struct futimes_args {
2494	int	fd;
2495	struct	timeval *tptr;
2496};
2497#endif
2498/* ARGSUSED */
2499int
2500futimes(td, uap)
2501	struct thread *td;
2502	register struct futimes_args /* {
2503		int  fd;
2504		struct timeval *tptr;
2505	} */ *uap;
2506{
2507
2508	return (kern_futimes(td, uap->fd, uap->tptr, UIO_USERSPACE));
2509}
2510
2511int
2512kern_futimes(struct thread *td, int fd, struct timeval *tptr,
2513    enum uio_seg tptrseg)
2514{
2515	struct timespec ts[2];
2516	struct file *fp;
2517	int error;
2518
2519	if ((error = getutimes(tptr, tptrseg, ts)) != 0)
2520		return (error);
2521	if ((error = getvnode(td->td_proc->p_fd, fd, &fp)) != 0)
2522		return (error);
2523	error = setutimes(td, fp->f_data, ts, 2, tptr == NULL);
2524	fdrop(fp, td);
2525	return (error);
2526}
2527
2528/*
2529 * Truncate a file given its path name.
2530 */
2531#ifndef _SYS_SYSPROTO_H_
2532struct truncate_args {
2533	char	*path;
2534	int	pad;
2535	off_t	length;
2536};
2537#endif
2538/* ARGSUSED */
2539int
2540truncate(td, uap)
2541	struct thread *td;
2542	register struct truncate_args /* {
2543		char *path;
2544		int pad;
2545		off_t length;
2546	} */ *uap;
2547{
2548
2549	return (kern_truncate(td, uap->path, UIO_USERSPACE, uap->length));
2550}
2551
2552int
2553kern_truncate(struct thread *td, char *path, enum uio_seg pathseg, off_t length)
2554{
2555	struct mount *mp;
2556	struct vnode *vp;
2557	struct vattr vattr;
2558	int error;
2559	struct nameidata nd;
2560
2561	if (length < 0)
2562		return(EINVAL);
2563	NDINIT(&nd, LOOKUP, FOLLOW, pathseg, path, td);
2564	if ((error = namei(&nd)) != 0)
2565		return (error);
2566	vp = nd.ni_vp;
2567	if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) {
2568		vrele(vp);
2569		return (error);
2570	}
2571	NDFREE(&nd, NDF_ONLY_PNBUF);
2572	VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
2573	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
2574	if (vp->v_type == VDIR)
2575		error = EISDIR;
2576#ifdef MAC
2577	else if ((error = mac_check_vnode_write(td->td_ucred, NOCRED, vp))) {
2578	}
2579#endif
2580	else if ((error = vn_writechk(vp)) == 0 &&
2581	    (error = VOP_ACCESS(vp, VWRITE, td->td_ucred, td)) == 0) {
2582		VATTR_NULL(&vattr);
2583		vattr.va_size = length;
2584		error = VOP_SETATTR(vp, &vattr, td->td_ucred, td);
2585	}
2586	vput(vp);
2587	vn_finished_write(mp);
2588	return (error);
2589}
2590
2591/*
2592 * Truncate a file given a file descriptor.
2593 */
2594#ifndef _SYS_SYSPROTO_H_
2595struct ftruncate_args {
2596	int	fd;
2597	int	pad;
2598	off_t	length;
2599};
2600#endif
2601/* ARGSUSED */
2602int
2603ftruncate(td, uap)
2604	struct thread *td;
2605	register struct ftruncate_args /* {
2606		int fd;
2607		int pad;
2608		off_t length;
2609	} */ *uap;
2610{
2611	struct mount *mp;
2612	struct vattr vattr;
2613	struct vnode *vp;
2614	struct file *fp;
2615	int error;
2616
2617	if (uap->length < 0)
2618		return(EINVAL);
2619	if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0)
2620		return (error);
2621	if ((fp->f_flag & FWRITE) == 0) {
2622		fdrop(fp, td);
2623		return (EINVAL);
2624	}
2625	vp = fp->f_data;
2626	if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) {
2627		fdrop(fp, td);
2628		return (error);
2629	}
2630	VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
2631	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
2632	if (vp->v_type == VDIR)
2633		error = EISDIR;
2634#ifdef MAC
2635	else if ((error = mac_check_vnode_write(td->td_ucred, fp->f_cred,
2636	    vp))) {
2637	}
2638#endif
2639	else if ((error = vn_writechk(vp)) == 0) {
2640		VATTR_NULL(&vattr);
2641		vattr.va_size = uap->length;
2642		error = VOP_SETATTR(vp, &vattr, fp->f_cred, td);
2643	}
2644	VOP_UNLOCK(vp, 0, td);
2645	vn_finished_write(mp);
2646	fdrop(fp, td);
2647	return (error);
2648}
2649
2650#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
2651/*
2652 * Truncate a file given its path name.
2653 */
2654#ifndef _SYS_SYSPROTO_H_
2655struct otruncate_args {
2656	char	*path;
2657	long	length;
2658};
2659#endif
2660/* ARGSUSED */
2661int
2662otruncate(td, uap)
2663	struct thread *td;
2664	register struct otruncate_args /* {
2665		char *path;
2666		long length;
2667	} */ *uap;
2668{
2669	struct truncate_args /* {
2670		char *path;
2671		int pad;
2672		off_t length;
2673	} */ nuap;
2674
2675	nuap.path = uap->path;
2676	nuap.length = uap->length;
2677	return (truncate(td, &nuap));
2678}
2679
2680/*
2681 * Truncate a file given a file descriptor.
2682 */
2683#ifndef _SYS_SYSPROTO_H_
2684struct oftruncate_args {
2685	int	fd;
2686	long	length;
2687};
2688#endif
2689/* ARGSUSED */
2690int
2691oftruncate(td, uap)
2692	struct thread *td;
2693	register struct oftruncate_args /* {
2694		int fd;
2695		long length;
2696	} */ *uap;
2697{
2698	struct ftruncate_args /* {
2699		int fd;
2700		int pad;
2701		off_t length;
2702	} */ nuap;
2703
2704	nuap.fd = uap->fd;
2705	nuap.length = uap->length;
2706	return (ftruncate(td, &nuap));
2707}
2708#endif /* COMPAT_43 || COMPAT_SUNOS */
2709
2710/*
2711 * Sync an open file.
2712 */
2713#ifndef _SYS_SYSPROTO_H_
2714struct fsync_args {
2715	int	fd;
2716};
2717#endif
2718/* ARGSUSED */
2719int
2720fsync(td, uap)
2721	struct thread *td;
2722	struct fsync_args /* {
2723		int fd;
2724	} */ *uap;
2725{
2726	struct vnode *vp;
2727	struct mount *mp;
2728	struct file *fp;
2729	vm_object_t obj;
2730	int error;
2731
2732	GIANT_REQUIRED;
2733
2734	if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0)
2735		return (error);
2736	vp = fp->f_data;
2737	if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0) {
2738		fdrop(fp, td);
2739		return (error);
2740	}
2741	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
2742	if (VOP_GETVOBJECT(vp, &obj) == 0) {
2743		VM_OBJECT_LOCK(obj);
2744		vm_object_page_clean(obj, 0, 0, 0);
2745		VM_OBJECT_UNLOCK(obj);
2746	}
2747	error = VOP_FSYNC(vp, fp->f_cred, MNT_WAIT, td);
2748	if (error == 0 && vp->v_mount && (vp->v_mount->mnt_flag & MNT_SOFTDEP)
2749	    && softdep_fsync_hook != NULL)
2750		error = (*softdep_fsync_hook)(vp);
2751
2752	VOP_UNLOCK(vp, 0, td);
2753	vn_finished_write(mp);
2754	fdrop(fp, td);
2755	return (error);
2756}
2757
2758/*
2759 * Rename files.  Source and destination must either both be directories,
2760 * or both not be directories.  If target is a directory, it must be empty.
2761 */
2762#ifndef _SYS_SYSPROTO_H_
2763struct rename_args {
2764	char	*from;
2765	char	*to;
2766};
2767#endif
2768/* ARGSUSED */
2769int
2770rename(td, uap)
2771	struct thread *td;
2772	register struct rename_args /* {
2773		char *from;
2774		char *to;
2775	} */ *uap;
2776{
2777
2778	return (kern_rename(td, uap->from, uap->to, UIO_USERSPACE));
2779}
2780
2781int
2782kern_rename(struct thread *td, char *from, char *to, enum uio_seg pathseg)
2783{
2784	struct mount *mp = NULL;
2785	struct vnode *tvp, *fvp, *tdvp;
2786	struct nameidata fromnd, tond;
2787	int error;
2788
2789	bwillwrite();
2790#ifdef MAC
2791	NDINIT(&fromnd, DELETE, LOCKPARENT | LOCKLEAF | SAVESTART, pathseg,
2792	    from, td);
2793#else
2794	NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, pathseg, from, td);
2795#endif
2796	if ((error = namei(&fromnd)) != 0)
2797		return (error);
2798#ifdef MAC
2799	error = mac_check_vnode_rename_from(td->td_ucred, fromnd.ni_dvp,
2800	    fromnd.ni_vp, &fromnd.ni_cnd);
2801	VOP_UNLOCK(fromnd.ni_dvp, 0, td);
2802	VOP_UNLOCK(fromnd.ni_vp, 0, td);
2803#endif
2804	fvp = fromnd.ni_vp;
2805	if (error == 0)
2806		error = vn_start_write(fvp, &mp, V_WAIT | PCATCH);
2807	if (error != 0) {
2808		NDFREE(&fromnd, NDF_ONLY_PNBUF);
2809		vrele(fromnd.ni_dvp);
2810		vrele(fvp);
2811		goto out1;
2812	}
2813	NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART |
2814	    NOOBJ, pathseg, to, td);
2815	if (fromnd.ni_vp->v_type == VDIR)
2816		tond.ni_cnd.cn_flags |= WILLBEDIR;
2817	if ((error = namei(&tond)) != 0) {
2818		/* Translate error code for rename("dir1", "dir2/."). */
2819		if (error == EISDIR && fvp->v_type == VDIR)
2820			error = EINVAL;
2821		NDFREE(&fromnd, NDF_ONLY_PNBUF);
2822		vrele(fromnd.ni_dvp);
2823		vrele(fvp);
2824		goto out1;
2825	}
2826	tdvp = tond.ni_dvp;
2827	tvp = tond.ni_vp;
2828	if (tvp != NULL) {
2829		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
2830			error = ENOTDIR;
2831			goto out;
2832		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
2833			error = EISDIR;
2834			goto out;
2835		}
2836	}
2837	if (fvp == tdvp)
2838		error = EINVAL;
2839	/*
2840	 * If the source is the same as the destination (that is, if they
2841	 * are links to the same vnode), then there is nothing to do.
2842	 */
2843	if (fvp == tvp)
2844		error = -1;
2845#ifdef MAC
2846	else
2847		error = mac_check_vnode_rename_to(td->td_ucred, tdvp,
2848		    tond.ni_vp, fromnd.ni_dvp == tdvp, &tond.ni_cnd);
2849#endif
2850out:
2851	if (!error) {
2852		VOP_LEASE(tdvp, td, td->td_ucred, LEASE_WRITE);
2853		if (fromnd.ni_dvp != tdvp) {
2854			VOP_LEASE(fromnd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
2855		}
2856		if (tvp) {
2857			VOP_LEASE(tvp, td, td->td_ucred, LEASE_WRITE);
2858		}
2859		error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
2860				   tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
2861		NDFREE(&fromnd, NDF_ONLY_PNBUF);
2862		NDFREE(&tond, NDF_ONLY_PNBUF);
2863	} else {
2864		NDFREE(&fromnd, NDF_ONLY_PNBUF);
2865		NDFREE(&tond, NDF_ONLY_PNBUF);
2866		if (tdvp == tvp)
2867			vrele(tdvp);
2868		else
2869			vput(tdvp);
2870		if (tvp)
2871			vput(tvp);
2872		vrele(fromnd.ni_dvp);
2873		vrele(fvp);
2874	}
2875	vrele(tond.ni_startdir);
2876	ASSERT_VOP_UNLOCKED(fromnd.ni_dvp, "rename");
2877	ASSERT_VOP_UNLOCKED(fromnd.ni_vp, "rename");
2878	ASSERT_VOP_UNLOCKED(tond.ni_dvp, "rename");
2879	ASSERT_VOP_UNLOCKED(tond.ni_vp, "rename");
2880out1:
2881	vn_finished_write(mp);
2882	if (fromnd.ni_startdir)
2883		vrele(fromnd.ni_startdir);
2884	if (error == -1)
2885		return (0);
2886	return (error);
2887}
2888
2889/*
2890 * Make a directory file.
2891 */
2892#ifndef _SYS_SYSPROTO_H_
2893struct mkdir_args {
2894	char	*path;
2895	int	mode;
2896};
2897#endif
2898/* ARGSUSED */
2899int
2900mkdir(td, uap)
2901	struct thread *td;
2902	register struct mkdir_args /* {
2903		char *path;
2904		int mode;
2905	} */ *uap;
2906{
2907
2908	return (kern_mkdir(td, uap->path, UIO_USERSPACE, uap->mode));
2909}
2910
2911int
2912kern_mkdir(struct thread *td, char *path, enum uio_seg segflg, int mode)
2913{
2914	struct mount *mp;
2915	struct vnode *vp;
2916	struct vattr vattr;
2917	int error;
2918	struct nameidata nd;
2919
2920restart:
2921	bwillwrite();
2922	NDINIT(&nd, CREATE, LOCKPARENT | SAVENAME, segflg, path, td);
2923	nd.ni_cnd.cn_flags |= WILLBEDIR;
2924	if ((error = namei(&nd)) != 0)
2925		return (error);
2926	vp = nd.ni_vp;
2927	if (vp != NULL) {
2928		NDFREE(&nd, NDF_ONLY_PNBUF);
2929		vrele(vp);
2930		/*
2931		 * XXX namei called with LOCKPARENT but not LOCKLEAF has
2932		 * the strange behaviour of leaving the vnode unlocked
2933		 * if the target is the same vnode as the parent.
2934		 */
2935		if (vp == nd.ni_dvp)
2936			vrele(nd.ni_dvp);
2937		else
2938			vput(nd.ni_dvp);
2939		return (EEXIST);
2940	}
2941	if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
2942		NDFREE(&nd, NDF_ONLY_PNBUF);
2943		vput(nd.ni_dvp);
2944		if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
2945			return (error);
2946		goto restart;
2947	}
2948	VATTR_NULL(&vattr);
2949	vattr.va_type = VDIR;
2950	FILEDESC_LOCK(td->td_proc->p_fd);
2951	vattr.va_mode = (mode & ACCESSPERMS) &~ td->td_proc->p_fd->fd_cmask;
2952	FILEDESC_UNLOCK(td->td_proc->p_fd);
2953#ifdef MAC
2954	error = mac_check_vnode_create(td->td_ucred, nd.ni_dvp, &nd.ni_cnd,
2955	    &vattr);
2956	if (error)
2957		goto out;
2958#endif
2959	VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
2960	error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &vattr);
2961#ifdef MAC
2962out:
2963#endif
2964	NDFREE(&nd, NDF_ONLY_PNBUF);
2965	vput(nd.ni_dvp);
2966	if (!error)
2967		vput(nd.ni_vp);
2968	vn_finished_write(mp);
2969	ASSERT_VOP_UNLOCKED(nd.ni_dvp, "mkdir");
2970	ASSERT_VOP_UNLOCKED(nd.ni_vp, "mkdir");
2971	return (error);
2972}
2973
2974/*
2975 * Remove a directory file.
2976 */
2977#ifndef _SYS_SYSPROTO_H_
2978struct rmdir_args {
2979	char	*path;
2980};
2981#endif
2982/* ARGSUSED */
2983int
2984rmdir(td, uap)
2985	struct thread *td;
2986	struct rmdir_args /* {
2987		char *path;
2988	} */ *uap;
2989{
2990
2991	return (kern_rmdir(td, uap->path, UIO_USERSPACE));
2992}
2993
2994int
2995kern_rmdir(struct thread *td, char *path, enum uio_seg pathseg)
2996{
2997	struct mount *mp;
2998	struct vnode *vp;
2999	int error;
3000	struct nameidata nd;
3001
3002restart:
3003	bwillwrite();
3004	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, pathseg, path, td);
3005	if ((error = namei(&nd)) != 0)
3006		return (error);
3007	vp = nd.ni_vp;
3008	if (vp->v_type != VDIR) {
3009		error = ENOTDIR;
3010		goto out;
3011	}
3012	/*
3013	 * No rmdir "." please.
3014	 */
3015	if (nd.ni_dvp == vp) {
3016		error = EINVAL;
3017		goto out;
3018	}
3019	/*
3020	 * The root of a mounted filesystem cannot be deleted.
3021	 */
3022	if (vp->v_vflag & VV_ROOT) {
3023		error = EBUSY;
3024		goto out;
3025	}
3026#ifdef MAC
3027	error = mac_check_vnode_delete(td->td_ucred, nd.ni_dvp, vp,
3028	    &nd.ni_cnd);
3029	if (error)
3030		goto out;
3031#endif
3032	if (vn_start_write(nd.ni_dvp, &mp, V_NOWAIT) != 0) {
3033		NDFREE(&nd, NDF_ONLY_PNBUF);
3034		if (nd.ni_dvp == vp)
3035			vrele(nd.ni_dvp);
3036		else
3037			vput(nd.ni_dvp);
3038		vput(vp);
3039		if ((error = vn_start_write(NULL, &mp, V_XSLEEP | PCATCH)) != 0)
3040			return (error);
3041		goto restart;
3042	}
3043	VOP_LEASE(nd.ni_dvp, td, td->td_ucred, LEASE_WRITE);
3044	VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
3045	error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
3046	vn_finished_write(mp);
3047out:
3048	NDFREE(&nd, NDF_ONLY_PNBUF);
3049	if (nd.ni_dvp == vp)
3050		vrele(nd.ni_dvp);
3051	else
3052		vput(nd.ni_dvp);
3053	vput(vp);
3054	ASSERT_VOP_UNLOCKED(nd.ni_dvp, "rmdir");
3055	ASSERT_VOP_UNLOCKED(nd.ni_vp, "rmdir");
3056	return (error);
3057}
3058
3059#ifdef COMPAT_43
3060/*
3061 * Read a block of directory entries in a filesystem independent format.
3062 */
3063#ifndef _SYS_SYSPROTO_H_
3064struct ogetdirentries_args {
3065	int	fd;
3066	char	*buf;
3067	u_int	count;
3068	long	*basep;
3069};
3070#endif
3071int
3072ogetdirentries(td, uap)
3073	struct thread *td;
3074	register struct ogetdirentries_args /* {
3075		int fd;
3076		char *buf;
3077		u_int count;
3078		long *basep;
3079	} */ *uap;
3080{
3081	struct vnode *vp;
3082	struct file *fp;
3083	struct uio auio, kuio;
3084	struct iovec aiov, kiov;
3085	struct dirent *dp, *edp;
3086	caddr_t dirbuf;
3087	int error, eofflag, readcnt;
3088	long loff;
3089
3090	/* XXX arbitrary sanity limit on `count'. */
3091	if (uap->count > 64 * 1024)
3092		return (EINVAL);
3093	if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0)
3094		return (error);
3095	if ((fp->f_flag & FREAD) == 0) {
3096		fdrop(fp, td);
3097		return (EBADF);
3098	}
3099	vp = fp->f_data;
3100unionread:
3101	if (vp->v_type != VDIR) {
3102		fdrop(fp, td);
3103		return (EINVAL);
3104	}
3105	aiov.iov_base = uap->buf;
3106	aiov.iov_len = uap->count;
3107	auio.uio_iov = &aiov;
3108	auio.uio_iovcnt = 1;
3109	auio.uio_rw = UIO_READ;
3110	auio.uio_segflg = UIO_USERSPACE;
3111	auio.uio_td = td;
3112	auio.uio_resid = uap->count;
3113	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
3114	loff = auio.uio_offset = fp->f_offset;
3115#ifdef MAC
3116	error = mac_check_vnode_readdir(td->td_ucred, vp);
3117	if (error) {
3118		VOP_UNLOCK(vp, 0, td);
3119		fdrop(fp, td);
3120		return (error);
3121	}
3122#endif
3123#	if (BYTE_ORDER != LITTLE_ENDIAN)
3124		if (vp->v_mount->mnt_maxsymlinklen <= 0) {
3125			error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag,
3126			    NULL, NULL);
3127			fp->f_offset = auio.uio_offset;
3128		} else
3129#	endif
3130	{
3131		kuio = auio;
3132		kuio.uio_iov = &kiov;
3133		kuio.uio_segflg = UIO_SYSSPACE;
3134		kiov.iov_len = uap->count;
3135		MALLOC(dirbuf, caddr_t, uap->count, M_TEMP, M_WAITOK);
3136		kiov.iov_base = dirbuf;
3137		error = VOP_READDIR(vp, &kuio, fp->f_cred, &eofflag,
3138			    NULL, NULL);
3139		fp->f_offset = kuio.uio_offset;
3140		if (error == 0) {
3141			readcnt = uap->count - kuio.uio_resid;
3142			edp = (struct dirent *)&dirbuf[readcnt];
3143			for (dp = (struct dirent *)dirbuf; dp < edp; ) {
3144#				if (BYTE_ORDER == LITTLE_ENDIAN)
3145					/*
3146					 * The expected low byte of
3147					 * dp->d_namlen is our dp->d_type.
3148					 * The high MBZ byte of dp->d_namlen
3149					 * is our dp->d_namlen.
3150					 */
3151					dp->d_type = dp->d_namlen;
3152					dp->d_namlen = 0;
3153#				else
3154					/*
3155					 * The dp->d_type is the high byte
3156					 * of the expected dp->d_namlen,
3157					 * so must be zero'ed.
3158					 */
3159					dp->d_type = 0;
3160#				endif
3161				if (dp->d_reclen > 0) {
3162					dp = (struct dirent *)
3163					    ((char *)dp + dp->d_reclen);
3164				} else {
3165					error = EIO;
3166					break;
3167				}
3168			}
3169			if (dp >= edp)
3170				error = uiomove(dirbuf, readcnt, &auio);
3171		}
3172		FREE(dirbuf, M_TEMP);
3173	}
3174	VOP_UNLOCK(vp, 0, td);
3175	if (error) {
3176		fdrop(fp, td);
3177		return (error);
3178	}
3179	if (uap->count == auio.uio_resid) {
3180		if (union_dircheckp) {
3181			error = union_dircheckp(td, &vp, fp);
3182			if (error == -1)
3183				goto unionread;
3184			if (error) {
3185				fdrop(fp, td);
3186				return (error);
3187			}
3188		}
3189		/*
3190		 * XXX We could delay dropping the lock above but
3191		 * union_dircheckp complicates things.
3192		 */
3193		vn_lock(vp, LK_EXCLUSIVE|LK_RETRY, td);
3194		if ((vp->v_vflag & VV_ROOT) &&
3195		    (vp->v_mount->mnt_flag & MNT_UNION)) {
3196			struct vnode *tvp = vp;
3197			vp = vp->v_mount->mnt_vnodecovered;
3198			VREF(vp);
3199			fp->f_data = vp;
3200			fp->f_offset = 0;
3201			vput(tvp);
3202			goto unionread;
3203		}
3204		VOP_UNLOCK(vp, 0, td);
3205	}
3206	error = copyout(&loff, uap->basep, sizeof(long));
3207	fdrop(fp, td);
3208	td->td_retval[0] = uap->count - auio.uio_resid;
3209	return (error);
3210}
3211#endif /* COMPAT_43 */
3212
3213/*
3214 * Read a block of directory entries in a filesystem independent format.
3215 */
3216#ifndef _SYS_SYSPROTO_H_
3217struct getdirentries_args {
3218	int	fd;
3219	char	*buf;
3220	u_int	count;
3221	long	*basep;
3222};
3223#endif
3224int
3225getdirentries(td, uap)
3226	struct thread *td;
3227	register struct getdirentries_args /* {
3228		int fd;
3229		char *buf;
3230		u_int count;
3231		long *basep;
3232	} */ *uap;
3233{
3234	struct vnode *vp;
3235	struct file *fp;
3236	struct uio auio;
3237	struct iovec aiov;
3238	long loff;
3239	int error, eofflag;
3240
3241	if ((error = getvnode(td->td_proc->p_fd, uap->fd, &fp)) != 0)
3242		return (error);
3243	if ((fp->f_flag & FREAD) == 0) {
3244		fdrop(fp, td);
3245		return (EBADF);
3246	}
3247	vp = fp->f_data;
3248unionread:
3249	if (vp->v_type != VDIR) {
3250		fdrop(fp, td);
3251		return (EINVAL);
3252	}
3253	aiov.iov_base = uap->buf;
3254	aiov.iov_len = uap->count;
3255	auio.uio_iov = &aiov;
3256	auio.uio_iovcnt = 1;
3257	auio.uio_rw = UIO_READ;
3258	auio.uio_segflg = UIO_USERSPACE;
3259	auio.uio_td = td;
3260	auio.uio_resid = uap->count;
3261	/* vn_lock(vp, LK_SHARED | LK_RETRY, td); */
3262	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
3263	loff = auio.uio_offset = fp->f_offset;
3264#ifdef MAC
3265	error = mac_check_vnode_readdir(td->td_ucred, vp);
3266	if (error == 0)
3267#endif
3268		error = VOP_READDIR(vp, &auio, fp->f_cred, &eofflag, NULL,
3269		    NULL);
3270	fp->f_offset = auio.uio_offset;
3271	VOP_UNLOCK(vp, 0, td);
3272	if (error) {
3273		fdrop(fp, td);
3274		return (error);
3275	}
3276	if (uap->count == auio.uio_resid) {
3277		if (union_dircheckp) {
3278			error = union_dircheckp(td, &vp, fp);
3279			if (error == -1)
3280				goto unionread;
3281			if (error) {
3282				fdrop(fp, td);
3283				return (error);
3284			}
3285		}
3286		/*
3287		 * XXX We could delay dropping the lock above but
3288		 * union_dircheckp complicates things.
3289		 */
3290		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
3291		if ((vp->v_vflag & VV_ROOT) &&
3292		    (vp->v_mount->mnt_flag & MNT_UNION)) {
3293			struct vnode *tvp = vp;
3294			vp = vp->v_mount->mnt_vnodecovered;
3295			VREF(vp);
3296			fp->f_data = vp;
3297			fp->f_offset = 0;
3298			vput(tvp);
3299			goto unionread;
3300		}
3301		VOP_UNLOCK(vp, 0, td);
3302	}
3303	if (uap->basep != NULL) {
3304		error = copyout(&loff, uap->basep, sizeof(long));
3305	}
3306	td->td_retval[0] = uap->count - auio.uio_resid;
3307	fdrop(fp, td);
3308	return (error);
3309}
3310#ifndef _SYS_SYSPROTO_H_
3311struct getdents_args {
3312	int fd;
3313	char *buf;
3314	size_t count;
3315};
3316#endif
3317int
3318getdents(td, uap)
3319	struct thread *td;
3320	register struct getdents_args /* {
3321		int fd;
3322		char *buf;
3323		u_int count;
3324	} */ *uap;
3325{
3326	struct getdirentries_args ap;
3327	ap.fd = uap->fd;
3328	ap.buf = uap->buf;
3329	ap.count = uap->count;
3330	ap.basep = NULL;
3331	return getdirentries(td, &ap);
3332}
3333
3334/*
3335 * Set the mode mask for creation of filesystem nodes.
3336 *
3337 * MP SAFE
3338 */
3339#ifndef _SYS_SYSPROTO_H_
3340struct umask_args {
3341	int	newmask;
3342};
3343#endif
3344int
3345umask(td, uap)
3346	struct thread *td;
3347	struct umask_args /* {
3348		int newmask;
3349	} */ *uap;
3350{
3351	register struct filedesc *fdp;
3352
3353	FILEDESC_LOCK(td->td_proc->p_fd);
3354	fdp = td->td_proc->p_fd;
3355	td->td_retval[0] = fdp->fd_cmask;
3356	fdp->fd_cmask = uap->newmask & ALLPERMS;
3357	FILEDESC_UNLOCK(td->td_proc->p_fd);
3358	return (0);
3359}
3360
3361/*
3362 * Void all references to file by ripping underlying filesystem
3363 * away from vnode.
3364 */
3365#ifndef _SYS_SYSPROTO_H_
3366struct revoke_args {
3367	char	*path;
3368};
3369#endif
3370/* ARGSUSED */
3371int
3372revoke(td, uap)
3373	struct thread *td;
3374	register struct revoke_args /* {
3375		char *path;
3376	} */ *uap;
3377{
3378	struct mount *mp;
3379	struct vnode *vp;
3380	struct vattr vattr;
3381	int error;
3382	struct nameidata nd;
3383
3384	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->path, td);
3385	if ((error = namei(&nd)) != 0)
3386		return (error);
3387	vp = nd.ni_vp;
3388	NDFREE(&nd, NDF_ONLY_PNBUF);
3389	if (vp->v_type != VCHR) {
3390		vput(vp);
3391		return (EINVAL);
3392	}
3393#ifdef MAC
3394	error = mac_check_vnode_revoke(td->td_ucred, vp);
3395	if (error) {
3396		vput(vp);
3397		return (error);
3398	}
3399#endif
3400	error = VOP_GETATTR(vp, &vattr, td->td_ucred, td);
3401	if (error) {
3402		vput(vp);
3403		return (error);
3404	}
3405	VOP_UNLOCK(vp, 0, td);
3406	if (td->td_ucred->cr_uid != vattr.va_uid) {
3407		error = suser_cred(td->td_ucred, PRISON_ROOT);
3408		if (error)
3409			goto out;
3410	}
3411	if ((error = vn_start_write(vp, &mp, V_WAIT | PCATCH)) != 0)
3412		goto out;
3413	if (vcount(vp) > 1)
3414		VOP_REVOKE(vp, REVOKEALL);
3415	vn_finished_write(mp);
3416out:
3417	vrele(vp);
3418	return (error);
3419}
3420
3421/*
3422 * Convert a user file descriptor to a kernel file entry.
3423 * The file entry is locked upon returning.
3424 */
3425int
3426getvnode(fdp, fd, fpp)
3427	struct filedesc *fdp;
3428	int fd;
3429	struct file **fpp;
3430{
3431	int error;
3432	struct file *fp;
3433
3434	fp = NULL;
3435	if (fdp == NULL)
3436		error = EBADF;
3437	else {
3438		FILEDESC_LOCK(fdp);
3439		if ((u_int)fd >= fdp->fd_nfiles ||
3440		    (fp = fdp->fd_ofiles[fd]) == NULL)
3441			error = EBADF;
3442		else if (fp->f_type != DTYPE_VNODE && fp->f_type != DTYPE_FIFO) {
3443			fp = NULL;
3444			error = EINVAL;
3445		} else {
3446			fhold(fp);
3447			error = 0;
3448		}
3449		FILEDESC_UNLOCK(fdp);
3450	}
3451	*fpp = fp;
3452	return (error);
3453}
3454/*
3455 * Get (NFS) file handle
3456 */
3457#ifndef _SYS_SYSPROTO_H_
3458struct getfh_args {
3459	char	*fname;
3460	fhandle_t *fhp;
3461};
3462#endif
3463int
3464getfh(td, uap)
3465	struct thread *td;
3466	register struct getfh_args *uap;
3467{
3468	struct nameidata nd;
3469	fhandle_t fh;
3470	register struct vnode *vp;
3471	int error;
3472
3473	/*
3474	 * Must be super user
3475	 */
3476	error = suser(td);
3477	if (error)
3478		return (error);
3479	NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE, uap->fname, td);
3480	error = namei(&nd);
3481	if (error)
3482		return (error);
3483	NDFREE(&nd, NDF_ONLY_PNBUF);
3484	vp = nd.ni_vp;
3485	bzero(&fh, sizeof(fh));
3486	fh.fh_fsid = vp->v_mount->mnt_stat.f_fsid;
3487	error = VFS_VPTOFH(vp, &fh.fh_fid);
3488	vput(vp);
3489	if (error)
3490		return (error);
3491	error = copyout(&fh, uap->fhp, sizeof (fh));
3492	return (error);
3493}
3494
3495/*
3496 * syscall for the rpc.lockd to use to translate a NFS file handle into
3497 * an open descriptor.
3498 *
3499 * warning: do not remove the suser() call or this becomes one giant
3500 * security hole.
3501 */
3502#ifndef _SYS_SYSPROTO_H_
3503struct fhopen_args {
3504	const struct fhandle *u_fhp;
3505	int flags;
3506};
3507#endif
3508int
3509fhopen(td, uap)
3510	struct thread *td;
3511	struct fhopen_args /* {
3512		const struct fhandle *u_fhp;
3513		int flags;
3514	} */ *uap;
3515{
3516	struct proc *p = td->td_proc;
3517	struct mount *mp;
3518	struct vnode *vp;
3519	struct fhandle fhp;
3520	struct vattr vat;
3521	struct vattr *vap = &vat;
3522	struct flock lf;
3523	struct file *fp;
3524	register struct filedesc *fdp = p->p_fd;
3525	int fmode, mode, error, type;
3526	struct file *nfp;
3527	int indx;
3528
3529	/*
3530	 * Must be super user
3531	 */
3532	error = suser(td);
3533	if (error)
3534		return (error);
3535
3536	fmode = FFLAGS(uap->flags);
3537	/* why not allow a non-read/write open for our lockd? */
3538	if (((fmode & (FREAD | FWRITE)) == 0) || (fmode & O_CREAT))
3539		return (EINVAL);
3540	error = copyin(uap->u_fhp, &fhp, sizeof(fhp));
3541	if (error)
3542		return(error);
3543	/* find the mount point */
3544	mp = vfs_getvfs(&fhp.fh_fsid);
3545	if (mp == NULL)
3546		return (ESTALE);
3547	/* now give me my vnode, it gets returned to me locked */
3548	error = VFS_FHTOVP(mp, &fhp.fh_fid, &vp);
3549	if (error)
3550		return (error);
3551 	/*
3552	 * from now on we have to make sure not
3553	 * to forget about the vnode
3554	 * any error that causes an abort must vput(vp)
3555	 * just set error = err and 'goto bad;'.
3556	 */
3557
3558	/*
3559	 * from vn_open
3560	 */
3561	if (vp->v_type == VLNK) {
3562		error = EMLINK;
3563		goto bad;
3564	}
3565	if (vp->v_type == VSOCK) {
3566		error = EOPNOTSUPP;
3567		goto bad;
3568	}
3569	mode = 0;
3570	if (fmode & (FWRITE | O_TRUNC)) {
3571		if (vp->v_type == VDIR) {
3572			error = EISDIR;
3573			goto bad;
3574		}
3575		error = vn_writechk(vp);
3576		if (error)
3577			goto bad;
3578		mode |= VWRITE;
3579	}
3580	if (fmode & FREAD)
3581		mode |= VREAD;
3582	if (fmode & O_APPEND)
3583		mode |= VAPPEND;
3584#ifdef MAC
3585	error = mac_check_vnode_open(td->td_ucred, vp, mode);
3586	if (error)
3587		goto bad;
3588#endif
3589	if (mode) {
3590		error = VOP_ACCESS(vp, mode, td->td_ucred, td);
3591		if (error)
3592			goto bad;
3593	}
3594	if (fmode & O_TRUNC) {
3595		VOP_UNLOCK(vp, 0, td);				/* XXX */
3596		if ((error = vn_start_write(NULL, &mp, V_WAIT | PCATCH)) != 0) {
3597			vrele(vp);
3598			return (error);
3599		}
3600		VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
3601		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);	/* XXX */
3602#ifdef MAC
3603		/*
3604		 * We don't yet have fp->f_cred, so use td->td_ucred, which
3605		 * should be right.
3606		 */
3607		error = mac_check_vnode_write(td->td_ucred, td->td_ucred, vp);
3608		if (error == 0) {
3609#endif
3610			VATTR_NULL(vap);
3611			vap->va_size = 0;
3612			error = VOP_SETATTR(vp, vap, td->td_ucred, td);
3613#ifdef MAC
3614		}
3615#endif
3616		vn_finished_write(mp);
3617		if (error)
3618			goto bad;
3619	}
3620	error = VOP_OPEN(vp, fmode, td->td_ucred, td);
3621	if (error)
3622		goto bad;
3623	/*
3624	 * Make sure that a VM object is created for VMIO support.
3625	 */
3626	if (vn_canvmio(vp) == TRUE) {
3627		if ((error = vfs_object_create(vp, td, td->td_ucred)) != 0)
3628			goto bad;
3629	}
3630	if (fmode & FWRITE)
3631		vp->v_writecount++;
3632
3633	/*
3634	 * end of vn_open code
3635	 */
3636
3637	if ((error = falloc(td, &nfp, &indx)) != 0) {
3638		if (fmode & FWRITE)
3639			vp->v_writecount--;
3640		goto bad;
3641	}
3642	fp = nfp;
3643
3644	/*
3645	 * Hold an extra reference to avoid having fp ripped out
3646	 * from under us while we block in the lock op
3647	 */
3648	fhold(fp);
3649	nfp->f_data = vp;
3650	nfp->f_flag = fmode & FMASK;
3651	nfp->f_ops = &vnops;
3652	nfp->f_type = DTYPE_VNODE;
3653	if (fmode & (O_EXLOCK | O_SHLOCK)) {
3654		lf.l_whence = SEEK_SET;
3655		lf.l_start = 0;
3656		lf.l_len = 0;
3657		if (fmode & O_EXLOCK)
3658			lf.l_type = F_WRLCK;
3659		else
3660			lf.l_type = F_RDLCK;
3661		type = F_FLOCK;
3662		if ((fmode & FNONBLOCK) == 0)
3663			type |= F_WAIT;
3664		VOP_UNLOCK(vp, 0, td);
3665		if ((error = VOP_ADVLOCK(vp, (caddr_t)fp, F_SETLK, &lf,
3666			    type)) != 0) {
3667			/*
3668			 * The lock request failed.  Normally close the
3669			 * descriptor but handle the case where someone might
3670			 * have dup()d or close()d it when we weren't looking.
3671			 */
3672			FILEDESC_LOCK(fdp);
3673			if (fdp->fd_ofiles[indx] == fp) {
3674				fdp->fd_ofiles[indx] = NULL;
3675				FILEDESC_UNLOCK(fdp);
3676				fdrop(fp, td);
3677			} else
3678				FILEDESC_UNLOCK(fdp);
3679			/*
3680			 * release our private reference
3681			 */
3682			fdrop(fp, td);
3683			return(error);
3684		}
3685		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
3686		fp->f_flag |= FHASLOCK;
3687	}
3688	if ((vp->v_type == VREG) && (VOP_GETVOBJECT(vp, NULL) != 0))
3689		vfs_object_create(vp, td, td->td_ucred);
3690
3691	VOP_UNLOCK(vp, 0, td);
3692	fdrop(fp, td);
3693	td->td_retval[0] = indx;
3694	return (0);
3695
3696bad:
3697	vput(vp);
3698	return (error);
3699}
3700
3701/*
3702 * Stat an (NFS) file handle.
3703 */
3704#ifndef _SYS_SYSPROTO_H_
3705struct fhstat_args {
3706	struct fhandle *u_fhp;
3707	struct stat *sb;
3708};
3709#endif
3710int
3711fhstat(td, uap)
3712	struct thread *td;
3713	register struct fhstat_args /* {
3714		struct fhandle *u_fhp;
3715		struct stat *sb;
3716	} */ *uap;
3717{
3718	struct stat sb;
3719	fhandle_t fh;
3720	struct mount *mp;
3721	struct vnode *vp;
3722	int error;
3723
3724	/*
3725	 * Must be super user
3726	 */
3727	error = suser(td);
3728	if (error)
3729		return (error);
3730
3731	error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t));
3732	if (error)
3733		return (error);
3734
3735	if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
3736		return (ESTALE);
3737	if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)))
3738		return (error);
3739	error = vn_stat(vp, &sb, td->td_ucred, NOCRED, td);
3740	vput(vp);
3741	if (error)
3742		return (error);
3743	error = copyout(&sb, uap->sb, sizeof(sb));
3744	return (error);
3745}
3746
3747/*
3748 * Implement fstatfs() for (NFS) file handles.
3749 */
3750#ifndef _SYS_SYSPROTO_H_
3751struct fhstatfs_args {
3752	struct fhandle *u_fhp;
3753	struct statfs *buf;
3754};
3755#endif
3756int
3757fhstatfs(td, uap)
3758	struct thread *td;
3759	struct fhstatfs_args /* {
3760		struct fhandle *u_fhp;
3761		struct statfs *buf;
3762	} */ *uap;
3763{
3764	struct statfs *sp;
3765	struct mount *mp;
3766	struct vnode *vp;
3767	struct statfs sb;
3768	fhandle_t fh;
3769	int error;
3770
3771	/*
3772	 * Must be super user
3773	 */
3774	error = suser(td);
3775	if (error)
3776		return (error);
3777
3778	if ((error = copyin(uap->u_fhp, &fh, sizeof(fhandle_t))) != 0)
3779		return (error);
3780
3781	if ((mp = vfs_getvfs(&fh.fh_fsid)) == NULL)
3782		return (ESTALE);
3783	if ((error = VFS_FHTOVP(mp, &fh.fh_fid, &vp)))
3784		return (error);
3785	mp = vp->v_mount;
3786	sp = &mp->mnt_stat;
3787	vput(vp);
3788#ifdef MAC
3789	error = mac_check_mount_stat(td->td_ucred, mp);
3790	if (error)
3791		return (error);
3792#endif
3793	if ((error = VFS_STATFS(mp, sp, td)) != 0)
3794		return (error);
3795	sp->f_flags = mp->mnt_flag & MNT_VISFLAGMASK;
3796	if (suser(td)) {
3797		bcopy(sp, &sb, sizeof(sb));
3798		sb.f_fsid.val[0] = sb.f_fsid.val[1] = 0;
3799		sp = &sb;
3800	}
3801	return (copyout(sp, uap->buf, sizeof(*sp)));
3802}
3803
3804/*
3805 * Syscall to push extended attribute configuration information into the
3806 * VFS.  Accepts a path, which it converts to a mountpoint, as well as
3807 * a command (int cmd), and attribute name and misc data.  For now, the
3808 * attribute name is left in userspace for consumption by the VFS_op.
3809 * It will probably be changed to be copied into sysspace by the
3810 * syscall in the future, once issues with various consumers of the
3811 * attribute code have raised their hands.
3812 *
3813 * Currently this is used only by UFS Extended Attributes.
3814 */
3815int
3816extattrctl(td, uap)
3817	struct thread *td;
3818	struct extattrctl_args /* {
3819		const char *path;
3820		int cmd;
3821		const char *filename;
3822		int attrnamespace;
3823		const char *attrname;
3824	} */ *uap;
3825{
3826	struct vnode *filename_vp;
3827	struct nameidata nd;
3828	struct mount *mp, *mp_writable;
3829	char attrname[EXTATTR_MAXNAMELEN];
3830	int error;
3831
3832	/*
3833	 * uap->attrname is not always defined.  We check again later when we
3834	 * invoke the VFS call so as to pass in NULL there if needed.
3835	 */
3836	if (uap->attrname != NULL) {
3837		error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN,
3838		    NULL);
3839		if (error)
3840			return (error);
3841	}
3842
3843	/*
3844	 * uap->filename is not always defined.  If it is, grab a vnode lock,
3845	 * which VFS_EXTATTRCTL() will later release.
3846	 */
3847	filename_vp = NULL;
3848	if (uap->filename != NULL) {
3849		NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF, UIO_USERSPACE,
3850		    uap->filename, td);
3851		error = namei(&nd);
3852		if (error)
3853			return (error);
3854		filename_vp = nd.ni_vp;
3855		NDFREE(&nd, NDF_NO_VP_RELE | NDF_NO_VP_UNLOCK);
3856	}
3857
3858	/* uap->path is always defined. */
3859	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
3860	error = namei(&nd);
3861	if (error) {
3862		if (filename_vp != NULL)
3863			vput(filename_vp);
3864		return (error);
3865	}
3866	mp = nd.ni_vp->v_mount;
3867	error = vn_start_write(nd.ni_vp, &mp_writable, V_WAIT | PCATCH);
3868	NDFREE(&nd, 0);
3869	if (error) {
3870		if (filename_vp != NULL)
3871			vput(filename_vp);
3872		return (error);
3873	}
3874
3875	error = VFS_EXTATTRCTL(mp, uap->cmd, filename_vp, uap->attrnamespace,
3876	    uap->attrname != NULL ? attrname : NULL, td);
3877
3878	vn_finished_write(mp_writable);
3879	/*
3880	 * VFS_EXTATTRCTL will have unlocked, but not de-ref'd,
3881	 * filename_vp, so vrele it if it is defined.
3882	 */
3883	if (filename_vp != NULL)
3884		vrele(filename_vp);
3885	return (error);
3886}
3887
3888/*-
3889 * Set a named extended attribute on a file or directory
3890 *
3891 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
3892 *            kernelspace string pointer "attrname", userspace buffer
3893 *            pointer "data", buffer length "nbytes", thread "td".
3894 * Returns: 0 on success, an error number otherwise
3895 * Locks: none
3896 * References: vp must be a valid reference for the duration of the call
3897 */
3898static int
3899extattr_set_vp(struct vnode *vp, int attrnamespace, const char *attrname,
3900    void *data, size_t nbytes, struct thread *td)
3901{
3902	struct mount *mp;
3903	struct uio auio;
3904	struct iovec aiov;
3905	ssize_t cnt;
3906	int error;
3907
3908	error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
3909	if (error)
3910		return (error);
3911	VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
3912	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
3913
3914	aiov.iov_base = data;
3915	aiov.iov_len = nbytes;
3916	auio.uio_iov = &aiov;
3917	auio.uio_iovcnt = 1;
3918	auio.uio_offset = 0;
3919	if (nbytes > INT_MAX) {
3920		error = EINVAL;
3921		goto done;
3922	}
3923	auio.uio_resid = nbytes;
3924	auio.uio_rw = UIO_WRITE;
3925	auio.uio_segflg = UIO_USERSPACE;
3926	auio.uio_td = td;
3927	cnt = nbytes;
3928
3929#ifdef MAC
3930	error = mac_check_vnode_setextattr(td->td_ucred, vp, attrnamespace,
3931	    attrname, &auio);
3932	if (error)
3933		goto done;
3934#endif
3935
3936	error = VOP_SETEXTATTR(vp, attrnamespace, attrname, &auio,
3937	    td->td_ucred, td);
3938	cnt -= auio.uio_resid;
3939	td->td_retval[0] = cnt;
3940
3941done:
3942	VOP_UNLOCK(vp, 0, td);
3943	vn_finished_write(mp);
3944	return (error);
3945}
3946
3947int
3948extattr_set_fd(td, uap)
3949	struct thread *td;
3950	struct extattr_set_fd_args /* {
3951		int fd;
3952		int attrnamespace;
3953		const char *attrname;
3954		void *data;
3955		size_t nbytes;
3956	} */ *uap;
3957{
3958	struct file *fp;
3959	char attrname[EXTATTR_MAXNAMELEN];
3960	int error;
3961
3962	error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
3963	if (error)
3964		return (error);
3965
3966	error = getvnode(td->td_proc->p_fd, uap->fd, &fp);
3967	if (error)
3968		return (error);
3969
3970	error = extattr_set_vp(fp->f_data, uap->attrnamespace,
3971	    attrname, uap->data, uap->nbytes, td);
3972	fdrop(fp, td);
3973
3974	return (error);
3975}
3976
3977int
3978extattr_set_file(td, uap)
3979	struct thread *td;
3980	struct extattr_set_file_args /* {
3981		const char *path;
3982		int attrnamespace;
3983		const char *attrname;
3984		void *data;
3985		size_t nbytes;
3986	} */ *uap;
3987{
3988	struct nameidata nd;
3989	char attrname[EXTATTR_MAXNAMELEN];
3990	int error;
3991
3992	error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
3993	if (error)
3994		return (error);
3995
3996	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
3997	error = namei(&nd);
3998	if (error)
3999		return (error);
4000	NDFREE(&nd, NDF_ONLY_PNBUF);
4001
4002	error = extattr_set_vp(nd.ni_vp, uap->attrnamespace, attrname,
4003	    uap->data, uap->nbytes, td);
4004
4005	vrele(nd.ni_vp);
4006	return (error);
4007}
4008
4009int
4010extattr_set_link(td, uap)
4011	struct thread *td;
4012	struct extattr_set_link_args /* {
4013		const char *path;
4014		int attrnamespace;
4015		const char *attrname;
4016		void *data;
4017		size_t nbytes;
4018	} */ *uap;
4019{
4020	struct nameidata nd;
4021	char attrname[EXTATTR_MAXNAMELEN];
4022	int error;
4023
4024	error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
4025	if (error)
4026		return (error);
4027
4028	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, td);
4029	error = namei(&nd);
4030	if (error)
4031		return (error);
4032	NDFREE(&nd, NDF_ONLY_PNBUF);
4033
4034	error = extattr_set_vp(nd.ni_vp, uap->attrnamespace, attrname,
4035	    uap->data, uap->nbytes, td);
4036
4037	vrele(nd.ni_vp);
4038	return (error);
4039}
4040
4041/*-
4042 * Get a named extended attribute on a file or directory
4043 *
4044 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
4045 *            kernelspace string pointer "attrname", userspace buffer
4046 *            pointer "data", buffer length "nbytes", thread "td".
4047 * Returns: 0 on success, an error number otherwise
4048 * Locks: none
4049 * References: vp must be a valid reference for the duration of the call
4050 */
4051static int
4052extattr_get_vp(struct vnode *vp, int attrnamespace, const char *attrname,
4053    void *data, size_t nbytes, struct thread *td)
4054{
4055	struct uio auio, *auiop;
4056	struct iovec aiov;
4057	ssize_t cnt;
4058	size_t size, *sizep;
4059	int error;
4060
4061	/*
4062	 * XXX: Temporary API compatibility for applications that know
4063	 * about this hack ("" means list), but haven't been updated
4064	 * for the extattr_list_*() system calls yet.  This will go
4065	 * away for FreeBSD 5.3.
4066	 */
4067	if (strlen(attrname) == 0)
4068		return (extattr_list_vp(vp, attrnamespace, data, nbytes, td));
4069
4070	VOP_LEASE(vp, td, td->td_ucred, LEASE_READ);
4071	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
4072
4073	/*
4074	 * Slightly unusual semantics: if the user provides a NULL data
4075	 * pointer, they don't want to receive the data, just the
4076	 * maximum read length.
4077	 */
4078	auiop = NULL;
4079	sizep = NULL;
4080	cnt = 0;
4081	if (data != NULL) {
4082		aiov.iov_base = data;
4083		aiov.iov_len = nbytes;
4084		auio.uio_iov = &aiov;
4085		auio.uio_offset = 0;
4086		if (nbytes > INT_MAX) {
4087			error = EINVAL;
4088			goto done;
4089		}
4090		auio.uio_resid = nbytes;
4091		auio.uio_rw = UIO_READ;
4092		auio.uio_segflg = UIO_USERSPACE;
4093		auio.uio_td = td;
4094		auiop = &auio;
4095		cnt = nbytes;
4096	} else
4097		sizep = &size;
4098
4099#ifdef MAC
4100	error = mac_check_vnode_getextattr(td->td_ucred, vp, attrnamespace,
4101	    attrname, &auio);
4102	if (error)
4103		goto done;
4104#endif
4105
4106	error = VOP_GETEXTATTR(vp, attrnamespace, attrname, auiop, sizep,
4107	    td->td_ucred, td);
4108
4109	if (auiop != NULL) {
4110		cnt -= auio.uio_resid;
4111		td->td_retval[0] = cnt;
4112	} else
4113		td->td_retval[0] = size;
4114
4115done:
4116	VOP_UNLOCK(vp, 0, td);
4117	return (error);
4118}
4119
4120int
4121extattr_get_fd(td, uap)
4122	struct thread *td;
4123	struct extattr_get_fd_args /* {
4124		int fd;
4125		int attrnamespace;
4126		const char *attrname;
4127		void *data;
4128		size_t nbytes;
4129	} */ *uap;
4130{
4131	struct file *fp;
4132	char attrname[EXTATTR_MAXNAMELEN];
4133	int error;
4134
4135	error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
4136	if (error)
4137		return (error);
4138
4139	error = getvnode(td->td_proc->p_fd, uap->fd, &fp);
4140	if (error)
4141		return (error);
4142
4143	error = extattr_get_vp(fp->f_data, uap->attrnamespace,
4144	    attrname, uap->data, uap->nbytes, td);
4145
4146	fdrop(fp, td);
4147	return (error);
4148}
4149
4150int
4151extattr_get_file(td, uap)
4152	struct thread *td;
4153	struct extattr_get_file_args /* {
4154		const char *path;
4155		int attrnamespace;
4156		const char *attrname;
4157		void *data;
4158		size_t nbytes;
4159	} */ *uap;
4160{
4161	struct nameidata nd;
4162	char attrname[EXTATTR_MAXNAMELEN];
4163	int error;
4164
4165	error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
4166	if (error)
4167		return (error);
4168
4169	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
4170	error = namei(&nd);
4171	if (error)
4172		return (error);
4173	NDFREE(&nd, NDF_ONLY_PNBUF);
4174
4175	error = extattr_get_vp(nd.ni_vp, uap->attrnamespace, attrname,
4176	    uap->data, uap->nbytes, td);
4177
4178	vrele(nd.ni_vp);
4179	return (error);
4180}
4181
4182int
4183extattr_get_link(td, uap)
4184	struct thread *td;
4185	struct extattr_get_link_args /* {
4186		const char *path;
4187		int attrnamespace;
4188		const char *attrname;
4189		void *data;
4190		size_t nbytes;
4191	} */ *uap;
4192{
4193	struct nameidata nd;
4194	char attrname[EXTATTR_MAXNAMELEN];
4195	int error;
4196
4197	error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
4198	if (error)
4199		return (error);
4200
4201	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, td);
4202	error = namei(&nd);
4203	if (error)
4204		return (error);
4205	NDFREE(&nd, NDF_ONLY_PNBUF);
4206
4207	error = extattr_get_vp(nd.ni_vp, uap->attrnamespace, attrname,
4208	    uap->data, uap->nbytes, td);
4209
4210	vrele(nd.ni_vp);
4211	return (error);
4212}
4213
4214/*
4215 * extattr_delete_vp(): Delete a named extended attribute on a file or
4216 *                      directory
4217 *
4218 * Arguments: unlocked vnode "vp", attribute namespace "attrnamespace",
4219 *            kernelspace string pointer "attrname", proc "p"
4220 * Returns: 0 on success, an error number otherwise
4221 * Locks: none
4222 * References: vp must be a valid reference for the duration of the call
4223 */
4224static int
4225extattr_delete_vp(struct vnode *vp, int attrnamespace, const char *attrname,
4226    struct thread *td)
4227{
4228	struct mount *mp;
4229	int error;
4230
4231	error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
4232	if (error)
4233		return (error);
4234	VOP_LEASE(vp, td, td->td_ucred, LEASE_WRITE);
4235	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
4236
4237#ifdef MAC
4238	error = mac_check_vnode_setextattr(td->td_ucred, vp, attrnamespace,
4239	    attrname, NULL);
4240	if (error)
4241		goto done;
4242#endif
4243
4244	error = VOP_SETEXTATTR(vp, attrnamespace, attrname, NULL, td->td_ucred,
4245	    td);
4246#ifdef MAC
4247done:
4248#endif
4249	VOP_UNLOCK(vp, 0, td);
4250	vn_finished_write(mp);
4251	return (error);
4252}
4253
4254int
4255extattr_delete_fd(td, uap)
4256	struct thread *td;
4257	struct extattr_delete_fd_args /* {
4258		int fd;
4259		int attrnamespace;
4260		const char *attrname;
4261	} */ *uap;
4262{
4263	struct file *fp;
4264	struct vnode *vp;
4265	char attrname[EXTATTR_MAXNAMELEN];
4266	int error;
4267
4268	error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
4269	if (error)
4270		return (error);
4271
4272	error = getvnode(td->td_proc->p_fd, uap->fd, &fp);
4273	if (error)
4274		return (error);
4275	vp = fp->f_data;
4276
4277	error = extattr_delete_vp(vp, uap->attrnamespace, attrname, td);
4278	fdrop(fp, td);
4279	return (error);
4280}
4281
4282int
4283extattr_delete_file(td, uap)
4284	struct thread *td;
4285	struct extattr_delete_file_args /* {
4286		const char *path;
4287		int attrnamespace;
4288		const char *attrname;
4289	} */ *uap;
4290{
4291	struct nameidata nd;
4292	char attrname[EXTATTR_MAXNAMELEN];
4293	int error;
4294
4295	error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
4296	if (error)
4297		return(error);
4298
4299	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
4300	error = namei(&nd);
4301	if (error)
4302		return(error);
4303	NDFREE(&nd, NDF_ONLY_PNBUF);
4304
4305	error = extattr_delete_vp(nd.ni_vp, uap->attrnamespace, attrname, td);
4306	vrele(nd.ni_vp);
4307	return(error);
4308}
4309
4310int
4311extattr_delete_link(td, uap)
4312	struct thread *td;
4313	struct extattr_delete_link_args /* {
4314		const char *path;
4315		int attrnamespace;
4316		const char *attrname;
4317	} */ *uap;
4318{
4319	struct nameidata nd;
4320	char attrname[EXTATTR_MAXNAMELEN];
4321	int error;
4322
4323	error = copyinstr(uap->attrname, attrname, EXTATTR_MAXNAMELEN, NULL);
4324	if (error)
4325		return(error);
4326
4327	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, td);
4328	error = namei(&nd);
4329	if (error)
4330		return(error);
4331	NDFREE(&nd, NDF_ONLY_PNBUF);
4332
4333	error = extattr_delete_vp(nd.ni_vp, uap->attrnamespace, attrname, td);
4334	vrele(nd.ni_vp);
4335	return(error);
4336}
4337
4338/*-
4339 * Retrieve a list of extended attributes on a file or directory.
4340 *
4341 * Arguments: unlocked vnode "vp", attribute namespace 'attrnamespace",
4342 *            userspace buffer pointer "data", buffer length "nbytes",
4343 *            thread "td".
4344 * Returns: 0 on success, an error number otherwise
4345 * Locks: none
4346 * References: vp must be a valid reference for the duration of the call
4347 */
4348static int
4349extattr_list_vp(struct vnode *vp, int attrnamespace, void *data,
4350    size_t nbytes, struct thread *td)
4351{
4352	struct uio auio, *auiop;
4353	size_t size, *sizep;
4354	struct iovec aiov;
4355	ssize_t cnt;
4356	int error;
4357
4358	VOP_LEASE(vp, td, td->td_ucred, LEASE_READ);
4359	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
4360
4361	auiop = NULL;
4362	sizep = NULL;
4363	cnt = 0;
4364	if (data != NULL) {
4365		aiov.iov_base = data;
4366		aiov.iov_len = nbytes;
4367		auio.uio_iov = &aiov;
4368		auio.uio_offset = 0;
4369		if (nbytes > INT_MAX) {
4370			error = EINVAL;
4371			goto done;
4372		}
4373		auio.uio_resid = nbytes;
4374		auio.uio_rw = UIO_READ;
4375		auio.uio_segflg = UIO_USERSPACE;
4376		auio.uio_td = td;
4377		auiop = &auio;
4378		cnt = nbytes;
4379	} else
4380		sizep = &size;
4381
4382#ifdef MAC
4383	error = mac_check_vnode_getextattr(td->td_ucred, vp, attrnamespace,
4384	    "", &auio);
4385	if (error)
4386		goto done;
4387#endif
4388
4389	error = VOP_LISTEXTATTR(vp, attrnamespace, auiop, sizep,
4390	    td->td_ucred, td);
4391
4392	if (auiop != NULL) {
4393		cnt -= auio.uio_resid;
4394		td->td_retval[0] = cnt;
4395	} else
4396		td->td_retval[0] = size;
4397
4398done:
4399	VOP_UNLOCK(vp, 0, td);
4400	return (error);
4401}
4402
4403
4404int
4405extattr_list_fd(td, uap)
4406	struct thread *td;
4407	struct extattr_list_fd_args /* {
4408		int fd;
4409		int attrnamespace;
4410		void *data;
4411		size_t nbytes;
4412	} */ *uap;
4413{
4414	struct file *fp;
4415	int error;
4416
4417	error = getvnode(td->td_proc->p_fd, uap->fd, &fp);
4418	if (error)
4419		return (error);
4420
4421	error = extattr_list_vp(fp->f_data, uap->attrnamespace, uap->data,
4422	    uap->nbytes, td);
4423
4424	fdrop(fp, td);
4425	return (error);
4426}
4427
4428int
4429extattr_list_file(td, uap)
4430	struct thread*td;
4431	struct extattr_list_file_args /* {
4432		const char *path;
4433		int attrnamespace;
4434		void *data;
4435		size_t nbytes;
4436	} */ *uap;
4437{
4438	struct nameidata nd;
4439	int error;
4440
4441	NDINIT(&nd, LOOKUP, FOLLOW, UIO_USERSPACE, uap->path, td);
4442	error = namei(&nd);
4443	if (error)
4444		return (error);
4445	NDFREE(&nd, NDF_ONLY_PNBUF);
4446
4447	error = extattr_list_vp(nd.ni_vp, uap->attrnamespace, uap->data,
4448	    uap->nbytes, td);
4449
4450	vrele(nd.ni_vp);
4451	return (error);
4452}
4453
4454int
4455extattr_list_link(td, uap)
4456	struct thread*td;
4457	struct extattr_list_link_args /* {
4458		const char *path;
4459		int attrnamespace;
4460		void *data;
4461		size_t nbytes;
4462	} */ *uap;
4463{
4464	struct nameidata nd;
4465	int error;
4466
4467	NDINIT(&nd, LOOKUP, NOFOLLOW, UIO_USERSPACE, uap->path, td);
4468	error = namei(&nd);
4469	if (error)
4470		return (error);
4471	NDFREE(&nd, NDF_ONLY_PNBUF);
4472
4473	error = extattr_list_vp(nd.ni_vp, uap->attrnamespace, uap->data,
4474	    uap->nbytes, td);
4475
4476	vrele(nd.ni_vp);
4477	return (error);
4478}
4479
4480