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