Home | History | Annotate | Line # | Download | only in genfs
genfs_rename.c revision 1.6
      1 /*	$NetBSD: genfs_rename.c,v 1.6 2021/10/20 03:08:18 thorpej 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.6 2021/10/20 03:08:18 thorpej 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 *, nlink_t *);
    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 	nlink_t tvp_new_nlink = 0;
    251 	int error;
    252 
    253 	KASSERT(ops != NULL);
    254 	KASSERT(fdvp != NULL);
    255 	KASSERT(fcnp != NULL);
    256 	KASSERT(tdvp != NULL);
    257 	KASSERT(tcnp != NULL);
    258 	/* KASSERT(VOP_ISLOCKED(fdvp) != LK_EXCLUSIVE); */
    259 	/* KASSERT(VOP_ISLOCKED(tdvp) != LK_EXCLUSIVE); */
    260 	KASSERT(fdvp->v_type == VDIR);
    261 	KASSERT(tdvp->v_type == VDIR);
    262 	KASSERT(fdvp->v_mount == tdvp->v_mount);
    263 	KASSERT(fcnp != tcnp);
    264 	KASSERT(fcnp->cn_nameiop == DELETE);
    265 	KASSERT(tcnp->cn_nameiop == RENAME);
    266 
    267         /* XXX Want a better equality test.  */
    268 	KASSERT(kauth_cred_uidmatch(cred, fcnp->cn_cred));
    269 	KASSERT(kauth_cred_uidmatch(cred, tcnp->cn_cred));
    270 
    271 	mp = fdvp->v_mount;
    272 	KASSERT(mp != NULL);
    273 	KASSERT(mp == tdvp->v_mount);
    274 	/* XXX How can we be sure this stays true?  */
    275 	KASSERT((mp->mnt_flag & MNT_RDONLY) == 0);
    276 
    277 	/* Reject rename("x/..", ...) and rename(..., "x/..") early.  */
    278 	if ((fcnp->cn_flags | tcnp->cn_flags) & ISDOTDOT)
    279 		return EINVAL;	/* XXX EISDIR?  */
    280 
    281 	error = genfs_rename_enter(ops, mp, cred,
    282 	    fdvp, fcnp, fde, &fvp,
    283 	    tdvp, tcnp, tde, &tvp);
    284 	if (error)
    285 		return error;
    286 
    287 	/*
    288 	 * Check that everything is locked and looks right.
    289 	 */
    290 	KASSERT(fvp != NULL);
    291 	KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE);
    292 	KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE);
    293 	KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
    294 	KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
    295 
    296 	/*
    297 	 * If the source and destination are the same object, we need
    298 	 * only at most delete the source entry.  We are guaranteed at
    299 	 * this point that the entries are distinct.
    300 	 */
    301 	if (fvp == tvp) {
    302 		KASSERT(tvp != NULL);
    303 		if (fvp->v_type == VDIR)
    304 			/* XXX This shouldn't be possible.  */
    305 			error = EINVAL;
    306 		else if (posixly_correct)
    307 			/* POSIX sez to leave them alone.  */
    308 			error = 0;
    309 		else if ((fdvp == tdvp) &&
    310 		    (fcnp->cn_namelen == tcnp->cn_namelen) &&
    311 		    (memcmp(fcnp->cn_nameptr, tcnp->cn_nameptr,
    312 			fcnp->cn_namelen) == 0))
    313 			/* Renaming an entry over itself does nothing.  */
    314 			error = 0;
    315 		else
    316 			/* XXX Can't use VOP_REMOVE because of locking.  */
    317 			error = genfs_rename_remove(ops, mp, cred,
    318 			    fdvp, fcnp, fde, fvp, &tvp_new_nlink);
    319 		goto out;
    320 	}
    321 	KASSERT(fvp != tvp);
    322 	KASSERT((fdvp != tdvp) ||
    323 	    (fcnp->cn_namelen != tcnp->cn_namelen) ||
    324 	    (memcmp(fcnp->cn_nameptr, tcnp->cn_nameptr, fcnp->cn_namelen)
    325 		!= 0));
    326 
    327 	/*
    328 	 * If the target exists, refuse to rename a directory over a
    329 	 * non-directory or vice versa, or to clobber a non-empty
    330 	 * directory.
    331 	 */
    332 	if (tvp != NULL) {
    333 		if (fvp->v_type == VDIR && tvp->v_type == VDIR)
    334 			error =
    335 			    (ops->gro_directory_empty_p(mp, cred, tvp, tdvp)?
    336 				0 : ENOTEMPTY);
    337 		else if (fvp->v_type == VDIR && tvp->v_type != VDIR)
    338 			error = ENOTDIR;
    339 		else if (fvp->v_type != VDIR && tvp->v_type == VDIR)
    340 			error = EISDIR;
    341 		else
    342 			error = 0;
    343 		if (error)
    344 			goto out;
    345 		KASSERT((fvp->v_type == VDIR) == (tvp->v_type == VDIR));
    346 	}
    347 
    348 	/*
    349 	 * Authorize the rename.
    350 	 */
    351 	error = ops->gro_rename_check_possible(mp, fdvp, fvp, tdvp, tvp);
    352 	if (error)
    353 		goto out;
    354 	error = ops->gro_rename_check_permitted(mp, cred, fdvp, fvp, tdvp, tvp);
    355 	error = kauth_authorize_vnode(cred, KAUTH_VNODE_DELETE, fvp, fdvp,
    356 	    error);
    357 	error = kauth_authorize_vnode(cred, KAUTH_VNODE_RENAME, tvp, tdvp,
    358 	    error);
    359 	if (error)
    360 		goto out;
    361 
    362 	/*
    363 	 * Everything is hunky-dory.  Shuffle the directory entries.
    364 	 */
    365 	error = ops->gro_rename(mp, cred,
    366 	    fdvp, fcnp, fde, fvp,
    367 	    tdvp, tcnp, tde, tvp,
    368 	    &tvp_new_nlink);
    369 	if (error)
    370 		goto out;
    371 
    372 	/* Success!  */
    373 
    374 out:	if (error == 0) {
    375 		genfs_rename_knote(fdvp, fvp, tdvp, tvp, tvp_new_nlink);
    376 	}
    377 	genfs_rename_exit(ops, mp, fdvp, fvp, tdvp, tvp);
    378 	return error;
    379 }
    380 
    381 /*
    382  * genfs_rename_knote: Note events about the various vnodes in a
    383  * rename.  To be called by gro_rename on success.  The only pair of
    384  * vnodes that may be identical is {fdvp, tdvp}.  tvp_new_nlink is
    385  * the resulting link count of tvp.
    386  */
    387 void
    388 genfs_rename_knote(struct vnode *fdvp, struct vnode *fvp,
    389     struct vnode *tdvp, struct vnode *tvp, nlink_t tvp_new_nlink)
    390 {
    391 	long fdvp_events, tdvp_events;
    392 	bool directory_p, reparent_p, replaced_p;
    393 
    394 	KASSERT(fdvp != NULL);
    395 	KASSERT(fvp != NULL);
    396 	KASSERT(tdvp != NULL);
    397 	KASSERT(fdvp != fvp);
    398 	KASSERT(fdvp != tvp);
    399 	KASSERT(tdvp != fvp);
    400 	KASSERT(tdvp != tvp);
    401 	KASSERT(fvp != tvp);
    402 	KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE);
    403 	KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE);
    404 	KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
    405 	KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
    406 
    407 	directory_p = (fvp->v_type == VDIR);
    408 	reparent_p = (fdvp != tdvp);
    409 	replaced_p = (tvp != NULL);
    410 
    411 	KASSERT((tvp == NULL) || (directory_p == (tvp->v_type == VDIR)));
    412 
    413 	fdvp_events = NOTE_WRITE;
    414 	if (directory_p && reparent_p)
    415 		fdvp_events |= NOTE_LINK;
    416 	VN_KNOTE(fdvp, fdvp_events);
    417 
    418 	VN_KNOTE(fvp, NOTE_RENAME);
    419 
    420 	if (reparent_p) {
    421 		tdvp_events = NOTE_WRITE;
    422 		if (!replaced_p) {
    423 			tdvp_events |= NOTE_EXTEND;
    424 			if (directory_p)
    425 				tdvp_events |= NOTE_LINK;
    426 		}
    427 		VN_KNOTE(tdvp, tdvp_events);
    428 	}
    429 
    430 	if (replaced_p)
    431 		VN_KNOTE(tvp, (tvp_new_nlink == 0 ? NOTE_DELETE : NOTE_LINK));
    432 }
    433 
    434 /*
    435  * genfs_rename_cache_purge: Purge the name cache.  To be called by
    436  * gro_rename on success.  The only pair of vnodes that may be
    437  * identical is {fdvp, tdvp}.
    438  */
    439 void
    440 genfs_rename_cache_purge(struct vnode *fdvp, struct vnode *fvp,
    441     struct vnode *tdvp, struct vnode *tvp)
    442 {
    443 
    444 	KASSERT(fdvp != NULL);
    445 	KASSERT(fvp != NULL);
    446 	KASSERT(tdvp != NULL);
    447 	KASSERT(fdvp != fvp);
    448 	KASSERT(fdvp != tvp);
    449 	KASSERT(tdvp != fvp);
    450 	KASSERT(tdvp != tvp);
    451 	KASSERT(fvp != tvp);
    452 	KASSERT(fdvp->v_type == VDIR);
    453 	KASSERT(tdvp->v_type == VDIR);
    454 
    455 	/*
    456 	 * XXX What actually needs to be purged?
    457 	 */
    458 
    459 	cache_purge(fdvp);
    460 
    461 	if (fvp->v_type == VDIR)
    462 		cache_purge(fvp);
    463 
    464 	if (tdvp != fdvp)
    465 		cache_purge(tdvp);
    466 
    467 	if ((tvp != NULL) && (tvp->v_type == VDIR))
    468 		cache_purge(tvp);
    469 }
    470 
    471 /*
    472  * genfs_rename_enter: Look up fcnp in fdvp, and store the lookup
    473  * results in *fde_ret and the associated vnode in *fvp_ret; fail if
    474  * not found.  Look up tcnp in tdvp, and store the lookup results in
    475  * *tde_ret and the associated vnode in *tvp_ret; store null instead if
    476  * not found.  Fail if anything has been mounted on any of the nodes
    477  * involved.
    478  *
    479  * fdvp and tdvp must be referenced.
    480  *
    481  * On entry, nothing is locked.
    482  *
    483  * On success, everything is locked, and *fvp_ret, and *tvp_ret if
    484  * nonnull, are referenced.  The only pairs of vnodes that may be
    485  * identical are {fdvp, tdvp} and {fvp, tvp}.
    486  *
    487  * On failure, everything remains as was.
    488  *
    489  * Locking everything including the source and target nodes is
    490  * necessary to make sure that, e.g., link count updates are OK.  The
    491  * locking order is, in general, ancestor-first, matching the order you
    492  * need to use to look up a descendant anyway.
    493  */
    494 static int
    495 genfs_rename_enter(const struct genfs_rename_ops *ops,
    496     struct mount *mp, kauth_cred_t cred,
    497     struct vnode *fdvp, struct componentname *fcnp,
    498     void *fde_ret, struct vnode **fvp_ret,
    499     struct vnode *tdvp, struct componentname *tcnp,
    500     void *tde_ret, struct vnode **tvp_ret)
    501 {
    502 	int error;
    503 
    504 	KASSERT(mp != NULL);
    505 	KASSERT(fdvp != NULL);
    506 	KASSERT(fcnp != NULL);
    507 	KASSERT(fvp_ret != NULL);
    508 	KASSERT(tdvp != NULL);
    509 	KASSERT(tcnp != NULL);
    510 	KASSERT(tvp_ret != NULL);
    511 	KASSERT(fvp_ret != tvp_ret);
    512 	KASSERT(fdvp->v_type == VDIR);
    513 	KASSERT(tdvp->v_type == VDIR);
    514 	KASSERT(fdvp->v_mount == mp);
    515 	KASSERT(tdvp->v_mount == mp);
    516 
    517 	if (fdvp == tdvp)
    518 		error = genfs_rename_enter_common(ops, mp, cred, fdvp,
    519 		    fcnp, fde_ret, fvp_ret,
    520 		    tcnp, tde_ret, tvp_ret);
    521 	else
    522 		error = genfs_rename_enter_separate(ops, mp, cred,
    523 		    fdvp, fcnp, fde_ret, fvp_ret,
    524 		    tdvp, tcnp, tde_ret, tvp_ret);
    525 
    526 	if (error)
    527 		return error;
    528 
    529 	KASSERT(*fvp_ret != NULL);
    530 	KASSERT(VOP_ISLOCKED(*fvp_ret) == LK_EXCLUSIVE);
    531 	KASSERT((*tvp_ret == NULL) || (VOP_ISLOCKED(*tvp_ret) == LK_EXCLUSIVE));
    532 	KASSERT(*fvp_ret != fdvp);
    533 	KASSERT(*fvp_ret != tdvp);
    534 	KASSERT(*tvp_ret != fdvp);
    535 	KASSERT(*tvp_ret != tdvp);
    536 	return 0;
    537 }
    538 
    539 /*
    540  * genfs_rename_enter_common: Lock and look up with a common
    541  * source/target directory.
    542  */
    543 static int
    544 genfs_rename_enter_common(const struct genfs_rename_ops *ops,
    545     struct mount *mp, kauth_cred_t cred, struct vnode *dvp,
    546     struct componentname *fcnp,
    547     void *fde_ret, struct vnode **fvp_ret,
    548     struct componentname *tcnp,
    549     void *tde_ret, struct vnode **tvp_ret)
    550 {
    551 	struct vnode *fvp, *tvp;
    552 	int error;
    553 
    554 	KASSERT(ops != NULL);
    555 	KASSERT(mp != NULL);
    556 	KASSERT(dvp != NULL);
    557 	KASSERT(fcnp != NULL);
    558 	KASSERT(fvp_ret != NULL);
    559 	KASSERT(tcnp != NULL);
    560 	KASSERT(tvp_ret != NULL);
    561 	KASSERT(dvp->v_type == VDIR);
    562 	KASSERT(dvp->v_mount == mp);
    563 
    564 	error = ops->gro_lock_directory(mp, dvp);
    565 	if (error)
    566 		goto fail0;
    567 
    568 	/* Did we lose a race with mount?  */
    569 	if (dvp->v_mountedhere != NULL) {
    570 		error = EBUSY;
    571 		goto fail1;
    572 	}
    573 
    574 	KASSERT(fcnp->cn_nameiop == DELETE);
    575 	error = ops->gro_lookup(mp, dvp, fcnp, fde_ret, &fvp);
    576 	if (error)
    577 		goto fail1;
    578 
    579 	KASSERT(fvp != NULL);
    580 
    581 	/* Refuse to rename `.'.  */
    582 	if (fvp == dvp) {
    583 		error = EINVAL;
    584 		goto fail2;
    585 	}
    586 	KASSERT(fvp != dvp);
    587 
    588 	KASSERT(tcnp->cn_nameiop == RENAME);
    589 	error = ops->gro_lookup(mp, dvp, tcnp, tde_ret, &tvp);
    590 	if (error == ENOENT) {
    591 		tvp = NULL;
    592 	} else if (error) {
    593 		goto fail2;
    594 	} else {
    595 		KASSERT(tvp != NULL);
    596 
    597 		/* Refuse to rename over `.'.  */
    598 		if (tvp == dvp) {
    599 			error = EISDIR; /* XXX EINVAL?  */
    600 			goto fail2;
    601 		}
    602 	}
    603 	KASSERT(tvp != dvp);
    604 
    605 	/*
    606 	 * We've looked up both nodes.  Now lock them and check them.
    607 	 */
    608 
    609 	vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY);
    610 	KASSERT(fvp->v_mount == mp);
    611 	/* Refuse to rename a mount point.  */
    612 	if ((fvp->v_type == VDIR) && (fvp->v_mountedhere != NULL)) {
    613 		error = EBUSY;
    614 		goto fail3;
    615 	}
    616 
    617 	if ((tvp != NULL) && (tvp != fvp)) {
    618 		vn_lock(tvp, LK_EXCLUSIVE | LK_RETRY);
    619 		KASSERT(tvp->v_mount == mp);
    620 		/* Refuse to rename over a mount point.  */
    621 		if ((tvp->v_type == VDIR) && (tvp->v_mountedhere != NULL)) {
    622 			error = EBUSY;
    623 			goto fail4;
    624 		}
    625 	}
    626 
    627 	KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
    628 	KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE);
    629 	KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
    630 
    631 	*fvp_ret = fvp;
    632 	*tvp_ret = tvp;
    633 	return 0;
    634 
    635 fail4:	if ((tvp != NULL) && (tvp != fvp))
    636 		VOP_UNLOCK(tvp);
    637 fail3:	VOP_UNLOCK(fvp);
    638 	if (tvp != NULL)
    639 		vrele(tvp);
    640 fail2:	vrele(fvp);
    641 fail1:	VOP_UNLOCK(dvp);
    642 fail0:	return error;
    643 }
    644 
    645 /*
    646  * genfs_rename_enter_separate: Lock and look up with separate source
    647  * and target directories.
    648  */
    649 static int
    650 genfs_rename_enter_separate(const struct genfs_rename_ops *ops,
    651     struct mount *mp, kauth_cred_t cred,
    652     struct vnode *fdvp, struct componentname *fcnp,
    653     void *fde_ret, struct vnode **fvp_ret,
    654     struct vnode *tdvp, struct componentname *tcnp,
    655     void *tde_ret, struct vnode **tvp_ret)
    656 {
    657 	struct vnode *intermediate_node;
    658 	struct vnode *fvp, *tvp;
    659 	int error;
    660 
    661 	KASSERT(ops != NULL);
    662 	KASSERT(mp != NULL);
    663 	KASSERT(fdvp != NULL);
    664 	KASSERT(fcnp != NULL);
    665 	KASSERT(fvp_ret != NULL);
    666 	KASSERT(tdvp != NULL);
    667 	KASSERT(tcnp != NULL);
    668 	KASSERT(tvp_ret != NULL);
    669 	KASSERT(fdvp != tdvp);
    670 	KASSERT(fcnp != tcnp);
    671 	KASSERT(fcnp->cn_nameiop == DELETE);
    672 	KASSERT(tcnp->cn_nameiop == RENAME);
    673 	KASSERT(fvp_ret != tvp_ret);
    674 	KASSERT(fdvp->v_type == VDIR);
    675 	KASSERT(tdvp->v_type == VDIR);
    676 	KASSERT(fdvp->v_mount == mp);
    677 	KASSERT(tdvp->v_mount == mp);
    678 
    679 	error = ops->gro_genealogy(mp, cred, fdvp, tdvp, &intermediate_node);
    680 	if (error)
    681 		return error;
    682 
    683 	/*
    684 	 * intermediate_node == NULL means fdvp is not an ancestor of tdvp.
    685 	 */
    686 	if (intermediate_node == NULL)
    687 		error = genfs_rename_lock(ops, mp, cred,
    688 		    ENOTEMPTY, EISDIR, EINVAL,
    689 		    tdvp, tcnp, true, tde_ret, &tvp,
    690 		    fdvp, fcnp, false, fde_ret, &fvp);
    691 	else
    692 		error = genfs_rename_lock(ops, mp, cred,
    693 		    EINVAL, EISDIR, EINVAL,
    694 		    fdvp, fcnp, false, fde_ret, &fvp,
    695 		    tdvp, tcnp, true, tde_ret, &tvp);
    696 	if (error)
    697 		goto out;
    698 
    699 	KASSERT(fvp != NULL);
    700 
    701 	/*
    702 	 * Reject rename("foo/bar", "foo/bar/baz/quux/zot").
    703 	 */
    704 	if (fvp == intermediate_node) {
    705 		genfs_rename_exit(ops, mp, fdvp, fvp, tdvp, tvp);
    706 		error = EINVAL;
    707 		goto out;
    708 	}
    709 
    710 	*fvp_ret = fvp;
    711 	*tvp_ret = tvp;
    712 	error = 0;
    713 
    714 out:	if (intermediate_node != NULL)
    715 		vrele(intermediate_node);
    716 	return error;
    717 }
    718 
    719 /*
    720  * genfs_rename_lock: Lookup and lock it all.  The lock order is:
    721  *
    722  *	a_dvp -> a_vp -> b_dvp -> b_vp,
    723  *
    724  * except if a_vp is a nondirectory in which case the lock order is:
    725  *
    726  *	a_dvp -> b_dvp -> b_vp -> a_vp,
    727  *
    728  * which can't violate ancestor->descendant because a_vp has no
    729  * descendants in this case.  This edge case is necessary because some
    730  * file systems can only lookup/lock/unlock, and we can't hold a_vp
    731  * locked when we lookup/lock/unlock b_vp if they turn out to be the
    732  * same, and we can't find out that they're the same until after the
    733  * lookup.
    734  *
    735  * b_dvp must not be an ancestor of a_dvp, although a_dvp may be an
    736  * ancestor of b_dvp.
    737  *
    738  * Fail with overlap_error if node a is directory b.  Neither
    739  * componentname may be `.' or `..'.
    740  *
    741  * a_dvp and b_dvp must be referenced.
    742  *
    743  * On entry, a_dvp and b_dvp are unlocked.
    744  *
    745  * On success,
    746  * . a_dvp and b_dvp are locked,
    747  * . *a_dirent_ret is filled with a directory entry whose node is
    748  *     locked and referenced,
    749  * . *b_vp_ret is filled with the corresponding vnode,
    750  * . *b_dirent_ret is filled either with null or with a directory entry
    751  *     whose node is locked and referenced,
    752  * . *b_vp is filled either with null or with the corresponding vnode,
    753  *     and
    754  * . the only pair of vnodes that may be identical is a_vp and b_vp.
    755  *
    756  * On failure, a_dvp and b_dvp are left unlocked, and *a_dirent_ret,
    757  * *a_vp, *b_dirent_ret, and *b_vp are left alone.
    758  */
    759 static int
    760 genfs_rename_lock(const struct genfs_rename_ops *ops,
    761     struct mount *mp, kauth_cred_t cred,
    762     int overlap_error, int a_dot_error, int b_dot_error,
    763     struct vnode *a_dvp, struct componentname *a_cnp, bool a_missing_ok,
    764     void *a_de_ret, struct vnode **a_vp_ret,
    765     struct vnode *b_dvp, struct componentname *b_cnp, bool b_missing_ok,
    766     void *b_de_ret, struct vnode **b_vp_ret)
    767 {
    768 	struct vnode *a_vp, *b_vp;
    769 	int error;
    770 
    771 	KASSERT(ops != NULL);
    772 	KASSERT(mp != NULL);
    773 	KASSERT(a_dvp != NULL);
    774 	KASSERT(a_cnp != NULL);
    775 	KASSERT(a_vp_ret != NULL);
    776 	KASSERT(b_dvp != NULL);
    777 	KASSERT(b_cnp != NULL);
    778 	KASSERT(b_vp_ret != NULL);
    779 	KASSERT(a_dvp != b_dvp);
    780 	KASSERT(a_vp_ret != b_vp_ret);
    781 	KASSERT(a_dvp->v_type == VDIR);
    782 	KASSERT(b_dvp->v_type == VDIR);
    783 	KASSERT(a_dvp->v_mount == mp);
    784 	KASSERT(b_dvp->v_mount == mp);
    785 	KASSERT(a_missing_ok != b_missing_ok);
    786 
    787 	/*
    788 	 * 1. Lock a_dvp.
    789 	 */
    790 	error = ops->gro_lock_directory(mp, a_dvp);
    791 	if (error)
    792 		goto fail0;
    793 
    794 	/* Did we lose a race with mount?  */
    795 	if (a_dvp->v_mountedhere != NULL) {
    796 		error = EBUSY;
    797 		goto fail1;
    798 	}
    799 
    800 	/*
    801 	 * 2. Lookup a_vp.  May lock/unlock a_vp.
    802 	 */
    803 	error = ops->gro_lookup(mp, a_dvp, a_cnp, a_de_ret, &a_vp);
    804 	if (error) {
    805 		if (a_missing_ok && (error == ENOENT))
    806 			a_vp = NULL;
    807 		else
    808 			goto fail1;
    809 	} else {
    810 		KASSERT(a_vp != NULL);
    811 
    812 		/* Refuse to rename (over) `.'.  */
    813 		if (a_vp == a_dvp) {
    814 			error = a_dot_error;
    815 			goto fail2;
    816 		}
    817 
    818 		/* Reject rename("x", "x/y") or rename("x/y", "x").  */
    819 		if (a_vp == b_dvp) {
    820 			error = overlap_error;
    821 			goto fail2;
    822 		}
    823 	}
    824 
    825 	KASSERT(a_vp != a_dvp);
    826 	KASSERT(a_vp != b_dvp);
    827 
    828 	/*
    829 	 * 3. Lock a_vp, if it is a directory.
    830 	 *
    831 	 * We already ruled out a_vp == a_dvp (i.e., a_cnp is `.'), so
    832 	 * this is not locking against self, and we already ruled out
    833 	 * a_vp == b_dvp, so this won't cause subsequent locking of
    834 	 * b_dvp to lock against self.
    835 	 *
    836 	 * If a_vp is a nondirectory, we can't hold it when we lookup
    837 	 * b_vp in case (a) the file system can only lookup/lock/unlock
    838 	 * and (b) b_vp turns out to be the same file as a_vp due to
    839 	 * hard links -- and we can't even detect that case until after
    840 	 * we've looked up b_vp.  Fortunately, if a_vp is a
    841 	 * nondirectory, then it is a leaf, so we can safely lock it
    842 	 * last.
    843 	 */
    844 	if (a_vp != NULL && a_vp->v_type == VDIR) {
    845 		vn_lock(a_vp, LK_EXCLUSIVE | LK_RETRY);
    846 		KASSERT(a_vp->v_mount == mp);
    847 		/* Refuse to rename (over) a mount point.  */
    848 		if (a_vp->v_mountedhere != NULL) {
    849 			error = EBUSY;
    850 			goto fail3;
    851 		}
    852 	}
    853 
    854 	/*
    855 	 * 4. Lock b_dvp.
    856 	 */
    857 	error = ops->gro_lock_directory(mp, b_dvp);
    858 	if (error)
    859 		goto fail3;
    860 
    861 	/* Did we lose a race with mount?  */
    862 	if (b_dvp->v_mountedhere != NULL) {
    863 		error = EBUSY;
    864 		goto fail4;
    865 	}
    866 
    867 	/*
    868 	 * 5. Lookup b_vp.  May lock/unlock b_vp.
    869 	 */
    870 	error = ops->gro_lookup(mp, b_dvp, b_cnp, b_de_ret, &b_vp);
    871 	if (error) {
    872 		if (b_missing_ok && (error == ENOENT))
    873 			b_vp = NULL;
    874 		else
    875 			goto fail4;
    876 	} else {
    877 		KASSERT(b_vp != NULL);
    878 
    879 		/* Refuse to rename (over) `.'.  */
    880 		if (b_vp == b_dvp) {
    881 			error = b_dot_error;
    882 			goto fail5;
    883 		}
    884 
    885 		/*
    886 		 * b_dvp must not be an ancestor of a_dvp, so if we
    887 		 * find b_dvp/b_vp=a_dvp/a_vp something is wrong.
    888 		 */
    889 		if (b_vp == a_dvp) {
    890 			/*
    891 			 * We have a directory hard link before us.
    892 			 * XXX What error should this return?  EDEADLK?
    893 			 * Panic?
    894 			 */
    895 			error = EIO;
    896 			goto fail5;
    897 		}
    898 	}
    899 	KASSERT(b_vp != b_dvp);
    900 	KASSERT(b_vp != a_dvp);
    901 
    902 	/*
    903 	 * 6. Lock a_vp, if it is a nondirectory.
    904 	 *
    905 	 * In this case a_vp is a leaf, so it is either equal to or
    906 	 * incommensurate with b_vp, and so we can safely lock it at
    907 	 * any point now.
    908 	 */
    909 	if (a_vp != NULL && a_vp->v_type != VDIR) {
    910 		vn_lock(a_vp, LK_EXCLUSIVE | LK_RETRY);
    911 		KASSERT(a_vp->v_mount == mp);
    912 		/* (not a directory so can't have anything mounted here) */
    913 	}
    914 
    915 	/*
    916 	 * 7. Lock b_vp, if it is not a_vp.
    917 	 *
    918 	 * b_vp and a_vp may the same inode if they are hard links to
    919 	 * one another.
    920 	 */
    921 	if ((b_vp != NULL) && (b_vp != a_vp)) {
    922 		vn_lock(b_vp, LK_EXCLUSIVE | LK_RETRY);
    923 		KASSERT(b_vp->v_mount == mp);
    924 		/* Refuse to rename (over) a mount point.  */
    925 		if ((b_vp->v_type == VDIR) && (b_vp->v_mountedhere != NULL)) {
    926 			error = EBUSY;
    927 			goto fail6;
    928 		}
    929 	}
    930 
    931 	KASSERT(VOP_ISLOCKED(a_dvp) == LK_EXCLUSIVE);
    932 	KASSERT(VOP_ISLOCKED(b_dvp) == LK_EXCLUSIVE);
    933 	KASSERT(a_missing_ok || (a_vp != NULL));
    934 	KASSERT(b_missing_ok || (b_vp != NULL));
    935 	KASSERT((a_vp == NULL) || (VOP_ISLOCKED(a_vp) == LK_EXCLUSIVE));
    936 	KASSERT((b_vp == NULL) || (VOP_ISLOCKED(b_vp) == LK_EXCLUSIVE));
    937 
    938 	*a_vp_ret = a_vp;
    939 	*b_vp_ret = b_vp;
    940 	return 0;
    941 
    942 fail6:	if ((b_vp != NULL) && (b_vp != a_vp))
    943 		VOP_UNLOCK(b_vp);
    944 	if (a_vp != NULL && a_vp->v_type != VDIR)
    945 		VOP_UNLOCK(a_vp);
    946 fail5:	if (b_vp != NULL)
    947 		vrele(b_vp);
    948 fail4:	VOP_UNLOCK(b_dvp);
    949 fail3:	if (a_vp != NULL && a_vp->v_type == VDIR)
    950 		VOP_UNLOCK(a_vp);
    951 fail2:	if (a_vp != NULL)
    952 		vrele(a_vp);
    953 fail1:	VOP_UNLOCK(a_dvp);
    954 fail0:	return error;
    955 }
    956 
    957 /*
    958  * genfs_rename_exit: Unlock everything we locked for rename.
    959  *
    960  * fdvp and tdvp must be referenced.
    961  *
    962  * On entry, everything is locked, and fvp and tvp referenced.
    963  *
    964  * On exit, everything is unlocked, and fvp and tvp are released.
    965  */
    966 static void
    967 genfs_rename_exit(const struct genfs_rename_ops *ops,
    968     struct mount *mp,
    969     struct vnode *fdvp, struct vnode *fvp,
    970     struct vnode *tdvp, struct vnode *tvp)
    971 {
    972 
    973 	(void)ops;
    974 	KASSERT(ops != NULL);
    975 	KASSERT(mp != NULL);
    976 	KASSERT(fdvp != NULL);
    977 	KASSERT(fvp != NULL);
    978 	KASSERT(fdvp != fvp);
    979 	KASSERT(fdvp != tvp);
    980 	KASSERT(tdvp != tvp);
    981 	KASSERT(tdvp != fvp);
    982 	KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE);
    983 	KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
    984 	KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE);
    985 	KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
    986 
    987 	if ((tvp != NULL) && (tvp != fvp))
    988 		VOP_UNLOCK(tvp);
    989 	VOP_UNLOCK(fvp);
    990 	if (tvp != NULL)
    991 		vrele(tvp);
    992 	if (tdvp != fdvp)
    993 		VOP_UNLOCK(tdvp);
    994 	vrele(fvp);
    995 	VOP_UNLOCK(fdvp);
    996 }
    997 
    998 /*
    999  * genfs_rename_remove: Remove the entry for the non-directory vp with
   1000  * componentname cnp from the directory dvp, using the lookup results
   1001  * de.  It is the responsibility of gro_remove to purge the name cache.
   1002  *
   1003  * Everything must be locked and referenced.
   1004  */
   1005 static int
   1006 genfs_rename_remove(const struct genfs_rename_ops *ops,
   1007     struct mount *mp, kauth_cred_t cred,
   1008     struct vnode *dvp, struct componentname *cnp, void *de, struct vnode *vp,
   1009     nlink_t *tvp_nlinkp)
   1010 {
   1011 	int error;
   1012 
   1013 	KASSERT(ops != NULL);
   1014 	KASSERT(mp != NULL);
   1015 	KASSERT(dvp != NULL);
   1016 	KASSERT(cnp != NULL);
   1017 	KASSERT(vp != NULL);
   1018 	KASSERT(dvp != vp);
   1019 	KASSERT(dvp->v_type == VDIR);
   1020 	KASSERT(vp->v_type != VDIR);
   1021 	KASSERT(dvp->v_mount == mp);
   1022 	KASSERT(vp->v_mount == mp);
   1023 	KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
   1024 	KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
   1025 
   1026 	error = ops->gro_remove_check_possible(mp, dvp, vp);
   1027 	if (error)
   1028 		return error;
   1029 
   1030 	error = ops->gro_remove_check_permitted(mp, cred, dvp, vp);
   1031 	error = kauth_authorize_vnode(cred, KAUTH_VNODE_DELETE, vp, dvp,
   1032 	    error);
   1033 	if (error)
   1034 		return error;
   1035 
   1036 	error = ops->gro_remove(mp, cred, dvp, cnp, de, vp, tvp_nlinkp);
   1037 	if (error)
   1038 		return error;
   1039 
   1040 	return 0;
   1041 }
   1042 
   1043 static int
   1044 genfs_ufslike_check_sticky(kauth_cred_t, mode_t, uid_t, struct vnode *, uid_t);
   1045 
   1046 /*
   1047  * genfs_ufslike_rename_check_possible: Check whether a rename is
   1048  * possible independent of credentials, assuming UFS-like inode flag
   1049  * semantics.  clobber_p is true iff the target node already exists.
   1050  */
   1051 int
   1052 genfs_ufslike_rename_check_possible(
   1053     unsigned long fdflags, unsigned long fflags,
   1054     unsigned long tdflags, unsigned long tflags, bool clobber_p,
   1055     unsigned long immutable, unsigned long append)
   1056 {
   1057 
   1058 	if ((fdflags | fflags) & (immutable | append))
   1059 		return EPERM;
   1060 
   1061 	if (tdflags & (immutable | (clobber_p? append : 0)))
   1062 		return EPERM;
   1063 
   1064 	if (clobber_p && (tflags & (immutable | append)))
   1065 		return EPERM;
   1066 
   1067 	return 0;
   1068 }
   1069 
   1070 /*
   1071  * genfs_ufslike_rename_check_permitted: Check whether a rename is
   1072  * permitted given our credentials, assuming UFS-like permission and
   1073  * ownership semantics.
   1074  *
   1075  * The only pair of vnodes that may be identical is {fdvp, tdvp}.
   1076  *
   1077  * Everything must be locked and referenced.
   1078  */
   1079 int
   1080 genfs_ufslike_rename_check_permitted(kauth_cred_t cred,
   1081     struct vnode *fdvp, mode_t fdmode, uid_t fduid,
   1082     struct vnode *fvp, uid_t fuid,
   1083     struct vnode *tdvp, mode_t tdmode, uid_t tduid,
   1084     struct vnode *tvp, uid_t tuid)
   1085 {
   1086 	int error;
   1087 
   1088 	KASSERT(fdvp != NULL);
   1089 	KASSERT(fvp != NULL);
   1090 	KASSERT(tdvp != NULL);
   1091 	KASSERT(fdvp != fvp);
   1092 	KASSERT(fdvp != tvp);
   1093 	KASSERT(tdvp != fvp);
   1094 	KASSERT(tdvp != tvp);
   1095 	KASSERT(fvp != tvp);
   1096 	KASSERT(fdvp->v_type == VDIR);
   1097 	KASSERT(tdvp->v_type == VDIR);
   1098 	KASSERT(fdvp->v_mount == fvp->v_mount);
   1099 	KASSERT(fdvp->v_mount == tdvp->v_mount);
   1100 	KASSERT((tvp == NULL) || (fdvp->v_mount == tvp->v_mount));
   1101 	KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE);
   1102 	KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE);
   1103 	KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
   1104 	KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
   1105 
   1106 	/*
   1107 	 * We need to remove or change an entry in the source directory.
   1108 	 */
   1109 	error = VOP_ACCESS(fdvp, VWRITE, cred);
   1110 	if (error)
   1111 		return error;
   1112 
   1113 	/*
   1114 	 * If we are changing directories, then we need to write to the
   1115 	 * target directory to add or change an entry.  Also, if fvp is
   1116 	 * a directory, we need to write to it to change its `..'
   1117 	 * entry.
   1118 	 */
   1119 	if (fdvp != tdvp) {
   1120 		error = VOP_ACCESS(tdvp, VWRITE, cred);
   1121 		if (error)
   1122 			return error;
   1123 		if (fvp->v_type == VDIR) {
   1124 			error = VOP_ACCESS(fvp, VWRITE, cred);
   1125 			if (error)
   1126 				return error;
   1127 		}
   1128 	}
   1129 
   1130 	error = genfs_ufslike_check_sticky(cred, fdmode, fduid, fvp, fuid);
   1131 	if (error)
   1132 		return error;
   1133 
   1134 	error = genfs_ufslike_check_sticky(cred, tdmode, tduid, tvp, tuid);
   1135 	if (error)
   1136 		return error;
   1137 
   1138 	return 0;
   1139 }
   1140 
   1141 /*
   1142  * genfs_ufslike_remove_check_possible: Check whether a remove is
   1143  * possible independent of credentials, assuming UFS-like inode flag
   1144  * semantics.
   1145  */
   1146 int
   1147 genfs_ufslike_remove_check_possible(unsigned long dflags, unsigned long flags,
   1148     unsigned long immutable, unsigned long append)
   1149 {
   1150 
   1151 	/*
   1152 	 * We want to delete the entry.  If the directory is immutable,
   1153 	 * we can't write to it to delete the entry.  If the directory
   1154 	 * is append-only, the only change we can make is to add
   1155 	 * entries, so we can't delete entries.  If the node is
   1156 	 * immutable, we can't change the links to it, so we can't
   1157 	 * delete the entry.  If the node is append-only...well, this
   1158 	 * is what UFS does.
   1159 	 */
   1160 	if ((dflags | flags) & (immutable | append))
   1161 		return EPERM;
   1162 
   1163 	return 0;
   1164 }
   1165 
   1166 /*
   1167  * genfs_ufslike_remove_check_permitted: Check whether a remove is
   1168  * permitted given our credentials, assuming UFS-like permission and
   1169  * ownership semantics.
   1170  *
   1171  * Everything must be locked and referenced.
   1172  */
   1173 int
   1174 genfs_ufslike_remove_check_permitted(kauth_cred_t cred,
   1175     struct vnode *dvp, mode_t dmode, uid_t duid,
   1176     struct vnode *vp, uid_t uid)
   1177 {
   1178 	int error;
   1179 
   1180 	KASSERT(dvp != NULL);
   1181 	KASSERT(vp != NULL);
   1182 	KASSERT(dvp != vp);
   1183 	KASSERT(dvp->v_type == VDIR);
   1184 	KASSERT(vp->v_type != VDIR);
   1185 	KASSERT(dvp->v_mount == vp->v_mount);
   1186 	KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
   1187 	KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
   1188 
   1189 	/*
   1190 	 * We need to write to the directory to remove from it.
   1191 	 */
   1192 	error = VOP_ACCESS(dvp, VWRITE, cred);
   1193 	if (error)
   1194 		return error;
   1195 
   1196 	error = genfs_ufslike_check_sticky(cred, dmode, duid, vp, uid);
   1197 	if (error)
   1198 		return error;
   1199 
   1200 	return 0;
   1201 }
   1202 
   1203 /*
   1204  * genfs_ufslike_check_sticky: Check whether a party with credentials
   1205  * cred may change an entry in a sticky directory, assuming UFS-like
   1206  * permission, ownership, and stickiness semantics: If the directory is
   1207  * sticky and the entry exists, the user must own either the directory
   1208  * or the entry's node in order to change the entry.
   1209  *
   1210  * Everything must be locked and referenced.
   1211  */
   1212 int
   1213 genfs_ufslike_check_sticky(kauth_cred_t cred, mode_t dmode, uid_t duid,
   1214     struct vnode *vp, uid_t uid)
   1215 {
   1216 
   1217 	if ((dmode & S_ISTXT) && (vp != NULL))
   1218 		return genfs_can_sticky(vp, cred, duid, uid);
   1219 
   1220 	return 0;
   1221 }
   1222