xref: /minix3/sys/ufs/lfs/ulfs_vnops.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: ulfs_vnops.c,v 1.34 2015/09/21 01:24:23 dholland Exp $	*/
284d9c625SLionel Sambuc /*  from NetBSD: ufs_vnops.c,v 1.213 2013/06/08 05:47:02 kardel Exp  */
384d9c625SLionel Sambuc 
484d9c625SLionel Sambuc /*-
584d9c625SLionel Sambuc  * Copyright (c) 2008 The NetBSD Foundation, Inc.
684d9c625SLionel Sambuc  * All rights reserved.
784d9c625SLionel Sambuc  *
884d9c625SLionel Sambuc  * This code is derived from software contributed to The NetBSD Foundation
984d9c625SLionel Sambuc  * by Wasabi Systems, Inc.
1084d9c625SLionel Sambuc  *
1184d9c625SLionel Sambuc  * Redistribution and use in source and binary forms, with or without
1284d9c625SLionel Sambuc  * modification, are permitted provided that the following conditions
1384d9c625SLionel Sambuc  * are met:
1484d9c625SLionel Sambuc  * 1. Redistributions of source code must retain the above copyright
1584d9c625SLionel Sambuc  *    notice, this list of conditions and the following disclaimer.
1684d9c625SLionel Sambuc  * 2. Redistributions in binary form must reproduce the above copyright
1784d9c625SLionel Sambuc  *    notice, this list of conditions and the following disclaimer in the
1884d9c625SLionel Sambuc  *    documentation and/or other materials provided with the distribution.
1984d9c625SLionel Sambuc  *
2084d9c625SLionel Sambuc  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
2184d9c625SLionel Sambuc  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
2284d9c625SLionel Sambuc  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2384d9c625SLionel Sambuc  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
2484d9c625SLionel Sambuc  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2584d9c625SLionel Sambuc  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2684d9c625SLionel Sambuc  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2784d9c625SLionel Sambuc  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2884d9c625SLionel Sambuc  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2984d9c625SLionel Sambuc  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
3084d9c625SLionel Sambuc  * POSSIBILITY OF SUCH DAMAGE.
3184d9c625SLionel Sambuc  */
3284d9c625SLionel Sambuc 
3384d9c625SLionel Sambuc /*
3484d9c625SLionel Sambuc  * Copyright (c) 1982, 1986, 1989, 1993, 1995
3584d9c625SLionel Sambuc  *	The Regents of the University of California.  All rights reserved.
3684d9c625SLionel Sambuc  * (c) UNIX System Laboratories, Inc.
3784d9c625SLionel Sambuc  * All or some portions of this file are derived from material licensed
3884d9c625SLionel Sambuc  * to the University of California by American Telephone and Telegraph
3984d9c625SLionel Sambuc  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
4084d9c625SLionel Sambuc  * the permission of UNIX System Laboratories, Inc.
4184d9c625SLionel Sambuc  *
4284d9c625SLionel Sambuc  * Redistribution and use in source and binary forms, with or without
4384d9c625SLionel Sambuc  * modification, are permitted provided that the following conditions
4484d9c625SLionel Sambuc  * are met:
4584d9c625SLionel Sambuc  * 1. Redistributions of source code must retain the above copyright
4684d9c625SLionel Sambuc  *    notice, this list of conditions and the following disclaimer.
4784d9c625SLionel Sambuc  * 2. Redistributions in binary form must reproduce the above copyright
4884d9c625SLionel Sambuc  *    notice, this list of conditions and the following disclaimer in the
4984d9c625SLionel Sambuc  *    documentation and/or other materials provided with the distribution.
5084d9c625SLionel Sambuc  * 3. Neither the name of the University nor the names of its contributors
5184d9c625SLionel Sambuc  *    may be used to endorse or promote products derived from this software
5284d9c625SLionel Sambuc  *    without specific prior written permission.
5384d9c625SLionel Sambuc  *
5484d9c625SLionel Sambuc  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
5584d9c625SLionel Sambuc  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
5684d9c625SLionel Sambuc  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5784d9c625SLionel Sambuc  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
5884d9c625SLionel Sambuc  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5984d9c625SLionel Sambuc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
6084d9c625SLionel Sambuc  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
6184d9c625SLionel Sambuc  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
6284d9c625SLionel Sambuc  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
6384d9c625SLionel Sambuc  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
6484d9c625SLionel Sambuc  * SUCH DAMAGE.
6584d9c625SLionel Sambuc  *
6684d9c625SLionel Sambuc  *	@(#)ufs_vnops.c	8.28 (Berkeley) 7/31/95
6784d9c625SLionel Sambuc  */
6884d9c625SLionel Sambuc 
6984d9c625SLionel Sambuc #include <sys/cdefs.h>
70*0a6a1f1dSLionel Sambuc __KERNEL_RCSID(0, "$NetBSD: ulfs_vnops.c,v 1.34 2015/09/21 01:24:23 dholland Exp $");
7184d9c625SLionel Sambuc 
7284d9c625SLionel Sambuc #if defined(_KERNEL_OPT)
7384d9c625SLionel Sambuc #include "opt_lfs.h"
7484d9c625SLionel Sambuc #include "opt_quota.h"
7584d9c625SLionel Sambuc #endif
7684d9c625SLionel Sambuc 
7784d9c625SLionel Sambuc #include <sys/param.h>
7884d9c625SLionel Sambuc #include <sys/systm.h>
7984d9c625SLionel Sambuc #include <sys/namei.h>
8084d9c625SLionel Sambuc #include <sys/resourcevar.h>
8184d9c625SLionel Sambuc #include <sys/kernel.h>
8284d9c625SLionel Sambuc #include <sys/file.h>
8384d9c625SLionel Sambuc #include <sys/stat.h>
8484d9c625SLionel Sambuc #include <sys/buf.h>
8584d9c625SLionel Sambuc #include <sys/proc.h>
8684d9c625SLionel Sambuc #include <sys/mount.h>
8784d9c625SLionel Sambuc #include <sys/vnode.h>
8884d9c625SLionel Sambuc #include <sys/kmem.h>
8984d9c625SLionel Sambuc #include <sys/malloc.h>
9084d9c625SLionel Sambuc #include <sys/dirent.h>
9184d9c625SLionel Sambuc #include <sys/lockf.h>
9284d9c625SLionel Sambuc #include <sys/kauth.h>
9384d9c625SLionel Sambuc #include <sys/wapbl.h>
9484d9c625SLionel Sambuc #include <sys/fstrans.h>
9584d9c625SLionel Sambuc 
9684d9c625SLionel Sambuc #include <miscfs/specfs/specdev.h>
9784d9c625SLionel Sambuc #include <miscfs/fifofs/fifo.h>
9884d9c625SLionel Sambuc #include <miscfs/genfs/genfs.h>
9984d9c625SLionel Sambuc 
100*0a6a1f1dSLionel Sambuc #include <ufs/lfs/lfs_extern.h>
101*0a6a1f1dSLionel Sambuc #include <ufs/lfs/lfs.h>
102*0a6a1f1dSLionel Sambuc #include <ufs/lfs/lfs_accessors.h>
103*0a6a1f1dSLionel Sambuc 
10484d9c625SLionel Sambuc #include <ufs/lfs/ulfs_inode.h>
10584d9c625SLionel Sambuc #include <ufs/lfs/ulfsmount.h>
10684d9c625SLionel Sambuc #include <ufs/lfs/ulfs_bswap.h>
10784d9c625SLionel Sambuc #include <ufs/lfs/ulfs_extern.h>
10884d9c625SLionel Sambuc #ifdef LFS_DIRHASH
10984d9c625SLionel Sambuc #include <ufs/lfs/ulfs_dirhash.h>
11084d9c625SLionel Sambuc #endif
11184d9c625SLionel Sambuc 
11284d9c625SLionel Sambuc #include <uvm/uvm.h>
11384d9c625SLionel Sambuc 
11484d9c625SLionel Sambuc static int ulfs_chmod(struct vnode *, int, kauth_cred_t, struct lwp *);
11584d9c625SLionel Sambuc static int ulfs_chown(struct vnode *, uid_t, gid_t, kauth_cred_t,
11684d9c625SLionel Sambuc     struct lwp *);
11784d9c625SLionel Sambuc 
11884d9c625SLionel Sambuc /*
11984d9c625SLionel Sambuc  * Open called.
12084d9c625SLionel Sambuc  *
12184d9c625SLionel Sambuc  * Nothing to do.
12284d9c625SLionel Sambuc  */
12384d9c625SLionel Sambuc /* ARGSUSED */
12484d9c625SLionel Sambuc int
ulfs_open(void * v)12584d9c625SLionel Sambuc ulfs_open(void *v)
12684d9c625SLionel Sambuc {
12784d9c625SLionel Sambuc 	struct vop_open_args /* {
12884d9c625SLionel Sambuc 		struct vnode	*a_vp;
12984d9c625SLionel Sambuc 		int		a_mode;
13084d9c625SLionel Sambuc 		kauth_cred_t	a_cred;
13184d9c625SLionel Sambuc 	} */ *ap = v;
13284d9c625SLionel Sambuc 
13384d9c625SLionel Sambuc 	/*
13484d9c625SLionel Sambuc 	 * Files marked append-only must be opened for appending.
13584d9c625SLionel Sambuc 	 */
13684d9c625SLionel Sambuc 	if ((VTOI(ap->a_vp)->i_flags & APPEND) &&
13784d9c625SLionel Sambuc 	    (ap->a_mode & (FWRITE | O_APPEND)) == FWRITE)
13884d9c625SLionel Sambuc 		return (EPERM);
13984d9c625SLionel Sambuc 	return (0);
14084d9c625SLionel Sambuc }
14184d9c625SLionel Sambuc 
14284d9c625SLionel Sambuc static int
ulfs_check_possible(struct vnode * vp,struct inode * ip,mode_t mode,kauth_cred_t cred)14384d9c625SLionel Sambuc ulfs_check_possible(struct vnode *vp, struct inode *ip, mode_t mode,
14484d9c625SLionel Sambuc     kauth_cred_t cred)
14584d9c625SLionel Sambuc {
14684d9c625SLionel Sambuc #if defined(LFS_QUOTA) || defined(LFS_QUOTA2)
14784d9c625SLionel Sambuc 	int error;
14884d9c625SLionel Sambuc #endif
14984d9c625SLionel Sambuc 
15084d9c625SLionel Sambuc 	/*
15184d9c625SLionel Sambuc 	 * Disallow write attempts on read-only file systems;
15284d9c625SLionel Sambuc 	 * unless the file is a socket, fifo, or a block or
15384d9c625SLionel Sambuc 	 * character device resident on the file system.
15484d9c625SLionel Sambuc 	 */
15584d9c625SLionel Sambuc 	if (mode & VWRITE) {
15684d9c625SLionel Sambuc 		switch (vp->v_type) {
15784d9c625SLionel Sambuc 		case VDIR:
15884d9c625SLionel Sambuc 		case VLNK:
15984d9c625SLionel Sambuc 		case VREG:
16084d9c625SLionel Sambuc 			if (vp->v_mount->mnt_flag & MNT_RDONLY)
16184d9c625SLionel Sambuc 				return (EROFS);
16284d9c625SLionel Sambuc #if defined(LFS_QUOTA) || defined(LFS_QUOTA2)
16384d9c625SLionel Sambuc 			fstrans_start(vp->v_mount, FSTRANS_SHARED);
16484d9c625SLionel Sambuc 			error = lfs_chkdq(ip, 0, cred, 0);
16584d9c625SLionel Sambuc 			fstrans_done(vp->v_mount);
16684d9c625SLionel Sambuc 			if (error != 0)
16784d9c625SLionel Sambuc 				return error;
16884d9c625SLionel Sambuc #endif
16984d9c625SLionel Sambuc 			break;
17084d9c625SLionel Sambuc 		case VBAD:
17184d9c625SLionel Sambuc 		case VBLK:
17284d9c625SLionel Sambuc 		case VCHR:
17384d9c625SLionel Sambuc 		case VSOCK:
17484d9c625SLionel Sambuc 		case VFIFO:
17584d9c625SLionel Sambuc 		case VNON:
17684d9c625SLionel Sambuc 		default:
17784d9c625SLionel Sambuc 			break;
17884d9c625SLionel Sambuc 		}
17984d9c625SLionel Sambuc 	}
18084d9c625SLionel Sambuc 
18184d9c625SLionel Sambuc 	/* If it is a snapshot, nobody gets access to it. */
18284d9c625SLionel Sambuc 	if ((ip->i_flags & SF_SNAPSHOT))
18384d9c625SLionel Sambuc 		return (EPERM);
18484d9c625SLionel Sambuc 	/* If immutable bit set, nobody gets to write it. */
18584d9c625SLionel Sambuc 	if ((mode & VWRITE) && (ip->i_flags & IMMUTABLE))
18684d9c625SLionel Sambuc 		return (EPERM);
18784d9c625SLionel Sambuc 
18884d9c625SLionel Sambuc 	return 0;
18984d9c625SLionel Sambuc }
19084d9c625SLionel Sambuc 
19184d9c625SLionel Sambuc static int
ulfs_check_permitted(struct vnode * vp,struct inode * ip,mode_t mode,kauth_cred_t cred)19284d9c625SLionel Sambuc ulfs_check_permitted(struct vnode *vp, struct inode *ip, mode_t mode,
19384d9c625SLionel Sambuc     kauth_cred_t cred)
19484d9c625SLionel Sambuc {
19584d9c625SLionel Sambuc 
19684d9c625SLionel Sambuc 	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(mode, vp->v_type,
19784d9c625SLionel Sambuc 	    ip->i_mode & ALLPERMS), vp, NULL, genfs_can_access(vp->v_type,
19884d9c625SLionel Sambuc 	    ip->i_mode & ALLPERMS, ip->i_uid, ip->i_gid, mode, cred));
19984d9c625SLionel Sambuc }
20084d9c625SLionel Sambuc 
20184d9c625SLionel Sambuc int
ulfs_access(void * v)20284d9c625SLionel Sambuc ulfs_access(void *v)
20384d9c625SLionel Sambuc {
20484d9c625SLionel Sambuc 	struct vop_access_args /* {
20584d9c625SLionel Sambuc 		struct vnode	*a_vp;
20684d9c625SLionel Sambuc 		int		a_mode;
20784d9c625SLionel Sambuc 		kauth_cred_t	a_cred;
20884d9c625SLionel Sambuc 	} */ *ap = v;
20984d9c625SLionel Sambuc 	struct vnode	*vp;
21084d9c625SLionel Sambuc 	struct inode	*ip;
21184d9c625SLionel Sambuc 	mode_t		mode;
21284d9c625SLionel Sambuc 	int		error;
21384d9c625SLionel Sambuc 
21484d9c625SLionel Sambuc 	vp = ap->a_vp;
21584d9c625SLionel Sambuc 	ip = VTOI(vp);
21684d9c625SLionel Sambuc 	mode = ap->a_mode;
21784d9c625SLionel Sambuc 
21884d9c625SLionel Sambuc 	error = ulfs_check_possible(vp, ip, mode, ap->a_cred);
21984d9c625SLionel Sambuc 	if (error)
22084d9c625SLionel Sambuc 		return error;
22184d9c625SLionel Sambuc 
22284d9c625SLionel Sambuc 	error = ulfs_check_permitted(vp, ip, mode, ap->a_cred);
22384d9c625SLionel Sambuc 
22484d9c625SLionel Sambuc 	return error;
22584d9c625SLionel Sambuc }
22684d9c625SLionel Sambuc 
22784d9c625SLionel Sambuc /*
22884d9c625SLionel Sambuc  * Set attribute vnode op. called from several syscalls
22984d9c625SLionel Sambuc  */
23084d9c625SLionel Sambuc int
ulfs_setattr(void * v)23184d9c625SLionel Sambuc ulfs_setattr(void *v)
23284d9c625SLionel Sambuc {
23384d9c625SLionel Sambuc 	struct vop_setattr_args /* {
23484d9c625SLionel Sambuc 		struct vnode	*a_vp;
23584d9c625SLionel Sambuc 		struct vattr	*a_vap;
23684d9c625SLionel Sambuc 		kauth_cred_t	a_cred;
23784d9c625SLionel Sambuc 	} */ *ap = v;
23884d9c625SLionel Sambuc 	struct vattr	*vap;
23984d9c625SLionel Sambuc 	struct vnode	*vp;
24084d9c625SLionel Sambuc 	struct inode	*ip;
241*0a6a1f1dSLionel Sambuc 	struct lfs	*fs;
24284d9c625SLionel Sambuc 	kauth_cred_t	cred;
24384d9c625SLionel Sambuc 	struct lwp	*l;
24484d9c625SLionel Sambuc 	int		error;
24584d9c625SLionel Sambuc 	kauth_action_t	action;
24684d9c625SLionel Sambuc 	bool		changing_sysflags;
24784d9c625SLionel Sambuc 
24884d9c625SLionel Sambuc 	vap = ap->a_vap;
24984d9c625SLionel Sambuc 	vp = ap->a_vp;
25084d9c625SLionel Sambuc 	ip = VTOI(vp);
251*0a6a1f1dSLionel Sambuc 	fs = ip->i_lfs;
25284d9c625SLionel Sambuc 	cred = ap->a_cred;
25384d9c625SLionel Sambuc 	l = curlwp;
25484d9c625SLionel Sambuc 	action = KAUTH_VNODE_WRITE_FLAGS;
25584d9c625SLionel Sambuc 	changing_sysflags = false;
25684d9c625SLionel Sambuc 
25784d9c625SLionel Sambuc 	/*
25884d9c625SLionel Sambuc 	 * Check for unsettable attributes.
25984d9c625SLionel Sambuc 	 */
26084d9c625SLionel Sambuc 	if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
26184d9c625SLionel Sambuc 	    (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
26284d9c625SLionel Sambuc 	    (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
26384d9c625SLionel Sambuc 	    ((int)vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
26484d9c625SLionel Sambuc 		return (EINVAL);
26584d9c625SLionel Sambuc 	}
26684d9c625SLionel Sambuc 
26784d9c625SLionel Sambuc 	fstrans_start(vp->v_mount, FSTRANS_SHARED);
26884d9c625SLionel Sambuc 
26984d9c625SLionel Sambuc 	if (vap->va_flags != VNOVAL) {
27084d9c625SLionel Sambuc 		if (vp->v_mount->mnt_flag & MNT_RDONLY) {
27184d9c625SLionel Sambuc 			error = EROFS;
27284d9c625SLionel Sambuc 			goto out;
27384d9c625SLionel Sambuc 		}
27484d9c625SLionel Sambuc 
27584d9c625SLionel Sambuc 		/* Snapshot flag cannot be set or cleared */
27684d9c625SLionel Sambuc 		if ((vap->va_flags & (SF_SNAPSHOT | SF_SNAPINVAL)) !=
27784d9c625SLionel Sambuc 		    (ip->i_flags & (SF_SNAPSHOT | SF_SNAPINVAL))) {
27884d9c625SLionel Sambuc 			error = EPERM;
27984d9c625SLionel Sambuc 			goto out;
28084d9c625SLionel Sambuc 		}
28184d9c625SLionel Sambuc 
28284d9c625SLionel Sambuc 		if (ip->i_flags & (SF_IMMUTABLE | SF_APPEND)) {
28384d9c625SLionel Sambuc 			action |= KAUTH_VNODE_HAS_SYSFLAGS;
28484d9c625SLionel Sambuc 		}
28584d9c625SLionel Sambuc 
28684d9c625SLionel Sambuc 		if ((vap->va_flags & SF_SETTABLE) != (ip->i_flags & SF_SETTABLE)) {
28784d9c625SLionel Sambuc 			action |= KAUTH_VNODE_WRITE_SYSFLAGS;
28884d9c625SLionel Sambuc 			changing_sysflags = true;
28984d9c625SLionel Sambuc 		}
29084d9c625SLionel Sambuc 
29184d9c625SLionel Sambuc 		error = kauth_authorize_vnode(cred, action, vp, NULL,
29284d9c625SLionel Sambuc 		    genfs_can_chflags(cred, vp->v_type, ip->i_uid,
29384d9c625SLionel Sambuc 		    changing_sysflags));
29484d9c625SLionel Sambuc 		if (error)
29584d9c625SLionel Sambuc 			goto out;
29684d9c625SLionel Sambuc 
29784d9c625SLionel Sambuc 		if (changing_sysflags) {
29884d9c625SLionel Sambuc 			ip->i_flags = vap->va_flags;
29984d9c625SLionel Sambuc 			DIP_ASSIGN(ip, flags, ip->i_flags);
30084d9c625SLionel Sambuc 		} else {
30184d9c625SLionel Sambuc 			ip->i_flags &= SF_SETTABLE;
30284d9c625SLionel Sambuc 			ip->i_flags |= (vap->va_flags & UF_SETTABLE);
30384d9c625SLionel Sambuc 			DIP_ASSIGN(ip, flags, ip->i_flags);
30484d9c625SLionel Sambuc 		}
30584d9c625SLionel Sambuc 		ip->i_flag |= IN_CHANGE;
30684d9c625SLionel Sambuc 		if (vap->va_flags & (IMMUTABLE | APPEND)) {
30784d9c625SLionel Sambuc 			error = 0;
30884d9c625SLionel Sambuc 			goto out;
30984d9c625SLionel Sambuc 		}
31084d9c625SLionel Sambuc 	}
31184d9c625SLionel Sambuc 	if (ip->i_flags & (IMMUTABLE | APPEND)) {
31284d9c625SLionel Sambuc 		error = EPERM;
31384d9c625SLionel Sambuc 		goto out;
31484d9c625SLionel Sambuc 	}
31584d9c625SLionel Sambuc 	/*
31684d9c625SLionel Sambuc 	 * Go through the fields and update iff not VNOVAL.
31784d9c625SLionel Sambuc 	 */
31884d9c625SLionel Sambuc 	if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
31984d9c625SLionel Sambuc 		if (vp->v_mount->mnt_flag & MNT_RDONLY) {
32084d9c625SLionel Sambuc 			error = EROFS;
32184d9c625SLionel Sambuc 			goto out;
32284d9c625SLionel Sambuc 		}
32384d9c625SLionel Sambuc 		error = ulfs_chown(vp, vap->va_uid, vap->va_gid, cred, l);
32484d9c625SLionel Sambuc 		if (error)
32584d9c625SLionel Sambuc 			goto out;
32684d9c625SLionel Sambuc 	}
32784d9c625SLionel Sambuc 	if (vap->va_size != VNOVAL) {
32884d9c625SLionel Sambuc 		/*
32984d9c625SLionel Sambuc 		 * Disallow write attempts on read-only file systems;
33084d9c625SLionel Sambuc 		 * unless the file is a socket, fifo, or a block or
33184d9c625SLionel Sambuc 		 * character device resident on the file system.
33284d9c625SLionel Sambuc 		 */
33384d9c625SLionel Sambuc 		switch (vp->v_type) {
33484d9c625SLionel Sambuc 		case VDIR:
33584d9c625SLionel Sambuc 			error = EISDIR;
33684d9c625SLionel Sambuc 			goto out;
33784d9c625SLionel Sambuc 		case VCHR:
33884d9c625SLionel Sambuc 		case VBLK:
33984d9c625SLionel Sambuc 		case VFIFO:
34084d9c625SLionel Sambuc 			break;
34184d9c625SLionel Sambuc 		case VREG:
34284d9c625SLionel Sambuc 			if (vp->v_mount->mnt_flag & MNT_RDONLY) {
34384d9c625SLionel Sambuc 				error = EROFS;
34484d9c625SLionel Sambuc 				goto out;
34584d9c625SLionel Sambuc 			}
34684d9c625SLionel Sambuc 			if ((ip->i_flags & SF_SNAPSHOT) != 0) {
34784d9c625SLionel Sambuc 				error = EPERM;
34884d9c625SLionel Sambuc 				goto out;
34984d9c625SLionel Sambuc 			}
35084d9c625SLionel Sambuc 			error = lfs_truncate(vp, vap->va_size, 0, cred);
35184d9c625SLionel Sambuc 			if (error)
35284d9c625SLionel Sambuc 				goto out;
35384d9c625SLionel Sambuc 			break;
35484d9c625SLionel Sambuc 		default:
35584d9c625SLionel Sambuc 			error = EOPNOTSUPP;
35684d9c625SLionel Sambuc 			goto out;
35784d9c625SLionel Sambuc 		}
35884d9c625SLionel Sambuc 	}
35984d9c625SLionel Sambuc 	ip = VTOI(vp);
36084d9c625SLionel Sambuc 	if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL ||
36184d9c625SLionel Sambuc 	    vap->va_birthtime.tv_sec != VNOVAL) {
36284d9c625SLionel Sambuc 		if (vp->v_mount->mnt_flag & MNT_RDONLY) {
36384d9c625SLionel Sambuc 			error = EROFS;
36484d9c625SLionel Sambuc 			goto out;
36584d9c625SLionel Sambuc 		}
36684d9c625SLionel Sambuc 		if ((ip->i_flags & SF_SNAPSHOT) != 0) {
36784d9c625SLionel Sambuc 			error = EPERM;
36884d9c625SLionel Sambuc 			goto out;
36984d9c625SLionel Sambuc 		}
37084d9c625SLionel Sambuc 		error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_TIMES, vp,
37184d9c625SLionel Sambuc 		    NULL, genfs_can_chtimes(vp, vap->va_vaflags, ip->i_uid, cred));
37284d9c625SLionel Sambuc 		if (error)
37384d9c625SLionel Sambuc 			goto out;
37484d9c625SLionel Sambuc 		if (vap->va_atime.tv_sec != VNOVAL)
37584d9c625SLionel Sambuc 			if (!(vp->v_mount->mnt_flag & MNT_NOATIME))
37684d9c625SLionel Sambuc 				ip->i_flag |= IN_ACCESS;
37784d9c625SLionel Sambuc 		if (vap->va_mtime.tv_sec != VNOVAL) {
37884d9c625SLionel Sambuc 			ip->i_flag |= IN_CHANGE | IN_UPDATE;
37984d9c625SLionel Sambuc 			if (vp->v_mount->mnt_flag & MNT_RELATIME)
38084d9c625SLionel Sambuc 				ip->i_flag |= IN_ACCESS;
38184d9c625SLionel Sambuc 		}
382*0a6a1f1dSLionel Sambuc 		if (vap->va_birthtime.tv_sec != VNOVAL) {
383*0a6a1f1dSLionel Sambuc 			lfs_dino_setbirthtime(fs, ip->i_din,
384*0a6a1f1dSLionel Sambuc 					      &vap->va_birthtime);
38584d9c625SLionel Sambuc 		}
38684d9c625SLionel Sambuc 		error = lfs_update(vp, &vap->va_atime, &vap->va_mtime, 0);
38784d9c625SLionel Sambuc 		if (error)
38884d9c625SLionel Sambuc 			goto out;
38984d9c625SLionel Sambuc 	}
39084d9c625SLionel Sambuc 	error = 0;
39184d9c625SLionel Sambuc 	if (vap->va_mode != (mode_t)VNOVAL) {
39284d9c625SLionel Sambuc 		if (vp->v_mount->mnt_flag & MNT_RDONLY) {
39384d9c625SLionel Sambuc 			error = EROFS;
39484d9c625SLionel Sambuc 			goto out;
39584d9c625SLionel Sambuc 		}
39684d9c625SLionel Sambuc 		if ((ip->i_flags & SF_SNAPSHOT) != 0 &&
39784d9c625SLionel Sambuc 		    (vap->va_mode & (S_IXUSR | S_IWUSR | S_IXGRP | S_IWGRP |
39884d9c625SLionel Sambuc 		     S_IXOTH | S_IWOTH))) {
39984d9c625SLionel Sambuc 			error = EPERM;
40084d9c625SLionel Sambuc 			goto out;
40184d9c625SLionel Sambuc 		}
40284d9c625SLionel Sambuc 		error = ulfs_chmod(vp, (int)vap->va_mode, cred, l);
40384d9c625SLionel Sambuc 	}
40484d9c625SLionel Sambuc 	VN_KNOTE(vp, NOTE_ATTRIB);
40584d9c625SLionel Sambuc out:
40684d9c625SLionel Sambuc 	fstrans_done(vp->v_mount);
40784d9c625SLionel Sambuc 	return (error);
40884d9c625SLionel Sambuc }
40984d9c625SLionel Sambuc 
41084d9c625SLionel Sambuc /*
41184d9c625SLionel Sambuc  * Change the mode on a file.
41284d9c625SLionel Sambuc  * Inode must be locked before calling.
41384d9c625SLionel Sambuc  */
41484d9c625SLionel Sambuc static int
ulfs_chmod(struct vnode * vp,int mode,kauth_cred_t cred,struct lwp * l)41584d9c625SLionel Sambuc ulfs_chmod(struct vnode *vp, int mode, kauth_cred_t cred, struct lwp *l)
41684d9c625SLionel Sambuc {
41784d9c625SLionel Sambuc 	struct inode	*ip;
41884d9c625SLionel Sambuc 	int		error;
41984d9c625SLionel Sambuc 
42084d9c625SLionel Sambuc 	ip = VTOI(vp);
42184d9c625SLionel Sambuc 
42284d9c625SLionel Sambuc 	error = kauth_authorize_vnode(cred, KAUTH_VNODE_WRITE_SECURITY, vp,
42384d9c625SLionel Sambuc 	    NULL, genfs_can_chmod(vp->v_type, cred, ip->i_uid, ip->i_gid, mode));
42484d9c625SLionel Sambuc 	if (error)
42584d9c625SLionel Sambuc 		return (error);
42684d9c625SLionel Sambuc 
42784d9c625SLionel Sambuc 	fstrans_start(vp->v_mount, FSTRANS_SHARED);
42884d9c625SLionel Sambuc 	ip->i_mode &= ~ALLPERMS;
42984d9c625SLionel Sambuc 	ip->i_mode |= (mode & ALLPERMS);
43084d9c625SLionel Sambuc 	ip->i_flag |= IN_CHANGE;
43184d9c625SLionel Sambuc 	DIP_ASSIGN(ip, mode, ip->i_mode);
43284d9c625SLionel Sambuc 	fstrans_done(vp->v_mount);
43384d9c625SLionel Sambuc 	return (0);
43484d9c625SLionel Sambuc }
43584d9c625SLionel Sambuc 
43684d9c625SLionel Sambuc /*
43784d9c625SLionel Sambuc  * Perform chown operation on inode ip;
43884d9c625SLionel Sambuc  * inode must be locked prior to call.
43984d9c625SLionel Sambuc  */
44084d9c625SLionel Sambuc static int
ulfs_chown(struct vnode * vp,uid_t uid,gid_t gid,kauth_cred_t cred,struct lwp * l)44184d9c625SLionel Sambuc ulfs_chown(struct vnode *vp, uid_t uid, gid_t gid, kauth_cred_t cred,
44284d9c625SLionel Sambuc     	struct lwp *l)
44384d9c625SLionel Sambuc {
44484d9c625SLionel Sambuc 	struct inode	*ip;
44584d9c625SLionel Sambuc 	int		error = 0;
44684d9c625SLionel Sambuc #if defined(LFS_QUOTA) || defined(LFS_QUOTA2)
44784d9c625SLionel Sambuc 	uid_t		ouid;
44884d9c625SLionel Sambuc 	gid_t		ogid;
44984d9c625SLionel Sambuc 	int64_t		change;
45084d9c625SLionel Sambuc #endif
45184d9c625SLionel Sambuc 	ip = VTOI(vp);
45284d9c625SLionel Sambuc 	error = 0;
45384d9c625SLionel Sambuc 
45484d9c625SLionel Sambuc 	if (uid == (uid_t)VNOVAL)
45584d9c625SLionel Sambuc 		uid = ip->i_uid;
45684d9c625SLionel Sambuc 	if (gid == (gid_t)VNOVAL)
45784d9c625SLionel Sambuc 		gid = ip->i_gid;
45884d9c625SLionel Sambuc 
45984d9c625SLionel Sambuc 	error = kauth_authorize_vnode(cred, KAUTH_VNODE_CHANGE_OWNERSHIP, vp,
46084d9c625SLionel Sambuc 	    NULL, genfs_can_chown(cred, ip->i_uid, ip->i_gid, uid, gid));
46184d9c625SLionel Sambuc 	if (error)
46284d9c625SLionel Sambuc 		return (error);
46384d9c625SLionel Sambuc 
46484d9c625SLionel Sambuc 	fstrans_start(vp->v_mount, FSTRANS_SHARED);
46584d9c625SLionel Sambuc #if defined(LFS_QUOTA) || defined(LFS_QUOTA2)
46684d9c625SLionel Sambuc 	ogid = ip->i_gid;
46784d9c625SLionel Sambuc 	ouid = ip->i_uid;
46884d9c625SLionel Sambuc 	change = DIP(ip, blocks);
46984d9c625SLionel Sambuc 	(void) lfs_chkdq(ip, -change, cred, 0);
47084d9c625SLionel Sambuc 	(void) lfs_chkiq(ip, -1, cred, 0);
47184d9c625SLionel Sambuc #endif
47284d9c625SLionel Sambuc 	ip->i_gid = gid;
47384d9c625SLionel Sambuc 	DIP_ASSIGN(ip, gid, gid);
47484d9c625SLionel Sambuc 	ip->i_uid = uid;
47584d9c625SLionel Sambuc 	DIP_ASSIGN(ip, uid, uid);
47684d9c625SLionel Sambuc #if defined(LFS_QUOTA) || defined(LFS_QUOTA2)
47784d9c625SLionel Sambuc 	if ((error = lfs_chkdq(ip, change, cred, 0)) == 0) {
47884d9c625SLionel Sambuc 		if ((error = lfs_chkiq(ip, 1, cred, 0)) == 0)
47984d9c625SLionel Sambuc 			goto good;
48084d9c625SLionel Sambuc 		else
48184d9c625SLionel Sambuc 			(void) lfs_chkdq(ip, -change, cred, FORCE);
48284d9c625SLionel Sambuc 	}
48384d9c625SLionel Sambuc 	ip->i_gid = ogid;
48484d9c625SLionel Sambuc 	DIP_ASSIGN(ip, gid, ogid);
48584d9c625SLionel Sambuc 	ip->i_uid = ouid;
48684d9c625SLionel Sambuc 	DIP_ASSIGN(ip, uid, ouid);
48784d9c625SLionel Sambuc 	(void) lfs_chkdq(ip, change, cred, FORCE);
48884d9c625SLionel Sambuc 	(void) lfs_chkiq(ip, 1, cred, FORCE);
48984d9c625SLionel Sambuc 	fstrans_done(vp->v_mount);
49084d9c625SLionel Sambuc 	return (error);
49184d9c625SLionel Sambuc  good:
49284d9c625SLionel Sambuc #endif /* LFS_QUOTA || LFS_QUOTA2 */
49384d9c625SLionel Sambuc 	ip->i_flag |= IN_CHANGE;
49484d9c625SLionel Sambuc 	fstrans_done(vp->v_mount);
49584d9c625SLionel Sambuc 	return (0);
49684d9c625SLionel Sambuc }
49784d9c625SLionel Sambuc 
49884d9c625SLionel Sambuc int
ulfs_remove(void * v)49984d9c625SLionel Sambuc ulfs_remove(void *v)
50084d9c625SLionel Sambuc {
50184d9c625SLionel Sambuc 	struct vop_remove_args /* {
50284d9c625SLionel Sambuc 		struct vnode		*a_dvp;
50384d9c625SLionel Sambuc 		struct vnode		*a_vp;
50484d9c625SLionel Sambuc 		struct componentname	*a_cnp;
50584d9c625SLionel Sambuc 	} */ *ap = v;
50684d9c625SLionel Sambuc 	struct vnode	*vp, *dvp;
50784d9c625SLionel Sambuc 	struct inode	*ip;
508*0a6a1f1dSLionel Sambuc 	struct mount	*mp;
50984d9c625SLionel Sambuc 	int		error;
51084d9c625SLionel Sambuc 	struct ulfs_lookup_results *ulr;
51184d9c625SLionel Sambuc 
51284d9c625SLionel Sambuc 	vp = ap->a_vp;
51384d9c625SLionel Sambuc 	dvp = ap->a_dvp;
51484d9c625SLionel Sambuc 	ip = VTOI(vp);
515*0a6a1f1dSLionel Sambuc 	mp = dvp->v_mount;
516*0a6a1f1dSLionel Sambuc 	KASSERT(mp == vp->v_mount); /* XXX Not stable without lock.  */
51784d9c625SLionel Sambuc 
51884d9c625SLionel Sambuc 	/* XXX should handle this material another way */
51984d9c625SLionel Sambuc 	ulr = &VTOI(dvp)->i_crap;
52084d9c625SLionel Sambuc 	ULFS_CHECK_CRAPCOUNTER(VTOI(dvp));
52184d9c625SLionel Sambuc 
522*0a6a1f1dSLionel Sambuc 	fstrans_start(mp, FSTRANS_SHARED);
52384d9c625SLionel Sambuc 	if (vp->v_type == VDIR || (ip->i_flags & (IMMUTABLE | APPEND)) ||
52484d9c625SLionel Sambuc 	    (VTOI(dvp)->i_flags & APPEND))
52584d9c625SLionel Sambuc 		error = EPERM;
52684d9c625SLionel Sambuc 	else {
52784d9c625SLionel Sambuc 		error = ulfs_dirremove(dvp, ulr,
52884d9c625SLionel Sambuc 				      ip, ap->a_cnp->cn_flags, 0);
52984d9c625SLionel Sambuc 	}
53084d9c625SLionel Sambuc 	VN_KNOTE(vp, NOTE_DELETE);
53184d9c625SLionel Sambuc 	VN_KNOTE(dvp, NOTE_WRITE);
53284d9c625SLionel Sambuc 	if (dvp == vp)
53384d9c625SLionel Sambuc 		vrele(vp);
53484d9c625SLionel Sambuc 	else
53584d9c625SLionel Sambuc 		vput(vp);
53684d9c625SLionel Sambuc 	vput(dvp);
537*0a6a1f1dSLionel Sambuc 	fstrans_done(mp);
53884d9c625SLionel Sambuc 	return (error);
53984d9c625SLionel Sambuc }
54084d9c625SLionel Sambuc 
54184d9c625SLionel Sambuc /*
54284d9c625SLionel Sambuc  * ulfs_link: create hard link.
54384d9c625SLionel Sambuc  */
54484d9c625SLionel Sambuc int
ulfs_link(void * v)54584d9c625SLionel Sambuc ulfs_link(void *v)
54684d9c625SLionel Sambuc {
547*0a6a1f1dSLionel Sambuc 	struct vop_link_v2_args /* {
54884d9c625SLionel Sambuc 		struct vnode *a_dvp;
54984d9c625SLionel Sambuc 		struct vnode *a_vp;
55084d9c625SLionel Sambuc 		struct componentname *a_cnp;
55184d9c625SLionel Sambuc 	} */ *ap = v;
55284d9c625SLionel Sambuc 	struct vnode *dvp = ap->a_dvp;
55384d9c625SLionel Sambuc 	struct vnode *vp = ap->a_vp;
55484d9c625SLionel Sambuc 	struct componentname *cnp = ap->a_cnp;
555*0a6a1f1dSLionel Sambuc 	struct mount *mp = dvp->v_mount;
55684d9c625SLionel Sambuc 	struct inode *ip;
55784d9c625SLionel Sambuc 	int error;
55884d9c625SLionel Sambuc 	struct ulfs_lookup_results *ulr;
55984d9c625SLionel Sambuc 
56084d9c625SLionel Sambuc 	KASSERT(dvp != vp);
56184d9c625SLionel Sambuc 	KASSERT(vp->v_type != VDIR);
562*0a6a1f1dSLionel Sambuc 	KASSERT(mp == vp->v_mount); /* XXX Not stable without lock.  */
56384d9c625SLionel Sambuc 
56484d9c625SLionel Sambuc 	/* XXX should handle this material another way */
56584d9c625SLionel Sambuc 	ulr = &VTOI(dvp)->i_crap;
56684d9c625SLionel Sambuc 	ULFS_CHECK_CRAPCOUNTER(VTOI(dvp));
56784d9c625SLionel Sambuc 
568*0a6a1f1dSLionel Sambuc 	fstrans_start(mp, FSTRANS_SHARED);
56984d9c625SLionel Sambuc 	error = vn_lock(vp, LK_EXCLUSIVE);
57084d9c625SLionel Sambuc 	if (error) {
57184d9c625SLionel Sambuc 		VOP_ABORTOP(dvp, cnp);
57284d9c625SLionel Sambuc 		goto out2;
57384d9c625SLionel Sambuc 	}
57484d9c625SLionel Sambuc 	ip = VTOI(vp);
57584d9c625SLionel Sambuc 	if ((nlink_t)ip->i_nlink >= LINK_MAX) {
57684d9c625SLionel Sambuc 		VOP_ABORTOP(dvp, cnp);
57784d9c625SLionel Sambuc 		error = EMLINK;
57884d9c625SLionel Sambuc 		goto out1;
57984d9c625SLionel Sambuc 	}
58084d9c625SLionel Sambuc 	if (ip->i_flags & (IMMUTABLE | APPEND)) {
58184d9c625SLionel Sambuc 		VOP_ABORTOP(dvp, cnp);
58284d9c625SLionel Sambuc 		error = EPERM;
58384d9c625SLionel Sambuc 		goto out1;
58484d9c625SLionel Sambuc 	}
58584d9c625SLionel Sambuc 	ip->i_nlink++;
58684d9c625SLionel Sambuc 	DIP_ASSIGN(ip, nlink, ip->i_nlink);
58784d9c625SLionel Sambuc 	ip->i_flag |= IN_CHANGE;
58884d9c625SLionel Sambuc 	error = lfs_update(vp, NULL, NULL, UPDATE_DIROP);
58984d9c625SLionel Sambuc 	if (!error) {
590*0a6a1f1dSLionel Sambuc 		error = ulfs_direnter(dvp, ulr, vp,
591*0a6a1f1dSLionel Sambuc 				      cnp, ip->i_number, LFS_IFTODT(ip->i_mode), NULL);
59284d9c625SLionel Sambuc 	}
59384d9c625SLionel Sambuc 	if (error) {
59484d9c625SLionel Sambuc 		ip->i_nlink--;
59584d9c625SLionel Sambuc 		DIP_ASSIGN(ip, nlink, ip->i_nlink);
59684d9c625SLionel Sambuc 		ip->i_flag |= IN_CHANGE;
59784d9c625SLionel Sambuc 	}
59884d9c625SLionel Sambuc  out1:
59984d9c625SLionel Sambuc 	VOP_UNLOCK(vp);
60084d9c625SLionel Sambuc  out2:
60184d9c625SLionel Sambuc 	VN_KNOTE(vp, NOTE_LINK);
60284d9c625SLionel Sambuc 	VN_KNOTE(dvp, NOTE_WRITE);
603*0a6a1f1dSLionel Sambuc 	fstrans_done(mp);
60484d9c625SLionel Sambuc 	return (error);
60584d9c625SLionel Sambuc }
60684d9c625SLionel Sambuc 
60784d9c625SLionel Sambuc /*
60884d9c625SLionel Sambuc  * whiteout vnode call
60984d9c625SLionel Sambuc  */
61084d9c625SLionel Sambuc int
ulfs_whiteout(void * v)61184d9c625SLionel Sambuc ulfs_whiteout(void *v)
61284d9c625SLionel Sambuc {
61384d9c625SLionel Sambuc 	struct vop_whiteout_args /* {
61484d9c625SLionel Sambuc 		struct vnode		*a_dvp;
61584d9c625SLionel Sambuc 		struct componentname	*a_cnp;
61684d9c625SLionel Sambuc 		int			a_flags;
61784d9c625SLionel Sambuc 	} */ *ap = v;
61884d9c625SLionel Sambuc 	struct vnode		*dvp = ap->a_dvp;
61984d9c625SLionel Sambuc 	struct componentname	*cnp = ap->a_cnp;
62084d9c625SLionel Sambuc 	int			error;
62184d9c625SLionel Sambuc 	struct ulfsmount	*ump = VFSTOULFS(dvp->v_mount);
62284d9c625SLionel Sambuc 	struct lfs *fs = ump->um_lfs;
62384d9c625SLionel Sambuc 	struct ulfs_lookup_results *ulr;
62484d9c625SLionel Sambuc 
62584d9c625SLionel Sambuc 	/* XXX should handle this material another way */
62684d9c625SLionel Sambuc 	ulr = &VTOI(dvp)->i_crap;
62784d9c625SLionel Sambuc 	ULFS_CHECK_CRAPCOUNTER(VTOI(dvp));
62884d9c625SLionel Sambuc 
62984d9c625SLionel Sambuc 	error = 0;
63084d9c625SLionel Sambuc 	switch (ap->a_flags) {
63184d9c625SLionel Sambuc 	case LOOKUP:
63284d9c625SLionel Sambuc 		/* 4.4 format directories support whiteout operations */
63384d9c625SLionel Sambuc 		if (fs->um_maxsymlinklen > 0)
63484d9c625SLionel Sambuc 			return (0);
63584d9c625SLionel Sambuc 		return (EOPNOTSUPP);
63684d9c625SLionel Sambuc 
63784d9c625SLionel Sambuc 	case CREATE:
63884d9c625SLionel Sambuc 		/* create a new directory whiteout */
63984d9c625SLionel Sambuc 		fstrans_start(dvp->v_mount, FSTRANS_SHARED);
64084d9c625SLionel Sambuc #ifdef DIAGNOSTIC
64184d9c625SLionel Sambuc 		if (fs->um_maxsymlinklen <= 0)
64284d9c625SLionel Sambuc 			panic("ulfs_whiteout: old format filesystem");
64384d9c625SLionel Sambuc #endif
64484d9c625SLionel Sambuc 
645*0a6a1f1dSLionel Sambuc 		error = ulfs_direnter(dvp, ulr, NULL,
646*0a6a1f1dSLionel Sambuc 				      cnp, ULFS_WINO, LFS_DT_WHT,  NULL);
64784d9c625SLionel Sambuc 		break;
64884d9c625SLionel Sambuc 
64984d9c625SLionel Sambuc 	case DELETE:
65084d9c625SLionel Sambuc 		/* remove an existing directory whiteout */
65184d9c625SLionel Sambuc 		fstrans_start(dvp->v_mount, FSTRANS_SHARED);
65284d9c625SLionel Sambuc #ifdef DIAGNOSTIC
65384d9c625SLionel Sambuc 		if (fs->um_maxsymlinklen <= 0)
65484d9c625SLionel Sambuc 			panic("ulfs_whiteout: old format filesystem");
65584d9c625SLionel Sambuc #endif
65684d9c625SLionel Sambuc 
65784d9c625SLionel Sambuc 		cnp->cn_flags &= ~DOWHITEOUT;
65884d9c625SLionel Sambuc 		error = ulfs_dirremove(dvp, ulr, NULL, cnp->cn_flags, 0);
65984d9c625SLionel Sambuc 		break;
66084d9c625SLionel Sambuc 	default:
66184d9c625SLionel Sambuc 		panic("ulfs_whiteout: unknown op");
66284d9c625SLionel Sambuc 		/* NOTREACHED */
66384d9c625SLionel Sambuc 	}
66484d9c625SLionel Sambuc 	fstrans_done(dvp->v_mount);
66584d9c625SLionel Sambuc 	return (error);
66684d9c625SLionel Sambuc }
66784d9c625SLionel Sambuc 
66884d9c625SLionel Sambuc int
ulfs_rmdir(void * v)66984d9c625SLionel Sambuc ulfs_rmdir(void *v)
67084d9c625SLionel Sambuc {
67184d9c625SLionel Sambuc 	struct vop_rmdir_args /* {
67284d9c625SLionel Sambuc 		struct vnode		*a_dvp;
67384d9c625SLionel Sambuc 		struct vnode		*a_vp;
67484d9c625SLionel Sambuc 		struct componentname	*a_cnp;
67584d9c625SLionel Sambuc 	} */ *ap = v;
67684d9c625SLionel Sambuc 	struct vnode		*vp, *dvp;
67784d9c625SLionel Sambuc 	struct componentname	*cnp;
67884d9c625SLionel Sambuc 	struct inode		*ip, *dp;
67984d9c625SLionel Sambuc 	int			error;
68084d9c625SLionel Sambuc 	struct ulfs_lookup_results *ulr;
68184d9c625SLionel Sambuc 
68284d9c625SLionel Sambuc 	vp = ap->a_vp;
68384d9c625SLionel Sambuc 	dvp = ap->a_dvp;
68484d9c625SLionel Sambuc 	cnp = ap->a_cnp;
68584d9c625SLionel Sambuc 	ip = VTOI(vp);
68684d9c625SLionel Sambuc 	dp = VTOI(dvp);
68784d9c625SLionel Sambuc 
68884d9c625SLionel Sambuc 	/* XXX should handle this material another way */
68984d9c625SLionel Sambuc 	ulr = &dp->i_crap;
69084d9c625SLionel Sambuc 	ULFS_CHECK_CRAPCOUNTER(dp);
69184d9c625SLionel Sambuc 
69284d9c625SLionel Sambuc 	/*
69384d9c625SLionel Sambuc 	 * No rmdir "." or of mounted directories please.
69484d9c625SLionel Sambuc 	 */
69584d9c625SLionel Sambuc 	if (dp == ip || vp->v_mountedhere != NULL) {
69684d9c625SLionel Sambuc 		if (dp == ip)
69784d9c625SLionel Sambuc 			vrele(dvp);
69884d9c625SLionel Sambuc 		else
69984d9c625SLionel Sambuc 			vput(dvp);
70084d9c625SLionel Sambuc 		vput(vp);
70184d9c625SLionel Sambuc 		return (EINVAL);
70284d9c625SLionel Sambuc 	}
70384d9c625SLionel Sambuc 
70484d9c625SLionel Sambuc 	fstrans_start(dvp->v_mount, FSTRANS_SHARED);
70584d9c625SLionel Sambuc 
70684d9c625SLionel Sambuc 	/*
70784d9c625SLionel Sambuc 	 * Do not remove a directory that is in the process of being renamed.
70884d9c625SLionel Sambuc 	 * Verify that the directory is empty (and valid). (Rmdir ".." won't
70984d9c625SLionel Sambuc 	 * be valid since ".." will contain a reference to the current
71084d9c625SLionel Sambuc 	 * directory and thus be non-empty.)
71184d9c625SLionel Sambuc 	 */
71284d9c625SLionel Sambuc 	error = 0;
71384d9c625SLionel Sambuc 	if (ip->i_nlink != 2 ||
71484d9c625SLionel Sambuc 	    !ulfs_dirempty(ip, dp->i_number, cnp->cn_cred)) {
71584d9c625SLionel Sambuc 		error = ENOTEMPTY;
71684d9c625SLionel Sambuc 		goto out;
71784d9c625SLionel Sambuc 	}
71884d9c625SLionel Sambuc 	if ((dp->i_flags & APPEND) ||
71984d9c625SLionel Sambuc 		(ip->i_flags & (IMMUTABLE | APPEND))) {
72084d9c625SLionel Sambuc 		error = EPERM;
72184d9c625SLionel Sambuc 		goto out;
72284d9c625SLionel Sambuc 	}
72384d9c625SLionel Sambuc 	/*
72484d9c625SLionel Sambuc 	 * Delete reference to directory before purging
72584d9c625SLionel Sambuc 	 * inode.  If we crash in between, the directory
72684d9c625SLionel Sambuc 	 * will be reattached to lost+found,
72784d9c625SLionel Sambuc 	 */
72884d9c625SLionel Sambuc 	error = ulfs_dirremove(dvp, ulr, ip, cnp->cn_flags, 1);
72984d9c625SLionel Sambuc 	if (error) {
73084d9c625SLionel Sambuc 		goto out;
73184d9c625SLionel Sambuc 	}
73284d9c625SLionel Sambuc 	VN_KNOTE(dvp, NOTE_WRITE | NOTE_LINK);
73384d9c625SLionel Sambuc 	cache_purge(dvp);
73484d9c625SLionel Sambuc 	/*
73584d9c625SLionel Sambuc 	 * Truncate inode.  The only stuff left in the directory is "." and
73684d9c625SLionel Sambuc 	 * "..".  The "." reference is inconsequential since we're quashing
73784d9c625SLionel Sambuc 	 * it.
73884d9c625SLionel Sambuc 	 */
73984d9c625SLionel Sambuc 	dp->i_nlink--;
74084d9c625SLionel Sambuc 	DIP_ASSIGN(dp, nlink, dp->i_nlink);
74184d9c625SLionel Sambuc 	dp->i_flag |= IN_CHANGE;
74284d9c625SLionel Sambuc 	ip->i_nlink--;
74384d9c625SLionel Sambuc 	DIP_ASSIGN(ip, nlink, ip->i_nlink);
74484d9c625SLionel Sambuc 	ip->i_flag |= IN_CHANGE;
74584d9c625SLionel Sambuc 	error = lfs_truncate(vp, (off_t)0, IO_SYNC, cnp->cn_cred);
74684d9c625SLionel Sambuc 	cache_purge(vp);
74784d9c625SLionel Sambuc #ifdef LFS_DIRHASH
74884d9c625SLionel Sambuc 	if (ip->i_dirhash != NULL)
74984d9c625SLionel Sambuc 		ulfsdirhash_free(ip);
75084d9c625SLionel Sambuc #endif
75184d9c625SLionel Sambuc  out:
75284d9c625SLionel Sambuc 	VN_KNOTE(vp, NOTE_DELETE);
75384d9c625SLionel Sambuc 	vput(vp);
75484d9c625SLionel Sambuc 	fstrans_done(dvp->v_mount);
75584d9c625SLionel Sambuc 	vput(dvp);
75684d9c625SLionel Sambuc 	return (error);
75784d9c625SLionel Sambuc }
75884d9c625SLionel Sambuc 
75984d9c625SLionel Sambuc /*
76084d9c625SLionel Sambuc  * Vnode op for reading directories.
76184d9c625SLionel Sambuc  *
76284d9c625SLionel Sambuc  * This routine handles converting from the on-disk directory format
76384d9c625SLionel Sambuc  * "struct lfs_direct" to the in-memory format "struct dirent" as well as
76484d9c625SLionel Sambuc  * byte swapping the entries if necessary.
76584d9c625SLionel Sambuc  */
76684d9c625SLionel Sambuc int
ulfs_readdir(void * v)76784d9c625SLionel Sambuc ulfs_readdir(void *v)
76884d9c625SLionel Sambuc {
76984d9c625SLionel Sambuc 	struct vop_readdir_args /* {
77084d9c625SLionel Sambuc 		struct vnode	*a_vp;
77184d9c625SLionel Sambuc 		struct uio	*a_uio;
77284d9c625SLionel Sambuc 		kauth_cred_t	a_cred;
77384d9c625SLionel Sambuc 		int		*a_eofflag;
77484d9c625SLionel Sambuc 		off_t		**a_cookies;
77584d9c625SLionel Sambuc 		int		*ncookies;
77684d9c625SLionel Sambuc 	} */ *ap = v;
77784d9c625SLionel Sambuc 	struct vnode	*vp = ap->a_vp;
778*0a6a1f1dSLionel Sambuc 	LFS_DIRHEADER	*cdp, *ecdp;
77984d9c625SLionel Sambuc 	struct dirent	*ndp;
78084d9c625SLionel Sambuc 	char		*cdbuf, *ndbuf, *endp;
78184d9c625SLionel Sambuc 	struct uio	auio, *uio;
78284d9c625SLionel Sambuc 	struct iovec	aiov;
78384d9c625SLionel Sambuc 	int		error;
78484d9c625SLionel Sambuc 	size_t		count, ccount, rcount, cdbufsz, ndbufsz;
78584d9c625SLionel Sambuc 	off_t		off, *ccp;
78684d9c625SLionel Sambuc 	off_t		startoff;
78784d9c625SLionel Sambuc 	size_t		skipbytes;
78884d9c625SLionel Sambuc 	struct ulfsmount *ump = VFSTOULFS(vp->v_mount);
78984d9c625SLionel Sambuc 	struct lfs *fs = ump->um_lfs;
79084d9c625SLionel Sambuc 	uio = ap->a_uio;
79184d9c625SLionel Sambuc 	count = uio->uio_resid;
79284d9c625SLionel Sambuc 	rcount = count - ((uio->uio_offset + count) & (fs->um_dirblksiz - 1));
79384d9c625SLionel Sambuc 
794*0a6a1f1dSLionel Sambuc 	if (rcount < LFS_DIRECTSIZ(fs, 0) || count < _DIRENT_MINSIZE(ndp))
79584d9c625SLionel Sambuc 		return EINVAL;
79684d9c625SLionel Sambuc 
79784d9c625SLionel Sambuc 	startoff = uio->uio_offset & ~(fs->um_dirblksiz - 1);
79884d9c625SLionel Sambuc 	skipbytes = uio->uio_offset - startoff;
79984d9c625SLionel Sambuc 	rcount += skipbytes;
80084d9c625SLionel Sambuc 
80184d9c625SLionel Sambuc 	auio.uio_iov = &aiov;
80284d9c625SLionel Sambuc 	auio.uio_iovcnt = 1;
80384d9c625SLionel Sambuc 	auio.uio_offset = startoff;
80484d9c625SLionel Sambuc 	auio.uio_resid = rcount;
80584d9c625SLionel Sambuc 	UIO_SETUP_SYSSPACE(&auio);
80684d9c625SLionel Sambuc 	auio.uio_rw = UIO_READ;
80784d9c625SLionel Sambuc 	cdbufsz = rcount;
80884d9c625SLionel Sambuc 	cdbuf = kmem_alloc(cdbufsz, KM_SLEEP);
80984d9c625SLionel Sambuc 	aiov.iov_base = cdbuf;
81084d9c625SLionel Sambuc 	aiov.iov_len = rcount;
81184d9c625SLionel Sambuc 	error = VOP_READ(vp, &auio, 0, ap->a_cred);
81284d9c625SLionel Sambuc 	if (error != 0) {
81384d9c625SLionel Sambuc 		kmem_free(cdbuf, cdbufsz);
81484d9c625SLionel Sambuc 		return error;
81584d9c625SLionel Sambuc 	}
81684d9c625SLionel Sambuc 
81784d9c625SLionel Sambuc 	rcount -= auio.uio_resid;
81884d9c625SLionel Sambuc 
819*0a6a1f1dSLionel Sambuc 	cdp = (LFS_DIRHEADER *)(void *)cdbuf;
820*0a6a1f1dSLionel Sambuc 	ecdp = (LFS_DIRHEADER *)(void *)&cdbuf[rcount];
82184d9c625SLionel Sambuc 
82284d9c625SLionel Sambuc 	ndbufsz = count;
82384d9c625SLionel Sambuc 	ndbuf = kmem_alloc(ndbufsz, KM_SLEEP);
82484d9c625SLionel Sambuc 	ndp = (struct dirent *)(void *)ndbuf;
82584d9c625SLionel Sambuc 	endp = &ndbuf[count];
82684d9c625SLionel Sambuc 
82784d9c625SLionel Sambuc 	off = uio->uio_offset;
82884d9c625SLionel Sambuc 	if (ap->a_cookies) {
829*0a6a1f1dSLionel Sambuc 		ccount = rcount / _DIRENT_RECLEN(ndp, 1);
83084d9c625SLionel Sambuc 		ccp = *(ap->a_cookies) = malloc(ccount * sizeof(*ccp),
83184d9c625SLionel Sambuc 		    M_TEMP, M_WAITOK);
83284d9c625SLionel Sambuc 	} else {
83384d9c625SLionel Sambuc 		/* XXX: GCC */
83484d9c625SLionel Sambuc 		ccount = 0;
83584d9c625SLionel Sambuc 		ccp = NULL;
83684d9c625SLionel Sambuc 	}
83784d9c625SLionel Sambuc 
83884d9c625SLionel Sambuc 	while (cdp < ecdp) {
83984d9c625SLionel Sambuc 		if (skipbytes > 0) {
840*0a6a1f1dSLionel Sambuc 			if (lfs_dir_getreclen(fs, cdp) <= skipbytes) {
841*0a6a1f1dSLionel Sambuc 				skipbytes -= lfs_dir_getreclen(fs, cdp);
842*0a6a1f1dSLionel Sambuc 				cdp = LFS_NEXTDIR(fs, cdp);
84384d9c625SLionel Sambuc 				continue;
84484d9c625SLionel Sambuc 			}
84584d9c625SLionel Sambuc 			/*
84684d9c625SLionel Sambuc 			 * invalid cookie.
84784d9c625SLionel Sambuc 			 */
84884d9c625SLionel Sambuc 			error = EINVAL;
84984d9c625SLionel Sambuc 			goto out;
85084d9c625SLionel Sambuc 		}
851*0a6a1f1dSLionel Sambuc 		if (lfs_dir_getreclen(fs, cdp) == 0) {
85284d9c625SLionel Sambuc 			struct dirent *ondp = ndp;
85384d9c625SLionel Sambuc 			ndp->d_reclen = _DIRENT_MINSIZE(ndp);
85484d9c625SLionel Sambuc 			ndp = _DIRENT_NEXT(ndp);
85584d9c625SLionel Sambuc 			ondp->d_reclen = 0;
85684d9c625SLionel Sambuc 			cdp = ecdp;
85784d9c625SLionel Sambuc 			break;
85884d9c625SLionel Sambuc 		}
859*0a6a1f1dSLionel Sambuc 		ndp->d_type = lfs_dir_gettype(fs, cdp);
860*0a6a1f1dSLionel Sambuc 		ndp->d_namlen = lfs_dir_getnamlen(fs, cdp);
86184d9c625SLionel Sambuc 		ndp->d_reclen = _DIRENT_RECLEN(ndp, ndp->d_namlen);
86284d9c625SLionel Sambuc 		if ((char *)(void *)ndp + ndp->d_reclen +
86384d9c625SLionel Sambuc 		    _DIRENT_MINSIZE(ndp) > endp)
86484d9c625SLionel Sambuc 			break;
865*0a6a1f1dSLionel Sambuc 		ndp->d_fileno = lfs_dir_getino(fs, cdp);
866*0a6a1f1dSLionel Sambuc 		(void)memcpy(ndp->d_name, lfs_dir_nameptr(fs, cdp),
867*0a6a1f1dSLionel Sambuc 			     ndp->d_namlen);
86884d9c625SLionel Sambuc 		memset(&ndp->d_name[ndp->d_namlen], 0,
86984d9c625SLionel Sambuc 		    ndp->d_reclen - _DIRENT_NAMEOFF(ndp) - ndp->d_namlen);
870*0a6a1f1dSLionel Sambuc 		off += lfs_dir_getreclen(fs, cdp);
87184d9c625SLionel Sambuc 		if (ap->a_cookies) {
87284d9c625SLionel Sambuc 			KASSERT(ccp - *(ap->a_cookies) < ccount);
87384d9c625SLionel Sambuc 			*(ccp++) = off;
87484d9c625SLionel Sambuc 		}
87584d9c625SLionel Sambuc 		ndp = _DIRENT_NEXT(ndp);
876*0a6a1f1dSLionel Sambuc 		cdp = LFS_NEXTDIR(fs, cdp);
87784d9c625SLionel Sambuc 	}
87884d9c625SLionel Sambuc 
87984d9c625SLionel Sambuc 	count = ((char *)(void *)ndp - ndbuf);
88084d9c625SLionel Sambuc 	error = uiomove(ndbuf, count, uio);
88184d9c625SLionel Sambuc out:
88284d9c625SLionel Sambuc 	if (ap->a_cookies) {
88384d9c625SLionel Sambuc 		if (error) {
88484d9c625SLionel Sambuc 			free(*(ap->a_cookies), M_TEMP);
88584d9c625SLionel Sambuc 			*(ap->a_cookies) = NULL;
88684d9c625SLionel Sambuc 			*(ap->a_ncookies) = 0;
88784d9c625SLionel Sambuc 		} else {
88884d9c625SLionel Sambuc 			*ap->a_ncookies = ccp - *(ap->a_cookies);
88984d9c625SLionel Sambuc 		}
89084d9c625SLionel Sambuc 	}
89184d9c625SLionel Sambuc 	uio->uio_offset = off;
89284d9c625SLionel Sambuc 	kmem_free(ndbuf, ndbufsz);
89384d9c625SLionel Sambuc 	kmem_free(cdbuf, cdbufsz);
89484d9c625SLionel Sambuc 	*ap->a_eofflag = VTOI(vp)->i_size <= uio->uio_offset;
89584d9c625SLionel Sambuc 	return error;
89684d9c625SLionel Sambuc }
89784d9c625SLionel Sambuc 
89884d9c625SLionel Sambuc /*
89984d9c625SLionel Sambuc  * Return target name of a symbolic link
90084d9c625SLionel Sambuc  */
90184d9c625SLionel Sambuc int
ulfs_readlink(void * v)90284d9c625SLionel Sambuc ulfs_readlink(void *v)
90384d9c625SLionel Sambuc {
90484d9c625SLionel Sambuc 	struct vop_readlink_args /* {
90584d9c625SLionel Sambuc 		struct vnode	*a_vp;
90684d9c625SLionel Sambuc 		struct uio	*a_uio;
90784d9c625SLionel Sambuc 		kauth_cred_t	a_cred;
90884d9c625SLionel Sambuc 	} */ *ap = v;
90984d9c625SLionel Sambuc 	struct vnode	*vp = ap->a_vp;
91084d9c625SLionel Sambuc 	struct inode	*ip = VTOI(vp);
91184d9c625SLionel Sambuc 	struct ulfsmount *ump = VFSTOULFS(vp->v_mount);
91284d9c625SLionel Sambuc 	struct lfs *fs = ump->um_lfs;
91384d9c625SLionel Sambuc 	int		isize;
91484d9c625SLionel Sambuc 
91584d9c625SLionel Sambuc 	isize = ip->i_size;
91684d9c625SLionel Sambuc 	if (isize < fs->um_maxsymlinklen ||
91784d9c625SLionel Sambuc 	    (fs->um_maxsymlinklen == 0 && DIP(ip, blocks) == 0)) {
91884d9c625SLionel Sambuc 		uiomove((char *)SHORTLINK(ip), isize, ap->a_uio);
91984d9c625SLionel Sambuc 		return (0);
92084d9c625SLionel Sambuc 	}
921*0a6a1f1dSLionel Sambuc 	return (lfs_bufrd(vp, ap->a_uio, 0, ap->a_cred));
92284d9c625SLionel Sambuc }
92384d9c625SLionel Sambuc 
92484d9c625SLionel Sambuc /*
92584d9c625SLionel Sambuc  * Print out the contents of an inode.
92684d9c625SLionel Sambuc  */
92784d9c625SLionel Sambuc int
ulfs_print(void * v)92884d9c625SLionel Sambuc ulfs_print(void *v)
92984d9c625SLionel Sambuc {
93084d9c625SLionel Sambuc 	struct vop_print_args /* {
93184d9c625SLionel Sambuc 		struct vnode	*a_vp;
93284d9c625SLionel Sambuc 	} */ *ap = v;
93384d9c625SLionel Sambuc 	struct vnode	*vp;
93484d9c625SLionel Sambuc 	struct inode	*ip;
93584d9c625SLionel Sambuc 
93684d9c625SLionel Sambuc 	vp = ap->a_vp;
93784d9c625SLionel Sambuc 	ip = VTOI(vp);
93884d9c625SLionel Sambuc 	printf("tag VT_ULFS, ino %llu, on dev %llu, %llu",
93984d9c625SLionel Sambuc 	    (unsigned long long)ip->i_number,
94084d9c625SLionel Sambuc 	    (unsigned long long)major(ip->i_dev),
94184d9c625SLionel Sambuc 	    (unsigned long long)minor(ip->i_dev));
94284d9c625SLionel Sambuc 	printf(" flags 0x%x, nlink %d\n",
94384d9c625SLionel Sambuc 	    ip->i_flag, ip->i_nlink);
94484d9c625SLionel Sambuc 	printf("\tmode 0%o, owner %d, group %d, size %qd",
94584d9c625SLionel Sambuc 	    ip->i_mode, ip->i_uid, ip->i_gid,
94684d9c625SLionel Sambuc 	    (long long)ip->i_size);
94784d9c625SLionel Sambuc 	if (vp->v_type == VFIFO)
94884d9c625SLionel Sambuc 		VOCALL(fifo_vnodeop_p, VOFFSET(vop_print), v);
94984d9c625SLionel Sambuc 	printf("\n");
95084d9c625SLionel Sambuc 	return (0);
95184d9c625SLionel Sambuc }
95284d9c625SLionel Sambuc 
95384d9c625SLionel Sambuc /*
95484d9c625SLionel Sambuc  * Read wrapper for special devices.
95584d9c625SLionel Sambuc  */
95684d9c625SLionel Sambuc int
ulfsspec_read(void * v)95784d9c625SLionel Sambuc ulfsspec_read(void *v)
95884d9c625SLionel Sambuc {
95984d9c625SLionel Sambuc 	struct vop_read_args /* {
96084d9c625SLionel Sambuc 		struct vnode	*a_vp;
96184d9c625SLionel Sambuc 		struct uio	*a_uio;
96284d9c625SLionel Sambuc 		int		a_ioflag;
96384d9c625SLionel Sambuc 		kauth_cred_t	a_cred;
96484d9c625SLionel Sambuc 	} */ *ap = v;
96584d9c625SLionel Sambuc 
96684d9c625SLionel Sambuc 	/*
96784d9c625SLionel Sambuc 	 * Set access flag.
96884d9c625SLionel Sambuc 	 */
96984d9c625SLionel Sambuc 	if ((ap->a_vp->v_mount->mnt_flag & MNT_NODEVMTIME) == 0)
97084d9c625SLionel Sambuc 		VTOI(ap->a_vp)->i_flag |= IN_ACCESS;
97184d9c625SLionel Sambuc 	return (VOCALL (spec_vnodeop_p, VOFFSET(vop_read), ap));
97284d9c625SLionel Sambuc }
97384d9c625SLionel Sambuc 
97484d9c625SLionel Sambuc /*
97584d9c625SLionel Sambuc  * Write wrapper for special devices.
97684d9c625SLionel Sambuc  */
97784d9c625SLionel Sambuc int
ulfsspec_write(void * v)97884d9c625SLionel Sambuc ulfsspec_write(void *v)
97984d9c625SLionel Sambuc {
98084d9c625SLionel Sambuc 	struct vop_write_args /* {
98184d9c625SLionel Sambuc 		struct vnode	*a_vp;
98284d9c625SLionel Sambuc 		struct uio	*a_uio;
98384d9c625SLionel Sambuc 		int		a_ioflag;
98484d9c625SLionel Sambuc 		kauth_cred_t	a_cred;
98584d9c625SLionel Sambuc 	} */ *ap = v;
98684d9c625SLionel Sambuc 
98784d9c625SLionel Sambuc 	/*
98884d9c625SLionel Sambuc 	 * Set update and change flags.
98984d9c625SLionel Sambuc 	 */
99084d9c625SLionel Sambuc 	if ((ap->a_vp->v_mount->mnt_flag & MNT_NODEVMTIME) == 0)
99184d9c625SLionel Sambuc 		VTOI(ap->a_vp)->i_flag |= IN_MODIFY;
99284d9c625SLionel Sambuc 	return (VOCALL (spec_vnodeop_p, VOFFSET(vop_write), ap));
99384d9c625SLionel Sambuc }
99484d9c625SLionel Sambuc 
99584d9c625SLionel Sambuc /*
99684d9c625SLionel Sambuc  * Read wrapper for fifo's
99784d9c625SLionel Sambuc  */
99884d9c625SLionel Sambuc int
ulfsfifo_read(void * v)99984d9c625SLionel Sambuc ulfsfifo_read(void *v)
100084d9c625SLionel Sambuc {
100184d9c625SLionel Sambuc 	struct vop_read_args /* {
100284d9c625SLionel Sambuc 		struct vnode	*a_vp;
100384d9c625SLionel Sambuc 		struct uio	*a_uio;
100484d9c625SLionel Sambuc 		int		a_ioflag;
100584d9c625SLionel Sambuc 		kauth_cred_t	a_cred;
100684d9c625SLionel Sambuc 	} */ *ap = v;
100784d9c625SLionel Sambuc 
100884d9c625SLionel Sambuc 	/*
100984d9c625SLionel Sambuc 	 * Set access flag.
101084d9c625SLionel Sambuc 	 */
101184d9c625SLionel Sambuc 	VTOI(ap->a_vp)->i_flag |= IN_ACCESS;
101284d9c625SLionel Sambuc 	return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_read), ap));
101384d9c625SLionel Sambuc }
101484d9c625SLionel Sambuc 
101584d9c625SLionel Sambuc /*
101684d9c625SLionel Sambuc  * Write wrapper for fifo's.
101784d9c625SLionel Sambuc  */
101884d9c625SLionel Sambuc int
ulfsfifo_write(void * v)101984d9c625SLionel Sambuc ulfsfifo_write(void *v)
102084d9c625SLionel Sambuc {
102184d9c625SLionel Sambuc 	struct vop_write_args /* {
102284d9c625SLionel Sambuc 		struct vnode	*a_vp;
102384d9c625SLionel Sambuc 		struct uio	*a_uio;
102484d9c625SLionel Sambuc 		int		a_ioflag;
102584d9c625SLionel Sambuc 		kauth_cred_t	a_cred;
102684d9c625SLionel Sambuc 	} */ *ap = v;
102784d9c625SLionel Sambuc 
102884d9c625SLionel Sambuc 	/*
102984d9c625SLionel Sambuc 	 * Set update and change flags.
103084d9c625SLionel Sambuc 	 */
103184d9c625SLionel Sambuc 	VTOI(ap->a_vp)->i_flag |= IN_MODIFY;
103284d9c625SLionel Sambuc 	return (VOCALL (fifo_vnodeop_p, VOFFSET(vop_write), ap));
103384d9c625SLionel Sambuc }
103484d9c625SLionel Sambuc 
103584d9c625SLionel Sambuc /*
103684d9c625SLionel Sambuc  * Return POSIX pathconf information applicable to ulfs filesystems.
103784d9c625SLionel Sambuc  */
103884d9c625SLionel Sambuc int
ulfs_pathconf(void * v)103984d9c625SLionel Sambuc ulfs_pathconf(void *v)
104084d9c625SLionel Sambuc {
104184d9c625SLionel Sambuc 	struct vop_pathconf_args /* {
104284d9c625SLionel Sambuc 		struct vnode	*a_vp;
104384d9c625SLionel Sambuc 		int		a_name;
104484d9c625SLionel Sambuc 		register_t	*a_retval;
104584d9c625SLionel Sambuc 	} */ *ap = v;
104684d9c625SLionel Sambuc 
104784d9c625SLionel Sambuc 	switch (ap->a_name) {
104884d9c625SLionel Sambuc 	case _PC_LINK_MAX:
104984d9c625SLionel Sambuc 		*ap->a_retval = LINK_MAX;
105084d9c625SLionel Sambuc 		return (0);
105184d9c625SLionel Sambuc 	case _PC_NAME_MAX:
105284d9c625SLionel Sambuc 		*ap->a_retval = LFS_MAXNAMLEN;
105384d9c625SLionel Sambuc 		return (0);
105484d9c625SLionel Sambuc 	case _PC_PATH_MAX:
105584d9c625SLionel Sambuc 		*ap->a_retval = PATH_MAX;
105684d9c625SLionel Sambuc 		return (0);
105784d9c625SLionel Sambuc 	case _PC_PIPE_BUF:
105884d9c625SLionel Sambuc 		*ap->a_retval = PIPE_BUF;
105984d9c625SLionel Sambuc 		return (0);
106084d9c625SLionel Sambuc 	case _PC_CHOWN_RESTRICTED:
106184d9c625SLionel Sambuc 		*ap->a_retval = 1;
106284d9c625SLionel Sambuc 		return (0);
106384d9c625SLionel Sambuc 	case _PC_NO_TRUNC:
106484d9c625SLionel Sambuc 		*ap->a_retval = 1;
106584d9c625SLionel Sambuc 		return (0);
106684d9c625SLionel Sambuc 	case _PC_SYNC_IO:
106784d9c625SLionel Sambuc 		*ap->a_retval = 1;
106884d9c625SLionel Sambuc 		return (0);
106984d9c625SLionel Sambuc 	case _PC_FILESIZEBITS:
107084d9c625SLionel Sambuc 		*ap->a_retval = 42;
107184d9c625SLionel Sambuc 		return (0);
107284d9c625SLionel Sambuc 	case _PC_SYMLINK_MAX:
107384d9c625SLionel Sambuc 		*ap->a_retval = MAXPATHLEN;
107484d9c625SLionel Sambuc 		return (0);
107584d9c625SLionel Sambuc 	case _PC_2_SYMLINKS:
107684d9c625SLionel Sambuc 		*ap->a_retval = 1;
107784d9c625SLionel Sambuc 		return (0);
107884d9c625SLionel Sambuc 	default:
107984d9c625SLionel Sambuc 		return (EINVAL);
108084d9c625SLionel Sambuc 	}
108184d9c625SLionel Sambuc 	/* NOTREACHED */
108284d9c625SLionel Sambuc }
108384d9c625SLionel Sambuc 
108484d9c625SLionel Sambuc /*
108584d9c625SLionel Sambuc  * Advisory record locking support
108684d9c625SLionel Sambuc  */
108784d9c625SLionel Sambuc int
ulfs_advlock(void * v)108884d9c625SLionel Sambuc ulfs_advlock(void *v)
108984d9c625SLionel Sambuc {
109084d9c625SLionel Sambuc 	struct vop_advlock_args /* {
109184d9c625SLionel Sambuc 		struct vnode	*a_vp;
109284d9c625SLionel Sambuc 		void *		a_id;
109384d9c625SLionel Sambuc 		int		a_op;
109484d9c625SLionel Sambuc 		struct flock	*a_fl;
109584d9c625SLionel Sambuc 		int		a_flags;
109684d9c625SLionel Sambuc 	} */ *ap = v;
109784d9c625SLionel Sambuc 	struct inode *ip;
109884d9c625SLionel Sambuc 
109984d9c625SLionel Sambuc 	ip = VTOI(ap->a_vp);
110084d9c625SLionel Sambuc 	return lf_advlock(ap, &ip->i_lockf, ip->i_size);
110184d9c625SLionel Sambuc }
110284d9c625SLionel Sambuc 
110384d9c625SLionel Sambuc /*
110484d9c625SLionel Sambuc  * Initialize the vnode associated with a new inode, handle aliased
110584d9c625SLionel Sambuc  * vnodes.
110684d9c625SLionel Sambuc  */
110784d9c625SLionel Sambuc void
ulfs_vinit(struct mount * mntp,int (** specops)(void *),int (** fifoops)(void *),struct vnode ** vpp)110884d9c625SLionel Sambuc ulfs_vinit(struct mount *mntp, int (**specops)(void *), int (**fifoops)(void *),
110984d9c625SLionel Sambuc 	struct vnode **vpp)
111084d9c625SLionel Sambuc {
111184d9c625SLionel Sambuc 	struct timeval	tv;
111284d9c625SLionel Sambuc 	struct inode	*ip;
111384d9c625SLionel Sambuc 	struct vnode	*vp;
111484d9c625SLionel Sambuc 	dev_t		rdev;
111584d9c625SLionel Sambuc 	struct ulfsmount *ump;
111684d9c625SLionel Sambuc 
111784d9c625SLionel Sambuc 	vp = *vpp;
111884d9c625SLionel Sambuc 	ip = VTOI(vp);
111984d9c625SLionel Sambuc 	switch(vp->v_type = IFTOVT(ip->i_mode)) {
112084d9c625SLionel Sambuc 	case VCHR:
112184d9c625SLionel Sambuc 	case VBLK:
112284d9c625SLionel Sambuc 		vp->v_op = specops;
112384d9c625SLionel Sambuc 		ump = ip->i_ump;
1124*0a6a1f1dSLionel Sambuc 		// XXX clean this up
112584d9c625SLionel Sambuc 		if (ump->um_fstype == ULFS1)
1126*0a6a1f1dSLionel Sambuc 			rdev = (dev_t)ulfs_rw32(ip->i_din->u_32.di_rdev,
112784d9c625SLionel Sambuc 			    ULFS_MPNEEDSWAP(ump->um_lfs));
112884d9c625SLionel Sambuc 		else
1129*0a6a1f1dSLionel Sambuc 			rdev = (dev_t)ulfs_rw64(ip->i_din->u_64.di_rdev,
113084d9c625SLionel Sambuc 			    ULFS_MPNEEDSWAP(ump->um_lfs));
113184d9c625SLionel Sambuc 		spec_node_init(vp, rdev);
113284d9c625SLionel Sambuc 		break;
113384d9c625SLionel Sambuc 	case VFIFO:
113484d9c625SLionel Sambuc 		vp->v_op = fifoops;
113584d9c625SLionel Sambuc 		break;
113684d9c625SLionel Sambuc 	case VNON:
113784d9c625SLionel Sambuc 	case VBAD:
113884d9c625SLionel Sambuc 	case VSOCK:
113984d9c625SLionel Sambuc 	case VLNK:
114084d9c625SLionel Sambuc 	case VDIR:
114184d9c625SLionel Sambuc 	case VREG:
114284d9c625SLionel Sambuc 		break;
114384d9c625SLionel Sambuc 	}
114484d9c625SLionel Sambuc 	if (ip->i_number == ULFS_ROOTINO)
114584d9c625SLionel Sambuc                 vp->v_vflag |= VV_ROOT;
114684d9c625SLionel Sambuc 	/*
114784d9c625SLionel Sambuc 	 * Initialize modrev times
114884d9c625SLionel Sambuc 	 */
114984d9c625SLionel Sambuc 	getmicrouptime(&tv);
115084d9c625SLionel Sambuc 	ip->i_modrev = (uint64_t)(uint)tv.tv_sec << 32
115184d9c625SLionel Sambuc 			| tv.tv_usec * 4294u;
115284d9c625SLionel Sambuc 	*vpp = vp;
115384d9c625SLionel Sambuc }
115484d9c625SLionel Sambuc 
115584d9c625SLionel Sambuc /*
115684d9c625SLionel Sambuc  * Allocate a new inode.
115784d9c625SLionel Sambuc  */
115884d9c625SLionel Sambuc int
ulfs_makeinode(struct vattr * vap,struct vnode * dvp,const struct ulfs_lookup_results * ulr,struct vnode ** vpp,struct componentname * cnp)1159*0a6a1f1dSLionel Sambuc ulfs_makeinode(struct vattr *vap, struct vnode *dvp,
1160*0a6a1f1dSLionel Sambuc 	const struct ulfs_lookup_results *ulr,
116184d9c625SLionel Sambuc 	struct vnode **vpp, struct componentname *cnp)
116284d9c625SLionel Sambuc {
1163*0a6a1f1dSLionel Sambuc 	struct inode	*ip;
116484d9c625SLionel Sambuc 	struct vnode	*tvp;
116584d9c625SLionel Sambuc 	int		error;
116684d9c625SLionel Sambuc 
1167*0a6a1f1dSLionel Sambuc 	error = vcache_new(dvp->v_mount, dvp, vap, cnp->cn_cred, &tvp);
1168*0a6a1f1dSLionel Sambuc 	if (error)
1169*0a6a1f1dSLionel Sambuc 		return error;
1170*0a6a1f1dSLionel Sambuc 	error = vn_lock(tvp, LK_EXCLUSIVE);
1171*0a6a1f1dSLionel Sambuc 	if (error) {
1172*0a6a1f1dSLionel Sambuc 		vrele(tvp);
1173*0a6a1f1dSLionel Sambuc 		return error;
117484d9c625SLionel Sambuc 	}
1175*0a6a1f1dSLionel Sambuc 	lfs_mark_vnode(tvp);
1176*0a6a1f1dSLionel Sambuc 	*vpp = tvp;
117784d9c625SLionel Sambuc 	ip = VTOI(tvp);
117884d9c625SLionel Sambuc 	ip->i_flag |= IN_ACCESS | IN_CHANGE | IN_UPDATE;
117984d9c625SLionel Sambuc 	ip->i_nlink = 1;
118084d9c625SLionel Sambuc 	DIP_ASSIGN(ip, nlink, 1);
118184d9c625SLionel Sambuc 
118284d9c625SLionel Sambuc 	/* Authorize setting SGID if needed. */
118384d9c625SLionel Sambuc 	if (ip->i_mode & ISGID) {
118484d9c625SLionel Sambuc 		error = kauth_authorize_vnode(cnp->cn_cred, KAUTH_VNODE_WRITE_SECURITY,
118584d9c625SLionel Sambuc 		    tvp, NULL, genfs_can_chmod(tvp->v_type, cnp->cn_cred, ip->i_uid,
1186*0a6a1f1dSLionel Sambuc 		    ip->i_gid, MAKEIMODE(vap->va_type, vap->va_mode)));
118784d9c625SLionel Sambuc 		if (error) {
118884d9c625SLionel Sambuc 			ip->i_mode &= ~ISGID;
118984d9c625SLionel Sambuc 			DIP_ASSIGN(ip, mode, ip->i_mode);
119084d9c625SLionel Sambuc 		}
119184d9c625SLionel Sambuc 	}
119284d9c625SLionel Sambuc 
119384d9c625SLionel Sambuc 	if (cnp->cn_flags & ISWHITEOUT) {
119484d9c625SLionel Sambuc 		ip->i_flags |= UF_OPAQUE;
119584d9c625SLionel Sambuc 		DIP_ASSIGN(ip, flags, ip->i_flags);
119684d9c625SLionel Sambuc 	}
119784d9c625SLionel Sambuc 
119884d9c625SLionel Sambuc 	/*
119984d9c625SLionel Sambuc 	 * Make sure inode goes to disk before directory entry.
120084d9c625SLionel Sambuc 	 */
120184d9c625SLionel Sambuc 	if ((error = lfs_update(tvp, NULL, NULL, UPDATE_DIROP)) != 0)
120284d9c625SLionel Sambuc 		goto bad;
1203*0a6a1f1dSLionel Sambuc 	error = ulfs_direnter(dvp, ulr, tvp,
1204*0a6a1f1dSLionel Sambuc 			      cnp, ip->i_number, LFS_IFTODT(ip->i_mode), NULL);
120584d9c625SLionel Sambuc 	if (error)
120684d9c625SLionel Sambuc 		goto bad;
120784d9c625SLionel Sambuc 	*vpp = tvp;
120884d9c625SLionel Sambuc 	return (0);
120984d9c625SLionel Sambuc 
121084d9c625SLionel Sambuc  bad:
121184d9c625SLionel Sambuc 	/*
121284d9c625SLionel Sambuc 	 * Write error occurred trying to update the inode
121384d9c625SLionel Sambuc 	 * or the directory so must deallocate the inode.
121484d9c625SLionel Sambuc 	 */
121584d9c625SLionel Sambuc 	ip->i_nlink = 0;
121684d9c625SLionel Sambuc 	DIP_ASSIGN(ip, nlink, 0);
121784d9c625SLionel Sambuc 	ip->i_flag |= IN_CHANGE;
121884d9c625SLionel Sambuc 	/* If IN_ADIROP, account for it */
121984d9c625SLionel Sambuc 	lfs_unmark_vnode(tvp);
122084d9c625SLionel Sambuc 	vput(tvp);
122184d9c625SLionel Sambuc 	return (error);
122284d9c625SLionel Sambuc }
122384d9c625SLionel Sambuc 
122484d9c625SLionel Sambuc /*
122584d9c625SLionel Sambuc  * Allocate len bytes at offset off.
122684d9c625SLionel Sambuc  */
122784d9c625SLionel Sambuc int
ulfs_gop_alloc(struct vnode * vp,off_t off,off_t len,int flags,kauth_cred_t cred)122884d9c625SLionel Sambuc ulfs_gop_alloc(struct vnode *vp, off_t off, off_t len, int flags,
122984d9c625SLionel Sambuc     kauth_cred_t cred)
123084d9c625SLionel Sambuc {
123184d9c625SLionel Sambuc         struct inode *ip = VTOI(vp);
123284d9c625SLionel Sambuc         int error, delta, bshift, bsize;
123384d9c625SLionel Sambuc         UVMHIST_FUNC("ulfs_gop_alloc"); UVMHIST_CALLED(ubchist);
123484d9c625SLionel Sambuc 
123584d9c625SLionel Sambuc         error = 0;
123684d9c625SLionel Sambuc         bshift = vp->v_mount->mnt_fs_bshift;
123784d9c625SLionel Sambuc         bsize = 1 << bshift;
123884d9c625SLionel Sambuc 
123984d9c625SLionel Sambuc         delta = off & (bsize - 1);
124084d9c625SLionel Sambuc         off -= delta;
124184d9c625SLionel Sambuc         len += delta;
124284d9c625SLionel Sambuc 
124384d9c625SLionel Sambuc         while (len > 0) {
124484d9c625SLionel Sambuc                 bsize = MIN(bsize, len);
124584d9c625SLionel Sambuc 
124684d9c625SLionel Sambuc                 error = lfs_balloc(vp, off, bsize, cred, flags, NULL);
124784d9c625SLionel Sambuc                 if (error) {
124884d9c625SLionel Sambuc                         goto out;
124984d9c625SLionel Sambuc                 }
125084d9c625SLionel Sambuc 
125184d9c625SLionel Sambuc                 /*
125284d9c625SLionel Sambuc                  * increase file size now, lfs_balloc() requires that
125384d9c625SLionel Sambuc                  * EOF be up-to-date before each call.
125484d9c625SLionel Sambuc                  */
125584d9c625SLionel Sambuc 
125684d9c625SLionel Sambuc                 if (ip->i_size < off + bsize) {
125784d9c625SLionel Sambuc                         UVMHIST_LOG(ubchist, "vp %p old 0x%x new 0x%x",
125884d9c625SLionel Sambuc                             vp, ip->i_size, off + bsize, 0);
125984d9c625SLionel Sambuc                         ip->i_size = off + bsize;
126084d9c625SLionel Sambuc 			DIP_ASSIGN(ip, size, ip->i_size);
126184d9c625SLionel Sambuc                 }
126284d9c625SLionel Sambuc 
126384d9c625SLionel Sambuc                 off += bsize;
126484d9c625SLionel Sambuc                 len -= bsize;
126584d9c625SLionel Sambuc         }
126684d9c625SLionel Sambuc 
126784d9c625SLionel Sambuc out:
126884d9c625SLionel Sambuc 	return error;
126984d9c625SLionel Sambuc }
127084d9c625SLionel Sambuc 
127184d9c625SLionel Sambuc void
ulfs_gop_markupdate(struct vnode * vp,int flags)127284d9c625SLionel Sambuc ulfs_gop_markupdate(struct vnode *vp, int flags)
127384d9c625SLionel Sambuc {
127484d9c625SLionel Sambuc 	u_int32_t mask = 0;
127584d9c625SLionel Sambuc 
127684d9c625SLionel Sambuc 	if ((flags & GOP_UPDATE_ACCESSED) != 0) {
127784d9c625SLionel Sambuc 		mask = IN_ACCESS;
127884d9c625SLionel Sambuc 	}
127984d9c625SLionel Sambuc 	if ((flags & GOP_UPDATE_MODIFIED) != 0) {
128084d9c625SLionel Sambuc 		if (vp->v_type == VREG) {
128184d9c625SLionel Sambuc 			mask |= IN_CHANGE | IN_UPDATE;
128284d9c625SLionel Sambuc 		} else {
128384d9c625SLionel Sambuc 			mask |= IN_MODIFY;
128484d9c625SLionel Sambuc 		}
128584d9c625SLionel Sambuc 	}
128684d9c625SLionel Sambuc 	if (mask) {
128784d9c625SLionel Sambuc 		struct inode *ip = VTOI(vp);
128884d9c625SLionel Sambuc 
128984d9c625SLionel Sambuc 		ip->i_flag |= mask;
129084d9c625SLionel Sambuc 	}
129184d9c625SLionel Sambuc }
1292*0a6a1f1dSLionel Sambuc 
1293*0a6a1f1dSLionel Sambuc int
ulfs_bufio(enum uio_rw rw,struct vnode * vp,void * buf,size_t len,off_t off,int ioflg,kauth_cred_t cred,size_t * aresid,struct lwp * l)1294*0a6a1f1dSLionel Sambuc ulfs_bufio(enum uio_rw rw, struct vnode *vp, void *buf, size_t len, off_t off,
1295*0a6a1f1dSLionel Sambuc     int ioflg, kauth_cred_t cred, size_t *aresid, struct lwp *l)
1296*0a6a1f1dSLionel Sambuc {
1297*0a6a1f1dSLionel Sambuc 	struct iovec iov;
1298*0a6a1f1dSLionel Sambuc 	struct uio uio;
1299*0a6a1f1dSLionel Sambuc 	int error;
1300*0a6a1f1dSLionel Sambuc 
1301*0a6a1f1dSLionel Sambuc 	KASSERT(ISSET(ioflg, IO_NODELOCKED));
1302*0a6a1f1dSLionel Sambuc 	KASSERT(VOP_ISLOCKED(vp));
1303*0a6a1f1dSLionel Sambuc 	KASSERT(rw != UIO_WRITE || VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
1304*0a6a1f1dSLionel Sambuc 
1305*0a6a1f1dSLionel Sambuc 	iov.iov_base = buf;
1306*0a6a1f1dSLionel Sambuc 	iov.iov_len = len;
1307*0a6a1f1dSLionel Sambuc 	uio.uio_iov = &iov;
1308*0a6a1f1dSLionel Sambuc 	uio.uio_iovcnt = 1;
1309*0a6a1f1dSLionel Sambuc 	uio.uio_resid = len;
1310*0a6a1f1dSLionel Sambuc 	uio.uio_offset = off;
1311*0a6a1f1dSLionel Sambuc 	uio.uio_rw = rw;
1312*0a6a1f1dSLionel Sambuc 	UIO_SETUP_SYSSPACE(&uio);
1313*0a6a1f1dSLionel Sambuc 
1314*0a6a1f1dSLionel Sambuc 	switch (rw) {
1315*0a6a1f1dSLionel Sambuc 	case UIO_READ:
1316*0a6a1f1dSLionel Sambuc 		error = lfs_bufrd(vp, &uio, ioflg, cred);
1317*0a6a1f1dSLionel Sambuc 		break;
1318*0a6a1f1dSLionel Sambuc 	case UIO_WRITE:
1319*0a6a1f1dSLionel Sambuc 		error = lfs_bufwr(vp, &uio, ioflg, cred);
1320*0a6a1f1dSLionel Sambuc 		break;
1321*0a6a1f1dSLionel Sambuc 	default:
1322*0a6a1f1dSLionel Sambuc 		panic("invalid uio rw: %d", (int)rw);
1323*0a6a1f1dSLionel Sambuc 	}
1324*0a6a1f1dSLionel Sambuc 
1325*0a6a1f1dSLionel Sambuc 	if (aresid)
1326*0a6a1f1dSLionel Sambuc 		*aresid = uio.uio_resid;
1327*0a6a1f1dSLionel Sambuc 	else if (uio.uio_resid && error == 0)
1328*0a6a1f1dSLionel Sambuc 		error = EIO;
1329*0a6a1f1dSLionel Sambuc 
1330*0a6a1f1dSLionel Sambuc 	KASSERT(VOP_ISLOCKED(vp));
1331*0a6a1f1dSLionel Sambuc 	KASSERT(rw != UIO_WRITE || VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
1332*0a6a1f1dSLionel Sambuc 	return error;
1333*0a6a1f1dSLionel Sambuc }
1334