Home | History | Annotate | Line # | Download | only in genfs
genfs_rename.c revision 1.5
      1 /*	$NetBSD: genfs_rename.c,v 1.5 2020/09/05 02:47:03 riastradh Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2012 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * This code is derived from software contributed to The NetBSD Foundation
      8  * by Taylor R Campbell.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted provided that the following conditions
     12  * are met:
     13  * 1. Redistributions of source code must retain the above copyright
     14  *    notice, this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright
     16  *    notice, this list of conditions and the following disclaimer in the
     17  *    documentation and/or other materials provided with the distribution.
     18  *
     19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  * POSSIBILITY OF SUCH DAMAGE.
     30  */
     31 
     32 /*
     33  * Generic rename abstraction.
     34  *
     35  * Rename is unbelievably hairy.  Try to use this if you can --
     36  * otherwise you are practically guaranteed to get it wrong.
     37  */
     38 
     39 #include <sys/cdefs.h>
     40 __KERNEL_RCSID(0, "$NetBSD: genfs_rename.c,v 1.5 2020/09/05 02:47:03 riastradh Exp $");
     41 
     42 #include <sys/param.h>
     43 #include <sys/kauth.h>
     44 #include <sys/mount.h>
     45 #include <sys/namei.h>
     46 #include <sys/stat.h>
     47 #include <sys/vnode.h>
     48 #include <sys/types.h>
     49 
     50 #include <miscfs/genfs/genfs.h>
     51 
     52 /*
     53  * Sample copypasta for implementing VOP_RENAME via genfs_rename.
     54  * Don't change this template without carefully considering whether
     55  * every other file system that already uses it needs to change too.
     56  * That way, once we have changed all the file systems to use it, we
     57  * can easily replace mumblefs_rename by mumblefs_sane_rename and
     58  * eliminate the insane API altogether.
     59  */
     60 
     61 /* begin sample copypasta */
     62 #if 0
     63 
     64 static const struct genfs_rename_ops mumblefs_genfs_rename_ops;
     65 
     66 /*
     67  * mumblefs_sane_rename: The hairiest vop, with the saner API.
     68  *
     69  * Arguments:
     70  *
     71  * . fdvp (from directory vnode),
     72  * . fcnp (from component name),
     73  * . tdvp (to directory vnode),
     74  * . tcnp (to component name),
     75  * . cred (credentials structure), and
     76  * . posixly_correct (flag for behaviour if target & source link same file).
     77  *
     78  * fdvp and tdvp may be the same, and must be referenced and unlocked.
     79  */
     80 static int
     81 mumblefs_sane_rename(
     82     struct vnode *fdvp, struct componentname *fcnp,
     83     struct vnode *tdvp, struct componentname *tcnp,
     84     kauth_cred_t cred, bool posixly_correct)
     85 {
     86 	struct mumblefs_lookup_results fulr, tulr;
     87 
     88 	return genfs_sane_rename(&mumblefs_genfs_rename_ops,
     89 	    fdvp, fcnp, &fulr, tdvp, tcnp, &tulr,
     90 	    cred, posixly_correct);
     91 }
     92 
     93 /*
     94  * mumblefs_rename: The hairiest vop, with the insanest API.  Defer to
     95  * genfs_insane_rename immediately.
     96  */
     97 int
     98 mumblefs_rename(void *v)
     99 {
    100 
    101 	return genfs_insane_rename(v, &mumblefs_sane_rename);
    102 }
    103 
    104 #endif
    105 /* end sample copypasta */
    106 
    107 /*
    108  * Forward declarations
    109  */
    110 
    111 static int genfs_rename_enter(const struct genfs_rename_ops *, struct mount *,
    112     kauth_cred_t,
    113     struct vnode *, struct componentname *, void *, struct vnode **,
    114     struct vnode *, struct componentname *, void *, struct vnode **);
    115 static int genfs_rename_enter_common(const struct genfs_rename_ops *,
    116     struct mount *, kauth_cred_t, struct vnode *,
    117     struct componentname *, void *, struct vnode **,
    118     struct componentname *, void *, struct vnode **);
    119 static int genfs_rename_enter_separate(const struct genfs_rename_ops *,
    120     struct mount *, kauth_cred_t,
    121     struct vnode *, struct componentname *, void *, struct vnode **,
    122     struct vnode *, struct componentname *, void *, struct vnode **);
    123 static int genfs_rename_lock(const struct genfs_rename_ops *, struct mount *,
    124     kauth_cred_t, int, int, int,
    125     struct vnode *, struct componentname *, bool, void *, struct vnode **,
    126     struct vnode *, struct componentname *, bool, void *, struct vnode **);
    127 static void genfs_rename_exit(const struct genfs_rename_ops *, struct mount *,
    128     struct vnode *, struct vnode *,
    129     struct vnode *, struct vnode *);
    130 static int genfs_rename_remove(const struct genfs_rename_ops *, struct mount *,
    131     kauth_cred_t,
    132     struct vnode *, struct componentname *, void *, struct vnode *);
    133 
    134 /*
    135  * genfs_insane_rename: Generic implementation of the insane API for
    136  * the rename vop.
    137  *
    138  * Arguments:
    139  *
    140  * . fdvp (from directory vnode),
    141  * . fvp (from vnode),
    142  * . fcnp (from component name),
    143  * . tdvp (to directory vnode),
    144  * . tvp (to vnode, or NULL), and
    145  * . tcnp (to component name).
    146  *
    147  * Any pair of vnode parameters may have the same vnode.
    148  *
    149  * On entry,
    150  *
    151  * . fdvp, fvp, tdvp, and tvp are referenced,
    152  * . fdvp and fvp are unlocked, and
    153  * . tdvp and tvp (if nonnull) are locked.
    154  *
    155  * On exit,
    156  *
    157  * . fdvp, fvp, tdvp, and tvp (if nonnull) are unreferenced, and
    158  * . tdvp and tvp (if nonnull) are unlocked.
    159  */
    160 int
    161 genfs_insane_rename(void *v,
    162     int (*sane_rename)(struct vnode *fdvp, struct componentname *fcnp,
    163 	struct vnode *tdvp, struct componentname *tcnp,
    164 	kauth_cred_t cred, bool posixly_correct))
    165 {
    166 	struct vop_rename_args	/* {
    167 		struct vnode *a_fdvp;
    168 		struct vnode *a_fvp;
    169 		struct componentname *a_fcnp;
    170 		struct vnode *a_tdvp;
    171 		struct vnode *a_tvp;
    172 		struct componentname *a_tcnp;
    173 	} */ *ap = v;
    174 	struct vnode *fdvp = ap->a_fdvp;
    175 	struct vnode *fvp = ap->a_fvp;
    176 	struct componentname *fcnp = ap->a_fcnp;
    177 	struct vnode *tdvp = ap->a_tdvp;
    178 	struct vnode *tvp = ap->a_tvp;
    179 	struct componentname *tcnp = ap->a_tcnp;
    180 	kauth_cred_t cred;
    181 	int error;
    182 
    183 	KASSERT(fdvp != NULL);
    184 	KASSERT(fvp != NULL);
    185 	KASSERT(fcnp != NULL);
    186 	KASSERT(fcnp->cn_nameptr != NULL);
    187 	KASSERT(tdvp != NULL);
    188 	KASSERT(tcnp != NULL);
    189 	KASSERT(fcnp->cn_nameptr != NULL);
    190 	/* KASSERT(VOP_ISLOCKED(fdvp) != LK_EXCLUSIVE); */
    191 	/* KASSERT(VOP_ISLOCKED(fvp) != LK_EXCLUSIVE); */
    192 	KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
    193 	KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
    194 	KASSERT(fdvp->v_type == VDIR);
    195 	KASSERT(tdvp->v_type == VDIR);
    196 
    197 	cred = fcnp->cn_cred;
    198 
    199 	/*
    200 	 * XXX Want a better equality test.  `tcnp->cn_cred == cred'
    201 	 * hoses p2k because puffs transmits the creds separately and
    202 	 * allocates distinct but equivalent structures for them.
    203 	 */
    204 	KASSERT(kauth_cred_uidmatch(cred, tcnp->cn_cred));
    205 
    206 	/*
    207 	 * Sanitize our world from the VFS insanity.  Unlock the target
    208 	 * directory and node, which are locked.  Release the children,
    209 	 * which are referenced, since we'll be looking them up again
    210 	 * later.
    211 	 */
    212 
    213 	VOP_UNLOCK(tdvp);
    214 	if ((tvp != NULL) && (tvp != tdvp))
    215 		VOP_UNLOCK(tvp);
    216 
    217 	vrele(fvp);
    218 	if (tvp != NULL)
    219 		vrele(tvp);
    220 
    221 	error = (*sane_rename)(fdvp, fcnp, tdvp, tcnp, cred, false);
    222 
    223 	/*
    224 	 * All done, whether with success or failure.  Release the
    225 	 * directory nodes now, as the caller expects from the VFS
    226 	 * protocol.
    227 	 */
    228 	vrele(fdvp);
    229 	vrele(tdvp);
    230 
    231 	return error;
    232 }
    233 
    234 /*
    235  * genfs_sane_rename: Generic implementation of the saner API for the
    236  * rename vop.  Handles ancestry checks, locking, and permissions
    237  * checks.  Caller is responsible for implementing the genfs rename
    238  * operations.
    239  *
    240  * fdvp and tdvp must be referenced and unlocked.
    241  */
    242 int
    243 genfs_sane_rename(const struct genfs_rename_ops *ops,
    244     struct vnode *fdvp, struct componentname *fcnp, void *fde,
    245     struct vnode *tdvp, struct componentname *tcnp, void *tde,
    246     kauth_cred_t cred, bool posixly_correct)
    247 {
    248 	struct mount *mp;
    249 	struct vnode *fvp = NULL, *tvp = NULL;
    250 	int error;
    251 
    252 	KASSERT(ops != NULL);
    253 	KASSERT(fdvp != NULL);
    254 	KASSERT(fcnp != NULL);
    255 	KASSERT(tdvp != NULL);
    256 	KASSERT(tcnp != NULL);
    257 	/* KASSERT(VOP_ISLOCKED(fdvp) != LK_EXCLUSIVE); */
    258 	/* KASSERT(VOP_ISLOCKED(tdvp) != LK_EXCLUSIVE); */
    259 	KASSERT(fdvp->v_type == VDIR);
    260 	KASSERT(tdvp->v_type == VDIR);
    261 	KASSERT(fdvp->v_mount == tdvp->v_mount);
    262 	KASSERT(fcnp != tcnp);
    263 	KASSERT(fcnp->cn_nameiop == DELETE);
    264 	KASSERT(tcnp->cn_nameiop == RENAME);
    265 
    266         /* XXX Want a better equality test.  */
    267 	KASSERT(kauth_cred_uidmatch(cred, fcnp->cn_cred));
    268 	KASSERT(kauth_cred_uidmatch(cred, tcnp->cn_cred));
    269 
    270 	mp = fdvp->v_mount;
    271 	KASSERT(mp != NULL);
    272 	KASSERT(mp == tdvp->v_mount);
    273 	/* XXX How can we be sure this stays true?  */
    274 	KASSERT((mp->mnt_flag & MNT_RDONLY) == 0);
    275 
    276 	/* Reject rename("x/..", ...) and rename(..., "x/..") early.  */
    277 	if ((fcnp->cn_flags | tcnp->cn_flags) & ISDOTDOT)
    278 		return EINVAL;	/* XXX EISDIR?  */
    279 
    280 	error = genfs_rename_enter(ops, mp, cred,
    281 	    fdvp, fcnp, fde, &fvp,
    282 	    tdvp, tcnp, tde, &tvp);
    283 	if (error)
    284 		return error;
    285 
    286 	/*
    287 	 * Check that everything is locked and looks right.
    288 	 */
    289 	KASSERT(fvp != NULL);
    290 	KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE);
    291 	KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE);
    292 	KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
    293 	KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
    294 
    295 	/*
    296 	 * If the source and destination are the same object, we need
    297 	 * only at most delete the source entry.  We are guaranteed at
    298 	 * this point that the entries are distinct.
    299 	 */
    300 	if (fvp == tvp) {
    301 		KASSERT(tvp != NULL);
    302 		if (fvp->v_type == VDIR)
    303 			/* XXX This shouldn't be possible.  */
    304 			error = EINVAL;
    305 		else if (posixly_correct)
    306 			/* POSIX sez to leave them alone.  */
    307 			error = 0;
    308 		else if ((fdvp == tdvp) &&
    309 		    (fcnp->cn_namelen == tcnp->cn_namelen) &&
    310 		    (memcmp(fcnp->cn_nameptr, tcnp->cn_nameptr,
    311 			fcnp->cn_namelen) == 0))
    312 			/* Renaming an entry over itself does nothing.  */
    313 			error = 0;
    314 		else
    315 			/* XXX Can't use VOP_REMOVE because of locking.  */
    316 			error = genfs_rename_remove(ops, mp, cred,
    317 			    fdvp, fcnp, fde, fvp);
    318 		goto out;
    319 	}
    320 	KASSERT(fvp != tvp);
    321 	KASSERT((fdvp != tdvp) ||
    322 	    (fcnp->cn_namelen != tcnp->cn_namelen) ||
    323 	    (memcmp(fcnp->cn_nameptr, tcnp->cn_nameptr, fcnp->cn_namelen)
    324 		!= 0));
    325 
    326 	/*
    327 	 * If the target exists, refuse to rename a directory over a
    328 	 * non-directory or vice versa, or to clobber a non-empty
    329 	 * directory.
    330 	 */
    331 	if (tvp != NULL) {
    332 		if (fvp->v_type == VDIR && tvp->v_type == VDIR)
    333 			error =
    334 			    (ops->gro_directory_empty_p(mp, cred, tvp, tdvp)?
    335 				0 : ENOTEMPTY);
    336 		else if (fvp->v_type == VDIR && tvp->v_type != VDIR)
    337 			error = ENOTDIR;
    338 		else if (fvp->v_type != VDIR && tvp->v_type == VDIR)
    339 			error = EISDIR;
    340 		else
    341 			error = 0;
    342 		if (error)
    343 			goto out;
    344 		KASSERT((fvp->v_type == VDIR) == (tvp->v_type == VDIR));
    345 	}
    346 
    347 	/*
    348 	 * Authorize the rename.
    349 	 */
    350 	error = ops->gro_rename_check_possible(mp, fdvp, fvp, tdvp, tvp);
    351 	if (error)
    352 		goto out;
    353 	error = ops->gro_rename_check_permitted(mp, cred, fdvp, fvp, tdvp, tvp);
    354 	error = kauth_authorize_vnode(cred, KAUTH_VNODE_DELETE, fvp, fdvp,
    355 	    error);
    356 	error = kauth_authorize_vnode(cred, KAUTH_VNODE_RENAME, tvp, tdvp,
    357 	    error);
    358 	if (error)
    359 		goto out;
    360 
    361 	/*
    362 	 * Everything is hunky-dory.  Shuffle the directory entries.
    363 	 */
    364 	error = ops->gro_rename(mp, cred,
    365 	    fdvp, fcnp, fde, fvp,
    366 	    tdvp, tcnp, tde, tvp);
    367 	if (error)
    368 		goto out;
    369 
    370 	/* Success!  */
    371 
    372 out:	genfs_rename_exit(ops, mp, fdvp, fvp, tdvp, tvp);
    373 	return error;
    374 }
    375 
    376 /*
    377  * genfs_rename_knote: Note events about the various vnodes in a
    378  * rename.  To be called by gro_rename on success.  The only pair of
    379  * vnodes that may be identical is {fdvp, tdvp}.  deleted_p is true iff
    380  * the rename overwrote the last link to tvp.
    381  */
    382 void
    383 genfs_rename_knote(struct vnode *fdvp, struct vnode *fvp,
    384     struct vnode *tdvp, struct vnode *tvp, bool deleted_p)
    385 {
    386 	long fdvp_events, tdvp_events;
    387 	bool directory_p, reparent_p, replaced_p;
    388 
    389 	KASSERT(fdvp != NULL);
    390 	KASSERT(fvp != NULL);
    391 	KASSERT(tdvp != NULL);
    392 	KASSERT(fdvp != fvp);
    393 	KASSERT(fdvp != tvp);
    394 	KASSERT(tdvp != fvp);
    395 	KASSERT(tdvp != tvp);
    396 	KASSERT(fvp != tvp);
    397 	KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE);
    398 	KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE);
    399 	KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
    400 	KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
    401 
    402 	directory_p = (fvp->v_type == VDIR);
    403 	reparent_p = (fdvp != tdvp);
    404 	replaced_p = (tvp != NULL);
    405 
    406 	KASSERT((tvp == NULL) || (directory_p == (tvp->v_type == VDIR)));
    407 	KASSERT(!deleted_p || replaced_p);
    408 
    409 	fdvp_events = NOTE_WRITE;
    410 	if (directory_p && reparent_p)
    411 		fdvp_events |= NOTE_LINK;
    412 	VN_KNOTE(fdvp, fdvp_events);
    413 
    414 	VN_KNOTE(fvp, NOTE_RENAME);
    415 
    416 	if (reparent_p) {
    417 		tdvp_events = NOTE_WRITE;
    418 		if (!replaced_p) {
    419 			tdvp_events |= NOTE_EXTEND;
    420 			if (directory_p)
    421 				tdvp_events |= NOTE_LINK;
    422 		}
    423 		VN_KNOTE(tdvp, tdvp_events);
    424 	}
    425 
    426 	if (replaced_p)
    427 		VN_KNOTE(tvp, (deleted_p? NOTE_DELETE : NOTE_LINK));
    428 }
    429 
    430 /*
    431  * genfs_rename_cache_purge: Purge the name cache.  To be called by
    432  * gro_rename on success.  The only pair of vnodes that may be
    433  * identical is {fdvp, tdvp}.
    434  */
    435 void
    436 genfs_rename_cache_purge(struct vnode *fdvp, struct vnode *fvp,
    437     struct vnode *tdvp, struct vnode *tvp)
    438 {
    439 
    440 	KASSERT(fdvp != NULL);
    441 	KASSERT(fvp != NULL);
    442 	KASSERT(tdvp != NULL);
    443 	KASSERT(fdvp != fvp);
    444 	KASSERT(fdvp != tvp);
    445 	KASSERT(tdvp != fvp);
    446 	KASSERT(tdvp != tvp);
    447 	KASSERT(fvp != tvp);
    448 	KASSERT(fdvp->v_type == VDIR);
    449 	KASSERT(tdvp->v_type == VDIR);
    450 
    451 	/*
    452 	 * XXX What actually needs to be purged?
    453 	 */
    454 
    455 	cache_purge(fdvp);
    456 
    457 	if (fvp->v_type == VDIR)
    458 		cache_purge(fvp);
    459 
    460 	if (tdvp != fdvp)
    461 		cache_purge(tdvp);
    462 
    463 	if ((tvp != NULL) && (tvp->v_type == VDIR))
    464 		cache_purge(tvp);
    465 }
    466 
    467 /*
    468  * genfs_rename_enter: Look up fcnp in fdvp, and store the lookup
    469  * results in *fde_ret and the associated vnode in *fvp_ret; fail if
    470  * not found.  Look up tcnp in tdvp, and store the lookup results in
    471  * *tde_ret and the associated vnode in *tvp_ret; store null instead if
    472  * not found.  Fail if anything has been mounted on any of the nodes
    473  * involved.
    474  *
    475  * fdvp and tdvp must be referenced.
    476  *
    477  * On entry, nothing is locked.
    478  *
    479  * On success, everything is locked, and *fvp_ret, and *tvp_ret if
    480  * nonnull, are referenced.  The only pairs of vnodes that may be
    481  * identical are {fdvp, tdvp} and {fvp, tvp}.
    482  *
    483  * On failure, everything remains as was.
    484  *
    485  * Locking everything including the source and target nodes is
    486  * necessary to make sure that, e.g., link count updates are OK.  The
    487  * locking order is, in general, ancestor-first, matching the order you
    488  * need to use to look up a descendant anyway.
    489  */
    490 static int
    491 genfs_rename_enter(const struct genfs_rename_ops *ops,
    492     struct mount *mp, kauth_cred_t cred,
    493     struct vnode *fdvp, struct componentname *fcnp,
    494     void *fde_ret, struct vnode **fvp_ret,
    495     struct vnode *tdvp, struct componentname *tcnp,
    496     void *tde_ret, struct vnode **tvp_ret)
    497 {
    498 	int error;
    499 
    500 	KASSERT(mp != NULL);
    501 	KASSERT(fdvp != NULL);
    502 	KASSERT(fcnp != NULL);
    503 	KASSERT(fvp_ret != NULL);
    504 	KASSERT(tdvp != NULL);
    505 	KASSERT(tcnp != NULL);
    506 	KASSERT(tvp_ret != NULL);
    507 	KASSERT(fvp_ret != tvp_ret);
    508 	KASSERT(fdvp->v_type == VDIR);
    509 	KASSERT(tdvp->v_type == VDIR);
    510 	KASSERT(fdvp->v_mount == mp);
    511 	KASSERT(tdvp->v_mount == mp);
    512 
    513 	if (fdvp == tdvp)
    514 		error = genfs_rename_enter_common(ops, mp, cred, fdvp,
    515 		    fcnp, fde_ret, fvp_ret,
    516 		    tcnp, tde_ret, tvp_ret);
    517 	else
    518 		error = genfs_rename_enter_separate(ops, mp, cred,
    519 		    fdvp, fcnp, fde_ret, fvp_ret,
    520 		    tdvp, tcnp, tde_ret, tvp_ret);
    521 
    522 	if (error)
    523 		return error;
    524 
    525 	KASSERT(*fvp_ret != NULL);
    526 	KASSERT(VOP_ISLOCKED(*fvp_ret) == LK_EXCLUSIVE);
    527 	KASSERT((*tvp_ret == NULL) || (VOP_ISLOCKED(*tvp_ret) == LK_EXCLUSIVE));
    528 	KASSERT(*fvp_ret != fdvp);
    529 	KASSERT(*fvp_ret != tdvp);
    530 	KASSERT(*tvp_ret != fdvp);
    531 	KASSERT(*tvp_ret != tdvp);
    532 	return 0;
    533 }
    534 
    535 /*
    536  * genfs_rename_enter_common: Lock and look up with a common
    537  * source/target directory.
    538  */
    539 static int
    540 genfs_rename_enter_common(const struct genfs_rename_ops *ops,
    541     struct mount *mp, kauth_cred_t cred, struct vnode *dvp,
    542     struct componentname *fcnp,
    543     void *fde_ret, struct vnode **fvp_ret,
    544     struct componentname *tcnp,
    545     void *tde_ret, struct vnode **tvp_ret)
    546 {
    547 	struct vnode *fvp, *tvp;
    548 	int error;
    549 
    550 	KASSERT(ops != NULL);
    551 	KASSERT(mp != NULL);
    552 	KASSERT(dvp != NULL);
    553 	KASSERT(fcnp != NULL);
    554 	KASSERT(fvp_ret != NULL);
    555 	KASSERT(tcnp != NULL);
    556 	KASSERT(tvp_ret != NULL);
    557 	KASSERT(dvp->v_type == VDIR);
    558 	KASSERT(dvp->v_mount == mp);
    559 
    560 	error = ops->gro_lock_directory(mp, dvp);
    561 	if (error)
    562 		goto fail0;
    563 
    564 	/* Did we lose a race with mount?  */
    565 	if (dvp->v_mountedhere != NULL) {
    566 		error = EBUSY;
    567 		goto fail1;
    568 	}
    569 
    570 	KASSERT(fcnp->cn_nameiop == DELETE);
    571 	error = ops->gro_lookup(mp, dvp, fcnp, fde_ret, &fvp);
    572 	if (error)
    573 		goto fail1;
    574 
    575 	KASSERT(fvp != NULL);
    576 
    577 	/* Refuse to rename `.'.  */
    578 	if (fvp == dvp) {
    579 		error = EINVAL;
    580 		goto fail2;
    581 	}
    582 	KASSERT(fvp != dvp);
    583 
    584 	KASSERT(tcnp->cn_nameiop == RENAME);
    585 	error = ops->gro_lookup(mp, dvp, tcnp, tde_ret, &tvp);
    586 	if (error == ENOENT) {
    587 		tvp = NULL;
    588 	} else if (error) {
    589 		goto fail2;
    590 	} else {
    591 		KASSERT(tvp != NULL);
    592 
    593 		/* Refuse to rename over `.'.  */
    594 		if (tvp == dvp) {
    595 			error = EISDIR; /* XXX EINVAL?  */
    596 			goto fail2;
    597 		}
    598 	}
    599 	KASSERT(tvp != dvp);
    600 
    601 	/*
    602 	 * We've looked up both nodes.  Now lock them and check them.
    603 	 */
    604 
    605 	vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY);
    606 	KASSERT(fvp->v_mount == mp);
    607 	/* Refuse to rename a mount point.  */
    608 	if ((fvp->v_type == VDIR) && (fvp->v_mountedhere != NULL)) {
    609 		error = EBUSY;
    610 		goto fail3;
    611 	}
    612 
    613 	if ((tvp != NULL) && (tvp != fvp)) {
    614 		vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY);
    615 		KASSERT(tvp->v_mount == mp);
    616 		/* Refuse to rename over a mount point.  */
    617 		if ((tvp->v_type == VDIR) && (tvp->v_mountedhere != NULL)) {
    618 			error = EBUSY;
    619 			goto fail4;
    620 		}
    621 	}
    622 
    623 	KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
    624 	KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE);
    625 	KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
    626 
    627 	*fvp_ret = fvp;
    628 	*tvp_ret = tvp;
    629 	return 0;
    630 
    631 fail4:	if ((tvp != NULL) && (tvp != fvp))
    632 		VOP_UNLOCK(tvp);
    633 fail3:	VOP_UNLOCK(fvp);
    634 	if (tvp != NULL)
    635 		vrele(tvp);
    636 fail2:	vrele(fvp);
    637 fail1:	VOP_UNLOCK(dvp);
    638 fail0:	return error;
    639 }
    640 
    641 /*
    642  * genfs_rename_enter_separate: Lock and look up with separate source
    643  * and target directories.
    644  */
    645 static int
    646 genfs_rename_enter_separate(const struct genfs_rename_ops *ops,
    647     struct mount *mp, kauth_cred_t cred,
    648     struct vnode *fdvp, struct componentname *fcnp,
    649     void *fde_ret, struct vnode **fvp_ret,
    650     struct vnode *tdvp, struct componentname *tcnp,
    651     void *tde_ret, struct vnode **tvp_ret)
    652 {
    653 	struct vnode *intermediate_node;
    654 	struct vnode *fvp, *tvp;
    655 	int error;
    656 
    657 	KASSERT(ops != NULL);
    658 	KASSERT(mp != NULL);
    659 	KASSERT(fdvp != NULL);
    660 	KASSERT(fcnp != NULL);
    661 	KASSERT(fvp_ret != NULL);
    662 	KASSERT(tdvp != NULL);
    663 	KASSERT(tcnp != NULL);
    664 	KASSERT(tvp_ret != NULL);
    665 	KASSERT(fdvp != tdvp);
    666 	KASSERT(fcnp != tcnp);
    667 	KASSERT(fcnp->cn_nameiop == DELETE);
    668 	KASSERT(tcnp->cn_nameiop == RENAME);
    669 	KASSERT(fvp_ret != tvp_ret);
    670 	KASSERT(fdvp->v_type == VDIR);
    671 	KASSERT(tdvp->v_type == VDIR);
    672 	KASSERT(fdvp->v_mount == mp);
    673 	KASSERT(tdvp->v_mount == mp);
    674 
    675 	error = ops->gro_genealogy(mp, cred, fdvp, tdvp, &intermediate_node);
    676 	if (error)
    677 		return error;
    678 
    679 	/*
    680 	 * intermediate_node == NULL means fdvp is not an ancestor of tdvp.
    681 	 */
    682 	if (intermediate_node == NULL)
    683 		error = genfs_rename_lock(ops, mp, cred,
    684 		    ENOTEMPTY, EISDIR, EINVAL,
    685 		    tdvp, tcnp, true, tde_ret, &tvp,
    686 		    fdvp, fcnp, false, fde_ret, &fvp);
    687 	else
    688 		error = genfs_rename_lock(ops, mp, cred,
    689 		    EINVAL, EISDIR, EINVAL,
    690 		    fdvp, fcnp, false, fde_ret, &fvp,
    691 		    tdvp, tcnp, true, tde_ret, &tvp);
    692 	if (error)
    693 		goto out;
    694 
    695 	KASSERT(fvp != NULL);
    696 
    697 	/*
    698 	 * Reject rename("foo/bar", "foo/bar/baz/quux/zot").
    699 	 */
    700 	if (fvp == intermediate_node) {
    701 		genfs_rename_exit(ops, mp, fdvp, fvp, tdvp, tvp);
    702 		error = EINVAL;
    703 		goto out;
    704 	}
    705 
    706 	*fvp_ret = fvp;
    707 	*tvp_ret = tvp;
    708 	error = 0;
    709 
    710 out:	if (intermediate_node != NULL)
    711 		vrele(intermediate_node);
    712 	return error;
    713 }
    714 
    715 /*
    716  * genfs_rename_lock: Lookup and lock it all.  The lock order is:
    717  *
    718  *	a_dvp -> a_vp -> b_dvp -> b_vp,
    719  *
    720  * except if a_vp is a nondirectory in which case the lock order is:
    721  *
    722  *	a_dvp -> b_dvp -> b_vp -> a_vp,
    723  *
    724  * which can't violate ancestor->descendant because a_vp has no
    725  * descendants in this case.  This edge case is necessary because some
    726  * file systems can only lookup/lock/unlock, and we can't hold a_vp
    727  * locked when we lookup/lock/unlock b_vp if they turn out to be the
    728  * same, and we can't find out that they're the same until after the
    729  * lookup.
    730  *
    731  * b_dvp must not be an ancestor of a_dvp, although a_dvp may be an
    732  * ancestor of b_dvp.
    733  *
    734  * Fail with overlap_error if node a is directory b.  Neither
    735  * componentname may be `.' or `..'.
    736  *
    737  * a_dvp and b_dvp must be referenced.
    738  *
    739  * On entry, a_dvp and b_dvp are unlocked.
    740  *
    741  * On success,
    742  * . a_dvp and b_dvp are locked,
    743  * . *a_dirent_ret is filled with a directory entry whose node is
    744  *     locked and referenced,
    745  * . *b_vp_ret is filled with the corresponding vnode,
    746  * . *b_dirent_ret is filled either with null or with a directory entry
    747  *     whose node is locked and referenced,
    748  * . *b_vp is filled either with null or with the corresponding vnode,
    749  *     and
    750  * . the only pair of vnodes that may be identical is a_vp and b_vp.
    751  *
    752  * On failure, a_dvp and b_dvp are left unlocked, and *a_dirent_ret,
    753  * *a_vp, *b_dirent_ret, and *b_vp are left alone.
    754  */
    755 static int
    756 genfs_rename_lock(const struct genfs_rename_ops *ops,
    757     struct mount *mp, kauth_cred_t cred,
    758     int overlap_error, int a_dot_error, int b_dot_error,
    759     struct vnode *a_dvp, struct componentname *a_cnp, bool a_missing_ok,
    760     void *a_de_ret, struct vnode **a_vp_ret,
    761     struct vnode *b_dvp, struct componentname *b_cnp, bool b_missing_ok,
    762     void *b_de_ret, struct vnode **b_vp_ret)
    763 {
    764 	struct vnode *a_vp, *b_vp;
    765 	int error;
    766 
    767 	KASSERT(ops != NULL);
    768 	KASSERT(mp != NULL);
    769 	KASSERT(a_dvp != NULL);
    770 	KASSERT(a_cnp != NULL);
    771 	KASSERT(a_vp_ret != NULL);
    772 	KASSERT(b_dvp != NULL);
    773 	KASSERT(b_cnp != NULL);
    774 	KASSERT(b_vp_ret != NULL);
    775 	KASSERT(a_dvp != b_dvp);
    776 	KASSERT(a_vp_ret != b_vp_ret);
    777 	KASSERT(a_dvp->v_type == VDIR);
    778 	KASSERT(b_dvp->v_type == VDIR);
    779 	KASSERT(a_dvp->v_mount == mp);
    780 	KASSERT(b_dvp->v_mount == mp);
    781 	KASSERT(a_missing_ok != b_missing_ok);
    782 
    783 	/*
    784 	 * 1. Lock a_dvp.
    785 	 */
    786 	error = ops->gro_lock_directory(mp, a_dvp);
    787 	if (error)
    788 		goto fail0;
    789 
    790 	/* Did we lose a race with mount?  */
    791 	if (a_dvp->v_mountedhere != NULL) {
    792 		error = EBUSY;
    793 		goto fail1;
    794 	}
    795 
    796 	/*
    797 	 * 2. Lookup a_vp.  May lock/unlock a_vp.
    798 	 */
    799 	error = ops->gro_lookup(mp, a_dvp, a_cnp, a_de_ret, &a_vp);
    800 	if (error) {
    801 		if (a_missing_ok && (error == ENOENT))
    802 			a_vp = NULL;
    803 		else
    804 			goto fail1;
    805 	} else {
    806 		KASSERT(a_vp != NULL);
    807 
    808 		/* Refuse to rename (over) `.'.  */
    809 		if (a_vp == a_dvp) {
    810 			error = a_dot_error;
    811 			goto fail2;
    812 		}
    813 
    814 		/* Reject rename("x", "x/y") or rename("x/y", "x").  */
    815 		if (a_vp == b_dvp) {
    816 			error = overlap_error;
    817 			goto fail2;
    818 		}
    819 	}
    820 
    821 	KASSERT(a_vp != a_dvp);
    822 	KASSERT(a_vp != b_dvp);
    823 
    824 	/*
    825 	 * 3. Lock a_vp, if it is a directory.
    826 	 *
    827 	 * We already ruled out a_vp == a_dvp (i.e., a_cnp is `.'), so
    828 	 * this is not locking against self, and we already ruled out
    829 	 * a_vp == b_dvp, so this won't cause subsequent locking of
    830 	 * b_dvp to lock against self.
    831 	 *
    832 	 * If a_vp is a nondirectory, we can't hold it when we lookup
    833 	 * b_vp in case (a) the file system can only lookup/lock/unlock
    834 	 * and (b) b_vp turns out to be the same file as a_vp due to
    835 	 * hard links -- and we can't even detect that case until after
    836 	 * we've looked up b_vp.  Fortunately, if a_vp is a
    837 	 * nondirectory, then it is a leaf, so we can safely lock it
    838 	 * last.
    839 	 */
    840 	if (a_vp != NULL && a_vp->v_type == VDIR) {
    841 		vn_lock(a_vp, LK_EXCLUSIVE | LK_RETRY);
    842 		KASSERT(a_vp->v_mount == mp);
    843 		/* Refuse to rename (over) a mount point.  */
    844 		if (a_vp->v_mountedhere != NULL) {
    845 			error = EBUSY;
    846 			goto fail3;
    847 		}
    848 	}
    849 
    850 	/*
    851 	 * 4. Lock b_dvp.
    852 	 */
    853 	error = ops->gro_lock_directory(mp, b_dvp);
    854 	if (error)
    855 		goto fail3;
    856 
    857 	/* Did we lose a race with mount?  */
    858 	if (b_dvp->v_mountedhere != NULL) {
    859 		error = EBUSY;
    860 		goto fail4;
    861 	}
    862 
    863 	/*
    864 	 * 5. Lookup b_vp.  May lock/unlock b_vp.
    865 	 */
    866 	error = ops->gro_lookup(mp, b_dvp, b_cnp, b_de_ret, &b_vp);
    867 	if (error) {
    868 		if (b_missing_ok && (error == ENOENT))
    869 			b_vp = NULL;
    870 		else
    871 			goto fail4;
    872 	} else {
    873 		KASSERT(b_vp != NULL);
    874 
    875 		/* Refuse to rename (over) `.'.  */
    876 		if (b_vp == b_dvp) {
    877 			error = b_dot_error;
    878 			goto fail5;
    879 		}
    880 
    881 		/*
    882 		 * b_dvp must not be an ancestor of a_dvp, so if we
    883 		 * find b_dvp/b_vp=a_dvp/a_vp something is wrong.
    884 		 */
    885 		if (b_vp == a_dvp) {
    886 			/*
    887 			 * We have a directory hard link before us.
    888 			 * XXX What error should this return?  EDEADLK?
    889 			 * Panic?
    890 			 */
    891 			error = EIO;
    892 			goto fail5;
    893 		}
    894 	}
    895 	KASSERT(b_vp != b_dvp);
    896 	KASSERT(b_vp != a_dvp);
    897 
    898 	/*
    899 	 * 6. Lock a_vp, if it is a nondirectory.
    900 	 *
    901 	 * In this case a_vp is a leaf, so it is either equal to or
    902 	 * incommensurate with b_vp, and so we can safely lock it at
    903 	 * any point now.
    904 	 */
    905 	if (a_vp != NULL && a_vp->v_type != VDIR) {
    906 		vn_lock(a_vp, LK_EXCLUSIVE | LK_RETRY);
    907 		KASSERT(a_vp->v_mount == mp);
    908 		/* (not a directory so can't have anything mounted here) */
    909 	}
    910 
    911 	/*
    912 	 * 7. Lock b_vp, if it is not a_vp.
    913 	 *
    914 	 * b_vp and a_vp may the same inode if they are hard links to
    915 	 * one another.
    916 	 */
    917 	if ((b_vp != NULL) && (b_vp != a_vp)) {
    918 		vn_lock(b_vp, LK_EXCLUSIVE | LK_RETRY);
    919 		KASSERT(b_vp->v_mount == mp);
    920 		/* Refuse to rename (over) a mount point.  */
    921 		if ((b_vp->v_type == VDIR) && (b_vp->v_mountedhere != NULL)) {
    922 			error = EBUSY;
    923 			goto fail6;
    924 		}
    925 	}
    926 
    927 	KASSERT(VOP_ISLOCKED(a_dvp) == LK_EXCLUSIVE);
    928 	KASSERT(VOP_ISLOCKED(b_dvp) == LK_EXCLUSIVE);
    929 	KASSERT(a_missing_ok || (a_vp != NULL));
    930 	KASSERT(b_missing_ok || (b_vp != NULL));
    931 	KASSERT((a_vp == NULL) || (VOP_ISLOCKED(a_vp) == LK_EXCLUSIVE));
    932 	KASSERT((b_vp == NULL) || (VOP_ISLOCKED(b_vp) == LK_EXCLUSIVE));
    933 
    934 	*a_vp_ret = a_vp;
    935 	*b_vp_ret = b_vp;
    936 	return 0;
    937 
    938 fail6:	if ((b_vp != NULL) && (b_vp != a_vp))
    939 		VOP_UNLOCK(b_vp);
    940 	if (a_vp != NULL && a_vp->v_type != VDIR)
    941 		VOP_UNLOCK(a_vp);
    942 fail5:	if (b_vp != NULL)
    943 		vrele(b_vp);
    944 fail4:	VOP_UNLOCK(b_dvp);
    945 fail3:	if (a_vp != NULL && a_vp->v_type == VDIR)
    946 		VOP_UNLOCK(a_vp);
    947 fail2:	if (a_vp != NULL)
    948 		vrele(a_vp);
    949 fail1:	VOP_UNLOCK(a_dvp);
    950 fail0:	return error;
    951 }
    952 
    953 /*
    954  * genfs_rename_exit: Unlock everything we locked for rename.
    955  *
    956  * fdvp and tdvp must be referenced.
    957  *
    958  * On entry, everything is locked, and fvp and tvp referenced.
    959  *
    960  * On exit, everything is unlocked, and fvp and tvp are released.
    961  */
    962 static void
    963 genfs_rename_exit(const struct genfs_rename_ops *ops,
    964     struct mount *mp,
    965     struct vnode *fdvp, struct vnode *fvp,
    966     struct vnode *tdvp, struct vnode *tvp)
    967 {
    968 
    969 	(void)ops;
    970 	KASSERT(ops != NULL);
    971 	KASSERT(mp != NULL);
    972 	KASSERT(fdvp != NULL);
    973 	KASSERT(fvp != NULL);
    974 	KASSERT(fdvp != fvp);
    975 	KASSERT(fdvp != tvp);
    976 	KASSERT(tdvp != tvp);
    977 	KASSERT(tdvp != fvp);
    978 	KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE);
    979 	KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
    980 	KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE);
    981 	KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
    982 
    983 	if ((tvp != NULL) && (tvp != fvp))
    984 		VOP_UNLOCK(tvp);
    985 	VOP_UNLOCK(fvp);
    986 	if (tvp != NULL)
    987 		vrele(tvp);
    988 	if (tdvp != fdvp)
    989 		VOP_UNLOCK(tdvp);
    990 	vrele(fvp);
    991 	VOP_UNLOCK(fdvp);
    992 }
    993 
    994 /*
    995  * genfs_rename_remove: Remove the entry for the non-directory vp with
    996  * componentname cnp from the directory dvp, using the lookup results
    997  * de.  It is the responsibility of gro_remove to purge the name cache
    998  * and note kevents.
    999  *
   1000  * Everything must be locked and referenced.
   1001  */
   1002 static int
   1003 genfs_rename_remove(const struct genfs_rename_ops *ops,
   1004     struct mount *mp, kauth_cred_t cred,
   1005     struct vnode *dvp, struct componentname *cnp, void *de, struct vnode *vp)
   1006 {
   1007 	int error;
   1008 
   1009 	KASSERT(ops != NULL);
   1010 	KASSERT(mp != NULL);
   1011 	KASSERT(dvp != NULL);
   1012 	KASSERT(cnp != NULL);
   1013 	KASSERT(vp != NULL);
   1014 	KASSERT(dvp != vp);
   1015 	KASSERT(dvp->v_type == VDIR);
   1016 	KASSERT(vp->v_type != VDIR);
   1017 	KASSERT(dvp->v_mount == mp);
   1018 	KASSERT(vp->v_mount == mp);
   1019 	KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
   1020 	KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
   1021 
   1022 	error = ops->gro_remove_check_possible(mp, dvp, vp);
   1023 	if (error)
   1024 		return error;
   1025 
   1026 	error = ops->gro_remove_check_permitted(mp, cred, dvp, vp);
   1027 	error = kauth_authorize_vnode(cred, KAUTH_VNODE_DELETE, vp, dvp,
   1028 	    error);
   1029 	if (error)
   1030 		return error;
   1031 
   1032 	error = ops->gro_remove(mp, cred, dvp, cnp, de, vp);
   1033 	if (error)
   1034 		return error;
   1035 
   1036 	return 0;
   1037 }
   1038 
   1039 static int
   1040 genfs_ufslike_check_sticky(kauth_cred_t, mode_t, uid_t, struct vnode *, uid_t);
   1041 
   1042 /*
   1043  * genfs_ufslike_rename_check_possible: Check whether a rename is
   1044  * possible independent of credentials, assuming UFS-like inode flag
   1045  * semantics.  clobber_p is true iff the target node already exists.
   1046  */
   1047 int
   1048 genfs_ufslike_rename_check_possible(
   1049     unsigned long fdflags, unsigned long fflags,
   1050     unsigned long tdflags, unsigned long tflags, bool clobber_p,
   1051     unsigned long immutable, unsigned long append)
   1052 {
   1053 
   1054 	if ((fdflags | fflags) & (immutable | append))
   1055 		return EPERM;
   1056 
   1057 	if (tdflags & (immutable | (clobber_p? append : 0)))
   1058 		return EPERM;
   1059 
   1060 	if (clobber_p && (tflags & (immutable | append)))
   1061 		return EPERM;
   1062 
   1063 	return 0;
   1064 }
   1065 
   1066 /*
   1067  * genfs_ufslike_rename_check_permitted: Check whether a rename is
   1068  * permitted given our credentials, assuming UFS-like permission and
   1069  * ownership semantics.
   1070  *
   1071  * The only pair of vnodes that may be identical is {fdvp, tdvp}.
   1072  *
   1073  * Everything must be locked and referenced.
   1074  */
   1075 int
   1076 genfs_ufslike_rename_check_permitted(kauth_cred_t cred,
   1077     struct vnode *fdvp, mode_t fdmode, uid_t fduid,
   1078     struct vnode *fvp, uid_t fuid,
   1079     struct vnode *tdvp, mode_t tdmode, uid_t tduid,
   1080     struct vnode *tvp, uid_t tuid)
   1081 {
   1082 	int error;
   1083 
   1084 	KASSERT(fdvp != NULL);
   1085 	KASSERT(fvp != NULL);
   1086 	KASSERT(tdvp != NULL);
   1087 	KASSERT(fdvp != fvp);
   1088 	KASSERT(fdvp != tvp);
   1089 	KASSERT(tdvp != fvp);
   1090 	KASSERT(tdvp != tvp);
   1091 	KASSERT(fvp != tvp);
   1092 	KASSERT(fdvp->v_type == VDIR);
   1093 	KASSERT(tdvp->v_type == VDIR);
   1094 	KASSERT(fdvp->v_mount == fvp->v_mount);
   1095 	KASSERT(fdvp->v_mount == tdvp->v_mount);
   1096 	KASSERT((tvp == NULL) || (fdvp->v_mount == tvp->v_mount));
   1097 	KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE);
   1098 	KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE);
   1099 	KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
   1100 	KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
   1101 
   1102 	/*
   1103 	 * We need to remove or change an entry in the source directory.
   1104 	 */
   1105 	error = VOP_ACCESS(fdvp, VWRITE, cred);
   1106 	if (error)
   1107 		return error;
   1108 
   1109 	/*
   1110 	 * If we are changing directories, then we need to write to the
   1111 	 * target directory to add or change an entry.  Also, if fvp is
   1112 	 * a directory, we need to write to it to change its `..'
   1113 	 * entry.
   1114 	 */
   1115 	if (fdvp != tdvp) {
   1116 		error = VOP_ACCESS(tdvp, VWRITE, cred);
   1117 		if (error)
   1118 			return error;
   1119 		if (fvp->v_type == VDIR) {
   1120 			error = VOP_ACCESS(fvp, VWRITE, cred);
   1121 			if (error)
   1122 				return error;
   1123 		}
   1124 	}
   1125 
   1126 	error = genfs_ufslike_check_sticky(cred, fdmode, fduid, fvp, fuid);
   1127 	if (error)
   1128 		return error;
   1129 
   1130 	error = genfs_ufslike_check_sticky(cred, tdmode, tduid, tvp, tuid);
   1131 	if (error)
   1132 		return error;
   1133 
   1134 	return 0;
   1135 }
   1136 
   1137 /*
   1138  * genfs_ufslike_remove_check_possible: Check whether a remove is
   1139  * possible independent of credentials, assuming UFS-like inode flag
   1140  * semantics.
   1141  */
   1142 int
   1143 genfs_ufslike_remove_check_possible(unsigned long dflags, unsigned long flags,
   1144     unsigned long immutable, unsigned long append)
   1145 {
   1146 
   1147 	/*
   1148 	 * We want to delete the entry.  If the directory is immutable,
   1149 	 * we can't write to it to delete the entry.  If the directory
   1150 	 * is append-only, the only change we can make is to add
   1151 	 * entries, so we can't delete entries.  If the node is
   1152 	 * immutable, we can't change the links to it, so we can't
   1153 	 * delete the entry.  If the node is append-only...well, this
   1154 	 * is what UFS does.
   1155 	 */
   1156 	if ((dflags | flags) & (immutable | append))
   1157 		return EPERM;
   1158 
   1159 	return 0;
   1160 }
   1161 
   1162 /*
   1163  * genfs_ufslike_remove_check_permitted: Check whether a remove is
   1164  * permitted given our credentials, assuming UFS-like permission and
   1165  * ownership semantics.
   1166  *
   1167  * Everything must be locked and referenced.
   1168  */
   1169 int
   1170 genfs_ufslike_remove_check_permitted(kauth_cred_t cred,
   1171     struct vnode *dvp, mode_t dmode, uid_t duid,
   1172     struct vnode *vp, uid_t uid)
   1173 {
   1174 	int error;
   1175 
   1176 	KASSERT(dvp != NULL);
   1177 	KASSERT(vp != NULL);
   1178 	KASSERT(dvp != vp);
   1179 	KASSERT(dvp->v_type == VDIR);
   1180 	KASSERT(vp->v_type != VDIR);
   1181 	KASSERT(dvp->v_mount == vp->v_mount);
   1182 	KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
   1183 	KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
   1184 
   1185 	/*
   1186 	 * We need to write to the directory to remove from it.
   1187 	 */
   1188 	error = VOP_ACCESS(dvp, VWRITE, cred);
   1189 	if (error)
   1190 		return error;
   1191 
   1192 	error = genfs_ufslike_check_sticky(cred, dmode, duid, vp, uid);
   1193 	if (error)
   1194 		return error;
   1195 
   1196 	return 0;
   1197 }
   1198 
   1199 /*
   1200  * genfs_ufslike_check_sticky: Check whether a party with credentials
   1201  * cred may change an entry in a sticky directory, assuming UFS-like
   1202  * permission, ownership, and stickiness semantics: If the directory is
   1203  * sticky and the entry exists, the user must own either the directory
   1204  * or the entry's node in order to change the entry.
   1205  *
   1206  * Everything must be locked and referenced.
   1207  */
   1208 int
   1209 genfs_ufslike_check_sticky(kauth_cred_t cred, mode_t dmode, uid_t duid,
   1210     struct vnode *vp, uid_t uid)
   1211 {
   1212 
   1213 	if ((dmode & S_ISTXT) && (vp != NULL))
   1214 		return genfs_can_sticky(vp, cred, duid, uid);
   1215 
   1216 	return 0;
   1217 }
   1218