1*6d4f51a7Smlelstv /* $NetBSD: msdosfs_rename.c,v 1.4 2024/05/04 05:49:39 mlelstv Exp $ */
2e99cb814Shannken
3e99cb814Shannken /*-
45b6c6a9aShannken * Copyright (c) 2011 The NetBSD Foundation, Inc.
5e99cb814Shannken * All rights reserved.
65b6c6a9aShannken *
75b6c6a9aShannken * This code is derived from software contributed to The NetBSD Foundation
85b6c6a9aShannken * by Taylor R Campbell.
9e99cb814Shannken *
10e99cb814Shannken * Redistribution and use in source and binary forms, with or without
11e99cb814Shannken * modification, are permitted provided that the following conditions
12e99cb814Shannken * are met:
13e99cb814Shannken * 1. Redistributions of source code must retain the above copyright
14e99cb814Shannken * notice, this list of conditions and the following disclaimer.
15e99cb814Shannken * 2. Redistributions in binary form must reproduce the above copyright
16e99cb814Shannken * notice, this list of conditions and the following disclaimer in the
17e99cb814Shannken * documentation and/or other materials provided with the distribution.
18e99cb814Shannken *
195b6c6a9aShannken * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
205b6c6a9aShannken * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
215b6c6a9aShannken * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
225b6c6a9aShannken * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
235b6c6a9aShannken * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
245b6c6a9aShannken * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
255b6c6a9aShannken * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
265b6c6a9aShannken * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
275b6c6a9aShannken * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
285b6c6a9aShannken * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
295b6c6a9aShannken * POSSIBILITY OF SUCH DAMAGE.
30e99cb814Shannken */
315b6c6a9aShannken
32e99cb814Shannken /*
335b6c6a9aShannken * MS-DOS FS Rename
34e99cb814Shannken */
35e99cb814Shannken
365b6c6a9aShannken #include <sys/cdefs.h>
37*6d4f51a7Smlelstv __KERNEL_RCSID(0, "$NetBSD: msdosfs_rename.c,v 1.4 2024/05/04 05:49:39 mlelstv Exp $");
385b6c6a9aShannken
39e99cb814Shannken #include <sys/param.h>
40e99cb814Shannken #include <sys/buf.h>
415b6c6a9aShannken #include <sys/errno.h>
42e99cb814Shannken #include <sys/kauth.h>
435b6c6a9aShannken #include <sys/namei.h>
445b6c6a9aShannken #include <sys/vnode.h>
455b6c6a9aShannken #include <sys/vnode_if.h>
46e99cb814Shannken
47e99cb814Shannken #include <miscfs/genfs/genfs.h>
48e99cb814Shannken
49e99cb814Shannken #include <fs/msdosfs/bpb.h>
50e99cb814Shannken #include <fs/msdosfs/direntry.h>
51e99cb814Shannken #include <fs/msdosfs/denode.h>
52e99cb814Shannken #include <fs/msdosfs/msdosfsmount.h>
53e99cb814Shannken #include <fs/msdosfs/fat.h>
54e99cb814Shannken
555b6c6a9aShannken /*
565b6c6a9aShannken * Forward declarations
575b6c6a9aShannken */
585b6c6a9aShannken
595b6c6a9aShannken static int msdosfs_sane_rename(struct vnode *, struct componentname *,
605b6c6a9aShannken struct vnode *, struct componentname *,
615b6c6a9aShannken kauth_cred_t, bool);
625b6c6a9aShannken static bool msdosfs_rmdired_p(struct vnode *);
635b6c6a9aShannken static int msdosfs_read_dotdot(struct vnode *, kauth_cred_t, unsigned long *);
645b6c6a9aShannken static int msdosfs_rename_replace_dotdot(struct vnode *,
655b6c6a9aShannken struct vnode *, struct vnode *, kauth_cred_t);
665b6c6a9aShannken static int msdosfs_gro_lock_directory(struct mount *, struct vnode *);
675b6c6a9aShannken
685b6c6a9aShannken static const struct genfs_rename_ops msdosfs_genfs_rename_ops;
695b6c6a9aShannken
705b6c6a9aShannken /*
715b6c6a9aShannken * msdosfs_rename: The hairiest vop, with the insanest API.
725b6c6a9aShannken *
735b6c6a9aShannken * Arguments:
745b6c6a9aShannken *
755b6c6a9aShannken * . fdvp (from directory vnode),
765b6c6a9aShannken * . fvp (from vnode),
775b6c6a9aShannken * . fcnp (from component name),
785b6c6a9aShannken * . tdvp (to directory vnode),
795b6c6a9aShannken * . tvp (to vnode, or NULL), and
805b6c6a9aShannken * . tcnp (to component name).
815b6c6a9aShannken *
825b6c6a9aShannken * Any pair of vnode parameters may have the same vnode.
835b6c6a9aShannken *
845b6c6a9aShannken * On entry,
855b6c6a9aShannken *
865b6c6a9aShannken * . fdvp, fvp, tdvp, and tvp are referenced,
875b6c6a9aShannken * . fdvp and fvp are unlocked, and
885b6c6a9aShannken * . tdvp and tvp (if nonnull) are locked.
895b6c6a9aShannken *
905b6c6a9aShannken * On exit,
915b6c6a9aShannken *
925b6c6a9aShannken * . fdvp, fvp, tdvp, and tvp (if nonnull) are unreferenced, and
935b6c6a9aShannken * . tdvp and tvp are unlocked.
945b6c6a9aShannken */
95e99cb814Shannken int
msdosfs_rename(void * v)96e99cb814Shannken msdosfs_rename(void *v)
97e99cb814Shannken {
98e99cb814Shannken struct vop_rename_args /* {
99e99cb814Shannken struct vnode *a_fdvp;
100e99cb814Shannken struct vnode *a_fvp;
101e99cb814Shannken struct componentname *a_fcnp;
102e99cb814Shannken struct vnode *a_tdvp;
103e99cb814Shannken struct vnode *a_tvp;
104e99cb814Shannken struct componentname *a_tcnp;
105e99cb814Shannken } */ *ap = v;
106e99cb814Shannken struct vnode *fdvp = ap->a_fdvp;
1075b6c6a9aShannken struct vnode *fvp = ap->a_fvp;
108e99cb814Shannken struct componentname *fcnp = ap->a_fcnp;
1095b6c6a9aShannken struct vnode *tdvp = ap->a_tdvp;
1105b6c6a9aShannken struct vnode *tvp = ap->a_tvp;
1115b6c6a9aShannken struct componentname *tcnp = ap->a_tcnp;
1125b6c6a9aShannken kauth_cred_t cred;
113e99cb814Shannken int error;
114e99cb814Shannken
1155b6c6a9aShannken KASSERT(fdvp != NULL);
1165b6c6a9aShannken KASSERT(fvp != NULL);
1175b6c6a9aShannken KASSERT(fcnp != NULL);
1185b6c6a9aShannken KASSERT(fcnp->cn_nameptr != NULL);
1195b6c6a9aShannken KASSERT(tdvp != NULL);
1205b6c6a9aShannken KASSERT(tcnp != NULL);
1215b6c6a9aShannken KASSERT(fcnp->cn_nameptr != NULL);
1225b6c6a9aShannken /* KASSERT(VOP_ISLOCKED(fdvp) != LK_EXCLUSIVE); */
1235b6c6a9aShannken /* KASSERT(VOP_ISLOCKED(fvp) != LK_EXCLUSIVE); */
1245b6c6a9aShannken KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
1255b6c6a9aShannken KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
1265b6c6a9aShannken KASSERT(fdvp->v_type == VDIR);
1275b6c6a9aShannken KASSERT(tdvp->v_type == VDIR);
1285b6c6a9aShannken
1295b6c6a9aShannken cred = fcnp->cn_cred;
130*6d4f51a7Smlelstv KASSERT(kauth_cred_uidmatch(cred, tcnp->cn_cred));
131e99cb814Shannken
132e99cb814Shannken /*
1335b6c6a9aShannken * Sanitize our world from the VFS insanity. Unlock the target
1345b6c6a9aShannken * directory and node, which are locked. Release the children,
1355b6c6a9aShannken * which are referenced. Check for rename("x", "y/."), which
1365b6c6a9aShannken * it is our responsibility to reject, not the caller's. (But
1375b6c6a9aShannken * the caller does reject rename("x/.", "y"). Go figure.)
138e99cb814Shannken */
139e99cb814Shannken
140e99cb814Shannken VOP_UNLOCK(tdvp);
1415b6c6a9aShannken if ((tvp != NULL) && (tvp != tdvp))
1425b6c6a9aShannken VOP_UNLOCK(tvp);
1435b6c6a9aShannken
1445b6c6a9aShannken vrele(fvp);
1455b6c6a9aShannken if (tvp != NULL)
1465b6c6a9aShannken vrele(tvp);
1475b6c6a9aShannken
1485b6c6a9aShannken if (tvp == tdvp) {
1495b6c6a9aShannken error = EINVAL;
1505b6c6a9aShannken goto out;
151e99cb814Shannken }
152e99cb814Shannken
1535b6c6a9aShannken error = msdosfs_sane_rename(fdvp, fcnp, tdvp, tcnp, cred, false);
1545b6c6a9aShannken
1555b6c6a9aShannken out: /*
1565b6c6a9aShannken * All done, whether with success or failure. Release the
1575b6c6a9aShannken * directory nodes now, as the caller expects from the VFS
1585b6c6a9aShannken * protocol.
159e99cb814Shannken */
1605b6c6a9aShannken vrele(fdvp);
1615b6c6a9aShannken vrele(tdvp);
1625b6c6a9aShannken
1635b6c6a9aShannken return error;
164e99cb814Shannken }
1655b6c6a9aShannken
1665b6c6a9aShannken /*
1675b6c6a9aShannken * msdosfs_sane_rename: The hairiest vop, with the saner API.
1685b6c6a9aShannken *
1695b6c6a9aShannken * Arguments:
1705b6c6a9aShannken *
1715b6c6a9aShannken * . fdvp (from directory vnode),
1725b6c6a9aShannken * . fcnp (from component name),
1735b6c6a9aShannken * . tdvp (to directory vnode), and
1745b6c6a9aShannken * . tcnp (to component name).
1755b6c6a9aShannken *
1765b6c6a9aShannken * fdvp and tdvp must be referenced and unlocked.
1775b6c6a9aShannken */
1785b6c6a9aShannken static int
msdosfs_sane_rename(struct vnode * fdvp,struct componentname * fcnp,struct vnode * tdvp,struct componentname * tcnp,kauth_cred_t cred,bool posixly_correct)1795b6c6a9aShannken msdosfs_sane_rename(
1805b6c6a9aShannken struct vnode *fdvp, struct componentname *fcnp,
1815b6c6a9aShannken struct vnode *tdvp, struct componentname *tcnp,
1825b6c6a9aShannken kauth_cred_t cred, bool posixly_correct)
1835b6c6a9aShannken {
1845b6c6a9aShannken struct msdosfs_lookup_results fmlr, tmlr;
1855b6c6a9aShannken
1865b6c6a9aShannken return genfs_sane_rename(&msdosfs_genfs_rename_ops,
1875b6c6a9aShannken fdvp, fcnp, &fmlr, tdvp, tcnp, &tmlr,
1885b6c6a9aShannken cred, posixly_correct);
189e99cb814Shannken }
1905b6c6a9aShannken
1915b6c6a9aShannken /*
1925b6c6a9aShannken * msdosfs_gro_directory_empty_p: Return true if the directory vp is
1935b6c6a9aShannken * empty. dvp is its parent.
1945b6c6a9aShannken *
1955b6c6a9aShannken * vp and dvp must be locked and referenced.
1965b6c6a9aShannken */
1975b6c6a9aShannken static bool
msdosfs_gro_directory_empty_p(struct mount * mp,kauth_cred_t cred,struct vnode * vp,struct vnode * dvp)1985b6c6a9aShannken msdosfs_gro_directory_empty_p(struct mount *mp, kauth_cred_t cred,
1995b6c6a9aShannken struct vnode *vp, struct vnode *dvp)
2005b6c6a9aShannken {
2015b6c6a9aShannken
2025b6c6a9aShannken (void)mp;
2035b6c6a9aShannken (void)cred;
2045b6c6a9aShannken (void)dvp;
2055b6c6a9aShannken KASSERT(mp != NULL);
2065b6c6a9aShannken KASSERT(vp != NULL);
2075b6c6a9aShannken KASSERT(dvp != NULL);
2085b6c6a9aShannken KASSERT(vp != dvp);
2095b6c6a9aShannken KASSERT(vp->v_mount == mp);
2105b6c6a9aShannken KASSERT(dvp->v_mount == mp);
2115b6c6a9aShannken KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
2125b6c6a9aShannken KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
2135b6c6a9aShannken
2148086f46eSthorpej return msdosfs_dosdirempty(VTODE(vp));
215e99cb814Shannken }
2165b6c6a9aShannken
2175b6c6a9aShannken /*
2185b6c6a9aShannken * Return a UFS-like mode for vp.
2195b6c6a9aShannken */
2205b6c6a9aShannken static mode_t
msdosfs_vnode_mode(struct vnode * vp)2215b6c6a9aShannken msdosfs_vnode_mode(struct vnode *vp)
2225b6c6a9aShannken {
2235b6c6a9aShannken struct msdosfsmount *pmp;
2245b6c6a9aShannken mode_t mode, mask;
2255b6c6a9aShannken
2265b6c6a9aShannken KASSERT(vp != NULL);
2275b6c6a9aShannken
2285b6c6a9aShannken pmp = VTODE(vp)->de_pmp;
2295b6c6a9aShannken KASSERT(pmp != NULL);
2305b6c6a9aShannken
2315b6c6a9aShannken if (VTODE(vp)->de_Attributes & ATTR_READONLY)
2325b6c6a9aShannken mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
2335b6c6a9aShannken else
2345b6c6a9aShannken mode = S_IRWXU|S_IRWXG|S_IRWXO;
2355b6c6a9aShannken
2365b6c6a9aShannken if (vp->v_type == VDIR)
2375b6c6a9aShannken mask = pmp->pm_dirmask;
2385b6c6a9aShannken else
2395b6c6a9aShannken mask = pmp->pm_mask;
2405b6c6a9aShannken
2415b6c6a9aShannken return (mode & mask);
2425b6c6a9aShannken }
2435b6c6a9aShannken
2445b6c6a9aShannken /*
2455b6c6a9aShannken * msdosfs_gro_rename_check_possible: Check whether renaming fvp in fdvp
2465b6c6a9aShannken * to tvp in tdvp is possible independent of credentials.
2475b6c6a9aShannken */
2485b6c6a9aShannken static int
msdosfs_gro_rename_check_possible(struct mount * mp,struct vnode * fdvp,struct vnode * fvp,struct vnode * tdvp,struct vnode * tvp)2495b6c6a9aShannken msdosfs_gro_rename_check_possible(struct mount *mp,
2505b6c6a9aShannken struct vnode *fdvp, struct vnode *fvp,
2515b6c6a9aShannken struct vnode *tdvp, struct vnode *tvp)
2525b6c6a9aShannken {
2535b6c6a9aShannken
2545b6c6a9aShannken (void)mp;
2555b6c6a9aShannken (void)fdvp;
2565b6c6a9aShannken (void)fvp;
2575b6c6a9aShannken (void)tdvp;
2585b6c6a9aShannken (void)tvp;
2595b6c6a9aShannken KASSERT(mp != NULL);
2605b6c6a9aShannken KASSERT(fdvp != NULL);
2615b6c6a9aShannken KASSERT(fvp != NULL);
2625b6c6a9aShannken KASSERT(tdvp != NULL);
2635b6c6a9aShannken KASSERT(fdvp != fvp);
2645b6c6a9aShannken KASSERT(fdvp != tvp);
2655b6c6a9aShannken KASSERT(tdvp != fvp);
2665b6c6a9aShannken KASSERT(tdvp != tvp);
2675b6c6a9aShannken KASSERT(fvp != tvp);
2685b6c6a9aShannken KASSERT(fdvp->v_mount == mp);
2695b6c6a9aShannken KASSERT(fvp->v_mount == mp);
2705b6c6a9aShannken KASSERT(tdvp->v_mount == mp);
2715b6c6a9aShannken KASSERT((tvp == NULL) || (tvp->v_mount == mp));
2725b6c6a9aShannken KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE);
2735b6c6a9aShannken KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE);
2745b6c6a9aShannken KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
2755b6c6a9aShannken KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
2765b6c6a9aShannken
2775b6c6a9aShannken /* It's always possible: no error. */
2785b6c6a9aShannken return 0;
2795b6c6a9aShannken }
2805b6c6a9aShannken
2815b6c6a9aShannken /*
2825b6c6a9aShannken * msdosfs_gro_rename_check_permitted: ...
2835b6c6a9aShannken */
2845b6c6a9aShannken static int
msdosfs_gro_rename_check_permitted(struct mount * mp,kauth_cred_t cred,struct vnode * fdvp,struct vnode * fvp,struct vnode * tdvp,struct vnode * tvp)2855b6c6a9aShannken msdosfs_gro_rename_check_permitted(struct mount *mp, kauth_cred_t cred,
2865b6c6a9aShannken struct vnode *fdvp, struct vnode *fvp,
2875b6c6a9aShannken struct vnode *tdvp, struct vnode *tvp)
2885b6c6a9aShannken {
2895b6c6a9aShannken struct msdosfsmount *pmp;
2905b6c6a9aShannken
2915b6c6a9aShannken KASSERT(mp != NULL);
2925b6c6a9aShannken KASSERT(fdvp != NULL);
2935b6c6a9aShannken KASSERT(fvp != NULL);
2945b6c6a9aShannken KASSERT(tdvp != NULL);
2955b6c6a9aShannken KASSERT(fdvp != fvp);
2965b6c6a9aShannken KASSERT(fdvp != tvp);
2975b6c6a9aShannken KASSERT(tdvp != fvp);
2985b6c6a9aShannken KASSERT(tdvp != tvp);
2995b6c6a9aShannken KASSERT(fvp != tvp);
3005b6c6a9aShannken KASSERT(fdvp->v_mount == mp);
3015b6c6a9aShannken KASSERT(fvp->v_mount == mp);
3025b6c6a9aShannken KASSERT(tdvp->v_mount == mp);
3035b6c6a9aShannken KASSERT((tvp == NULL) || (tvp->v_mount == mp));
3045b6c6a9aShannken KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE);
3055b6c6a9aShannken KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE);
3065b6c6a9aShannken KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
3075b6c6a9aShannken KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
3085b6c6a9aShannken
3095b6c6a9aShannken pmp = VFSTOMSDOSFS(mp);
3105b6c6a9aShannken KASSERT(pmp != NULL);
3115b6c6a9aShannken
3125b6c6a9aShannken return genfs_ufslike_rename_check_permitted(cred,
3135b6c6a9aShannken fdvp, msdosfs_vnode_mode(fdvp), pmp->pm_uid,
3145b6c6a9aShannken fvp, pmp->pm_uid,
3155b6c6a9aShannken tdvp, msdosfs_vnode_mode(tdvp), pmp->pm_uid,
3165b6c6a9aShannken tvp, (tvp? pmp->pm_uid : 0));
3175b6c6a9aShannken }
3185b6c6a9aShannken
3195b6c6a9aShannken /*
3205b6c6a9aShannken * msdosfs_gro_remove_check_possible: ...
3215b6c6a9aShannken */
3225b6c6a9aShannken static int
msdosfs_gro_remove_check_possible(struct mount * mp,struct vnode * dvp,struct vnode * vp)3235b6c6a9aShannken msdosfs_gro_remove_check_possible(struct mount *mp,
3245b6c6a9aShannken struct vnode *dvp, struct vnode *vp)
3255b6c6a9aShannken {
3265b6c6a9aShannken
3275b6c6a9aShannken KASSERT(mp != NULL);
3285b6c6a9aShannken KASSERT(dvp != NULL);
3295b6c6a9aShannken KASSERT(vp != NULL);
3305b6c6a9aShannken KASSERT(dvp != vp);
3315b6c6a9aShannken KASSERT(dvp->v_mount == mp);
3325b6c6a9aShannken KASSERT(vp->v_mount == mp);
3335b6c6a9aShannken KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
3345b6c6a9aShannken KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
3355b6c6a9aShannken
3365b6c6a9aShannken /* It's always possible: no error. */
3375b6c6a9aShannken return 0;
3385b6c6a9aShannken }
3395b6c6a9aShannken
3405b6c6a9aShannken /*
3415b6c6a9aShannken * msdosfs_gro_remove_check_permitted: ...
3425b6c6a9aShannken */
3435b6c6a9aShannken static int
msdosfs_gro_remove_check_permitted(struct mount * mp,kauth_cred_t cred,struct vnode * dvp,struct vnode * vp)3445b6c6a9aShannken msdosfs_gro_remove_check_permitted(struct mount *mp, kauth_cred_t cred,
3455b6c6a9aShannken struct vnode *dvp, struct vnode *vp)
3465b6c6a9aShannken {
3475b6c6a9aShannken struct msdosfsmount *pmp;
3485b6c6a9aShannken
3495b6c6a9aShannken KASSERT(mp != NULL);
3505b6c6a9aShannken KASSERT(dvp != NULL);
3515b6c6a9aShannken KASSERT(vp != NULL);
3525b6c6a9aShannken KASSERT(dvp != vp);
3535b6c6a9aShannken KASSERT(dvp->v_mount == mp);
3545b6c6a9aShannken KASSERT(vp->v_mount == mp);
3555b6c6a9aShannken KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
3565b6c6a9aShannken KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
3575b6c6a9aShannken
3585b6c6a9aShannken pmp = VFSTOMSDOSFS(mp);
3595b6c6a9aShannken KASSERT(pmp != NULL);
3605b6c6a9aShannken
3615b6c6a9aShannken return genfs_ufslike_remove_check_permitted(cred,
3625b6c6a9aShannken dvp, msdosfs_vnode_mode(dvp), pmp->pm_uid, vp, pmp->pm_uid);
3635b6c6a9aShannken }
3645b6c6a9aShannken
3655b6c6a9aShannken /*
3665b6c6a9aShannken * msdosfs_gro_rename: Actually perform the rename operation.
3675b6c6a9aShannken */
3685b6c6a9aShannken static int
msdosfs_gro_rename(struct mount * mp,kauth_cred_t cred,struct vnode * fdvp,struct componentname * fcnp,void * fde,struct vnode * fvp,struct vnode * tdvp,struct componentname * tcnp,void * tde,struct vnode * tvp,nlink_t * tvp_nlinkp)3695b6c6a9aShannken msdosfs_gro_rename(struct mount *mp, kauth_cred_t cred,
3705b6c6a9aShannken struct vnode *fdvp, struct componentname *fcnp,
3715b6c6a9aShannken void *fde, struct vnode *fvp,
3725b6c6a9aShannken struct vnode *tdvp, struct componentname *tcnp,
3735b6c6a9aShannken void *tde, struct vnode *tvp, nlink_t *tvp_nlinkp)
3745b6c6a9aShannken {
3755b6c6a9aShannken struct msdosfs_lookup_results *fmlr = fde;
3765b6c6a9aShannken struct msdosfs_lookup_results *tmlr = tde;
3775b6c6a9aShannken struct msdosfsmount *pmp;
3785b6c6a9aShannken bool directory_p, reparent_p;
3795b6c6a9aShannken unsigned char toname[12], oldname[12];
3805b6c6a9aShannken int error;
3815b6c6a9aShannken
3825b6c6a9aShannken KASSERT(mp != NULL);
3835b6c6a9aShannken KASSERT(fdvp != NULL);
3845b6c6a9aShannken KASSERT(fcnp != NULL);
3855b6c6a9aShannken KASSERT(fmlr != NULL);
3865b6c6a9aShannken KASSERT(fvp != NULL);
3875b6c6a9aShannken KASSERT(tdvp != NULL);
3885b6c6a9aShannken KASSERT(tcnp != NULL);
3895b6c6a9aShannken KASSERT(tmlr != NULL);
3905b6c6a9aShannken KASSERT(fmlr != tmlr);
3915b6c6a9aShannken KASSERT(fdvp != fvp);
3925b6c6a9aShannken KASSERT(fdvp != tvp);
3935b6c6a9aShannken KASSERT(tdvp != fvp);
3945b6c6a9aShannken KASSERT(tdvp != tvp);
3955b6c6a9aShannken KASSERT(fvp != tvp);
3965b6c6a9aShannken KASSERT(fdvp->v_mount == mp);
3975b6c6a9aShannken KASSERT(fvp->v_mount == mp);
3985b6c6a9aShannken KASSERT(tdvp->v_mount == mp);
3995b6c6a9aShannken KASSERT((tvp == NULL) || (tvp->v_mount == mp));
4005b6c6a9aShannken KASSERT(VOP_ISLOCKED(fdvp) == LK_EXCLUSIVE);
4015b6c6a9aShannken KASSERT(VOP_ISLOCKED(fvp) == LK_EXCLUSIVE);
4025b6c6a9aShannken KASSERT(VOP_ISLOCKED(tdvp) == LK_EXCLUSIVE);
4035b6c6a9aShannken KASSERT((tvp == NULL) || (VOP_ISLOCKED(tvp) == LK_EXCLUSIVE));
4045b6c6a9aShannken
4055b6c6a9aShannken /*
4065b6c6a9aShannken * We shall need to temporarily bump the reference count, so
4075b6c6a9aShannken * make sure there is room to do so.
4085b6c6a9aShannken */
4095b6c6a9aShannken if (VTODE(fvp)->de_refcnt >= LONG_MAX)
4105b6c6a9aShannken return EMLINK;
4115b6c6a9aShannken
4125b6c6a9aShannken /*
4135b6c6a9aShannken * XXX There is a pile of logic here to handle a voodoo flag
4145b6c6a9aShannken * DE_RENAME. I think this is a vestige of days when the file
4155b6c6a9aShannken * system hackers didn't understand concurrency or race
4165b6c6a9aShannken * conditions; I believe it serves no useful function
4175b6c6a9aShannken * whatsoever.
4185b6c6a9aShannken */
4195b6c6a9aShannken
4205b6c6a9aShannken directory_p = (fvp->v_type == VDIR);
4215b6c6a9aShannken KASSERT(directory_p ==
4225b6c6a9aShannken ((VTODE(fvp)->de_Attributes & ATTR_DIRECTORY) != 0));
4235b6c6a9aShannken KASSERT((tvp == NULL) || (directory_p == (tvp->v_type == VDIR)));
4245b6c6a9aShannken KASSERT((tvp == NULL) || (directory_p ==
4255b6c6a9aShannken ((VTODE(fvp)->de_Attributes & ATTR_DIRECTORY) != 0)));
4265b6c6a9aShannken if (directory_p) {
4275b6c6a9aShannken if (VTODE(fvp)->de_flag & DE_RENAME)
4285b6c6a9aShannken return EINVAL;
4295b6c6a9aShannken VTODE(fvp)->de_flag |= DE_RENAME;
4305b6c6a9aShannken }
4315b6c6a9aShannken
4325b6c6a9aShannken reparent_p = (fdvp != tdvp);
4335b6c6a9aShannken KASSERT(reparent_p == (VTODE(fdvp)->de_StartCluster !=
4345b6c6a9aShannken VTODE(tdvp)->de_StartCluster));
4355b6c6a9aShannken
4365b6c6a9aShannken /*
4375b6c6a9aShannken * XXX Hold it right there -- surely if we crash after
4385b6c6a9aShannken * removede, we'll fail to provide rename's guarantee that
4395b6c6a9aShannken * there will be something at the target pathname?
4405b6c6a9aShannken */
4415b6c6a9aShannken if (tvp != NULL) {
4428086f46eSthorpej error = msdosfs_removede(VTODE(tdvp), VTODE(tvp), tmlr);
4435b6c6a9aShannken if (error)
4445b6c6a9aShannken goto out;
445e99cb814Shannken }
446e99cb814Shannken
447e99cb814Shannken /*
448e99cb814Shannken * Convert the filename in tcnp into a dos filename. We copy this
449e99cb814Shannken * into the denode and directory entry for the destination
450e99cb814Shannken * file/directory.
451e99cb814Shannken */
4528086f46eSthorpej error = msdosfs_uniqdosname(VTODE(tdvp), tcnp, toname);
4535b6c6a9aShannken if (error)
4545b6c6a9aShannken goto out;
455e99cb814Shannken
456e99cb814Shannken /*
4575b6c6a9aShannken * First write a new entry in the destination directory and
4585b6c6a9aShannken * mark the entry in the source directory as deleted. Then
4595b6c6a9aShannken * move the denode to the correct hash chain for its new
4605b6c6a9aShannken * location in the filesystem. And, if we moved a directory,
4615b6c6a9aShannken * then update its .. entry to point to the new parent
4625b6c6a9aShannken * directory.
463e99cb814Shannken */
464e99cb814Shannken
4655b6c6a9aShannken /* Save the old name in case we need to back out. */
4665b6c6a9aShannken memcpy(oldname, VTODE(fvp)->de_Name, 11);
4675b6c6a9aShannken memcpy(VTODE(fvp)->de_Name, toname, 11);
468e99cb814Shannken
4698086f46eSthorpej error = msdosfs_createde(VTODE(fvp), VTODE(tdvp), tmlr, 0, tcnp);
470e99cb814Shannken if (error) {
4715b6c6a9aShannken /* Directory entry didn't take -- back out the name change. */
4725b6c6a9aShannken memcpy(VTODE(fvp)->de_Name, oldname, 11);
4735b6c6a9aShannken goto out;
474e99cb814Shannken }
475e99cb814Shannken
4765b6c6a9aShannken /*
4775b6c6a9aShannken * createde doesn't increment de_refcnt, but removede
4785b6c6a9aShannken * decrements it. Go figure.
4795b6c6a9aShannken */
4805b6c6a9aShannken KASSERT(VTODE(fvp)->de_refcnt < LONG_MAX);
4815b6c6a9aShannken VTODE(fvp)->de_refcnt++;
4825b6c6a9aShannken
4835b6c6a9aShannken /*
4845b6c6a9aShannken * XXX Yes, createde and removede have arguments swapped. Go figure.
4855b6c6a9aShannken */
4868086f46eSthorpej error = msdosfs_removede(VTODE(fdvp), VTODE(fvp), fmlr);
487e99cb814Shannken if (error) {
4885b6c6a9aShannken #if 0 /* XXX Back out the new directory entry? Panic? */
4898086f46eSthorpej (void)msdosfs_removede(VTODE(tdvp), VTODE(fvp), tmlr);
4905b6c6a9aShannken memcpy(VTODE(fvp)->de_Name, oldname, 11);
4915b6c6a9aShannken #endif
4925b6c6a9aShannken goto out;
493e99cb814Shannken }
4945b6c6a9aShannken
4955b6c6a9aShannken pmp = VFSTOMSDOSFS(mp);
4965b6c6a9aShannken
4975b6c6a9aShannken if (!directory_p) {
4985b6c6a9aShannken struct denode_key old_key = VTODE(fvp)->de_key;
4995b6c6a9aShannken struct denode_key new_key = VTODE(fvp)->de_key;
5005b6c6a9aShannken
5018086f46eSthorpej error = msdosfs_pcbmap(VTODE(tdvp),
5025b6c6a9aShannken de_cluster(pmp, tmlr->mlr_fndoffset), NULL,
5035b6c6a9aShannken &new_key.dk_dirclust, NULL);
5045b6c6a9aShannken if (error) /* XXX Back everything out? Panic? */
5055b6c6a9aShannken goto out;
5065b6c6a9aShannken new_key.dk_diroffset = tmlr->mlr_fndoffset;
507e99cb814Shannken if (new_key.dk_dirclust != MSDOSFSROOT)
508e99cb814Shannken new_key.dk_diroffset &= pmp->pm_crbomask;
509e99cb814Shannken vcache_rekey_enter(pmp->pm_mountp, fvp, &old_key,
510e99cb814Shannken sizeof(old_key), &new_key, sizeof(new_key));
5115b6c6a9aShannken VTODE(fvp)->de_key = new_key;
512e99cb814Shannken vcache_rekey_exit(pmp->pm_mountp, fvp, &old_key,
5135b6c6a9aShannken sizeof(old_key), &VTODE(fvp)->de_key,
5145b6c6a9aShannken sizeof(VTODE(fvp)->de_key));
515e99cb814Shannken }
516e99cb814Shannken
517e99cb814Shannken /*
518e99cb814Shannken * If we moved a directory to a new parent directory, then we must
519e99cb814Shannken * fixup the ".." entry in the moved directory.
520e99cb814Shannken */
5215b6c6a9aShannken if (directory_p && reparent_p) {
5225b6c6a9aShannken error = msdosfs_rename_replace_dotdot(fvp, fdvp, tdvp, cred);
5235b6c6a9aShannken if (error)
5245b6c6a9aShannken goto out;
5255b6c6a9aShannken }
5265b6c6a9aShannken
5275b6c6a9aShannken out:;
5285b6c6a9aShannken if (tvp != NULL)
5295b6c6a9aShannken *tvp_nlinkp = (error ? 1 : 0);
5305b6c6a9aShannken
5315b6c6a9aShannken genfs_rename_cache_purge(fdvp, fvp, tdvp, tvp);
5325b6c6a9aShannken
5335b6c6a9aShannken if (directory_p)
5345b6c6a9aShannken VTODE(fvp)->de_flag &=~ DE_RENAME;
5355b6c6a9aShannken
5365b6c6a9aShannken return error;
5375b6c6a9aShannken }
5385b6c6a9aShannken
5395b6c6a9aShannken /*
5405b6c6a9aShannken * msdosfs_gro_remove: Rename an object over another link to itself,
5415b6c6a9aShannken * effectively removing just the original link.
5425b6c6a9aShannken */
5435b6c6a9aShannken static int
msdosfs_gro_remove(struct mount * mp,kauth_cred_t cred,struct vnode * dvp,struct componentname * cnp,void * de,struct vnode * vp,nlink_t * tvp_nlinkp)5445b6c6a9aShannken msdosfs_gro_remove(struct mount *mp, kauth_cred_t cred,
5455b6c6a9aShannken struct vnode *dvp, struct componentname *cnp, void *de, struct vnode *vp,
5465b6c6a9aShannken nlink_t *tvp_nlinkp)
5475b6c6a9aShannken {
5485b6c6a9aShannken struct msdosfs_lookup_results *mlr = de;
5495b6c6a9aShannken int error;
5505b6c6a9aShannken
5515b6c6a9aShannken KASSERT(mp != NULL);
5525b6c6a9aShannken KASSERT(dvp != NULL);
5535b6c6a9aShannken KASSERT(cnp != NULL);
5545b6c6a9aShannken KASSERT(mlr != NULL);
5555b6c6a9aShannken KASSERT(vp != NULL);
5565b6c6a9aShannken KASSERT(dvp != vp);
5575b6c6a9aShannken KASSERT(dvp->v_mount == mp);
5585b6c6a9aShannken KASSERT(vp->v_mount == mp);
5595b6c6a9aShannken KASSERT(dvp->v_type == VDIR);
5605b6c6a9aShannken KASSERT(vp->v_type != VDIR);
5615b6c6a9aShannken KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
5625b6c6a9aShannken KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
5635b6c6a9aShannken
5648086f46eSthorpej error = msdosfs_removede(VTODE(dvp), VTODE(vp), mlr);
5655b6c6a9aShannken
5665b6c6a9aShannken *tvp_nlinkp = (error ? 1 : 0);
5675b6c6a9aShannken
5685b6c6a9aShannken return error;
5695b6c6a9aShannken }
5705b6c6a9aShannken
5715b6c6a9aShannken /*
5725b6c6a9aShannken * msdosfs_gro_lookup: Look up and save the lookup results.
5735b6c6a9aShannken */
5745b6c6a9aShannken static int
msdosfs_gro_lookup(struct mount * mp,struct vnode * dvp,struct componentname * cnp,void * de_ret,struct vnode ** vp_ret)5755b6c6a9aShannken msdosfs_gro_lookup(struct mount *mp, struct vnode *dvp,
5765b6c6a9aShannken struct componentname *cnp, void *de_ret, struct vnode **vp_ret)
5775b6c6a9aShannken {
5785b6c6a9aShannken struct msdosfs_lookup_results *mlr_ret = de_ret;
5795b6c6a9aShannken struct vnode *vp;
5805b6c6a9aShannken int error;
5815b6c6a9aShannken
5825b6c6a9aShannken (void)mp;
5835b6c6a9aShannken KASSERT(mp != NULL);
5845b6c6a9aShannken KASSERT(dvp != NULL);
5855b6c6a9aShannken KASSERT(cnp != NULL);
5865b6c6a9aShannken KASSERT(mlr_ret != NULL);
5875b6c6a9aShannken KASSERT(vp_ret != NULL);
5885b6c6a9aShannken KASSERT(VOP_ISLOCKED(dvp) == LK_EXCLUSIVE);
5895b6c6a9aShannken
5905b6c6a9aShannken /* Kludge cargo-culted from dholland's ufs_rename. */
5915b6c6a9aShannken cnp->cn_flags &=~ MODMASK;
5925b6c6a9aShannken cnp->cn_flags |= (LOCKPARENT | LOCKLEAF);
5935b6c6a9aShannken
5945b6c6a9aShannken error = relookup(dvp, &vp, cnp, 0);
5955b6c6a9aShannken if ((error == 0) && (vp == NULL)) {
5965b6c6a9aShannken error = ENOENT;
5975b6c6a9aShannken goto out;
5985b6c6a9aShannken }
5995b6c6a9aShannken if (error)
6005b6c6a9aShannken return error;
6015b6c6a9aShannken
6025b6c6a9aShannken /*
6035b6c6a9aShannken * Thanks to VFS insanity, relookup locks vp, which screws us
6045b6c6a9aShannken * in various ways.
6055b6c6a9aShannken */
6065b6c6a9aShannken VOP_UNLOCK(vp);
6075b6c6a9aShannken
6085b6c6a9aShannken out:
6095b6c6a9aShannken *mlr_ret = VTODE(dvp)->de_crap;
6105b6c6a9aShannken *vp_ret = vp;
6115b6c6a9aShannken return error;
6125b6c6a9aShannken }
6135b6c6a9aShannken
6145b6c6a9aShannken /*
6155b6c6a9aShannken * msdosfs_rmdired_p: Check whether the directory vp has been rmdired.
6165b6c6a9aShannken *
6175b6c6a9aShannken * vp must be locked and referenced.
6185b6c6a9aShannken */
6195b6c6a9aShannken static bool
msdosfs_rmdired_p(struct vnode * vp)6205b6c6a9aShannken msdosfs_rmdired_p(struct vnode *vp)
6215b6c6a9aShannken {
6225b6c6a9aShannken
6235b6c6a9aShannken KASSERT(vp != NULL);
6245b6c6a9aShannken KASSERT(VOP_ISLOCKED(vp) == LK_EXCLUSIVE);
6255b6c6a9aShannken KASSERT(vp->v_type == VDIR);
6265b6c6a9aShannken
6275b6c6a9aShannken return (VTODE(vp)->de_FileSize == 0);
6285b6c6a9aShannken }
6295b6c6a9aShannken
6305b6c6a9aShannken /*
6315b6c6a9aShannken * msdosfs_gro_genealogy: Analyze the genealogy of the source and target
6325b6c6a9aShannken * directories.
6335b6c6a9aShannken */
6345b6c6a9aShannken static int
msdosfs_gro_genealogy(struct mount * mp,kauth_cred_t cred,struct vnode * fdvp,struct vnode * tdvp,struct vnode ** intermediate_node_ret)6355b6c6a9aShannken msdosfs_gro_genealogy(struct mount *mp, kauth_cred_t cred,
6365b6c6a9aShannken struct vnode *fdvp, struct vnode *tdvp,
6375b6c6a9aShannken struct vnode **intermediate_node_ret)
6385b6c6a9aShannken {
6395b6c6a9aShannken struct msdosfsmount *pmp;
6405b6c6a9aShannken struct vnode *vp, *dvp;
6415b6c6a9aShannken unsigned long dotdot_cn;
6425b6c6a9aShannken int error;
6435b6c6a9aShannken
6445b6c6a9aShannken KASSERT(mp != NULL);
6455b6c6a9aShannken KASSERT(fdvp != NULL);
6465b6c6a9aShannken KASSERT(tdvp != NULL);
6475b6c6a9aShannken KASSERT(fdvp != tdvp);
6485b6c6a9aShannken KASSERT(intermediate_node_ret != NULL);
6495b6c6a9aShannken KASSERT(fdvp->v_mount == mp);
6505b6c6a9aShannken KASSERT(tdvp->v_mount == mp);
6515b6c6a9aShannken KASSERT(fdvp->v_type == VDIR);
6525b6c6a9aShannken KASSERT(tdvp->v_type == VDIR);
6535b6c6a9aShannken
6545b6c6a9aShannken pmp = VFSTOMSDOSFS(mp);
6555b6c6a9aShannken KASSERT(pmp != NULL);
6565b6c6a9aShannken
6575b6c6a9aShannken /*
6585b6c6a9aShannken * We need to provisionally lock tdvp to keep rmdir from
6595b6c6a9aShannken * deleting it -- or any ancestor -- at an inopportune moment.
6605b6c6a9aShannken */
6615b6c6a9aShannken error = msdosfs_gro_lock_directory(mp, tdvp);
6625b6c6a9aShannken if (error)
6635b6c6a9aShannken return error;
6645b6c6a9aShannken
6655b6c6a9aShannken vp = tdvp;
6665b6c6a9aShannken vref(vp);
6675b6c6a9aShannken
6685b6c6a9aShannken for (;;) {
6695b6c6a9aShannken KASSERT(vp->v_type == VDIR);
6705b6c6a9aShannken
6715b6c6a9aShannken /* Did we hit the root without finding fdvp? */
6725b6c6a9aShannken if ((vp->v_vflag & VV_ROOT) != 0) {
6735b6c6a9aShannken vput(vp);
6745b6c6a9aShannken *intermediate_node_ret = NULL;
6755b6c6a9aShannken return 0;
6765b6c6a9aShannken }
6775b6c6a9aShannken
6785b6c6a9aShannken error = msdosfs_read_dotdot(vp, cred, &dotdot_cn);
6795b6c6a9aShannken if (error) {
6805b6c6a9aShannken vput(vp);
6815b6c6a9aShannken return error;
6825b6c6a9aShannken }
6835b6c6a9aShannken
6845b6c6a9aShannken /* Did we find that fdvp is an ancestor? */
6855b6c6a9aShannken if (VTODE(fdvp)->de_StartCluster == dotdot_cn) {
6865b6c6a9aShannken /* Unlock vp, but keep it referenced. */
6875b6c6a9aShannken VOP_UNLOCK(vp);
6885b6c6a9aShannken *intermediate_node_ret = vp;
6895b6c6a9aShannken return 0;
6905b6c6a9aShannken }
6915b6c6a9aShannken
6925b6c6a9aShannken /* Neither -- keep ascending. */
6935b6c6a9aShannken
6948086f46eSthorpej error = msdosfs_deget(pmp, dotdot_cn,
6958086f46eSthorpej (dotdot_cn ? 0 : MSDOSFSROOT_OFS), &dvp);
6965b6c6a9aShannken vput(vp);
6975b6c6a9aShannken if (error)
6985b6c6a9aShannken return error;
6995b6c6a9aShannken error = vn_lock(dvp, LK_EXCLUSIVE);
7005b6c6a9aShannken if (error) {
7015b6c6a9aShannken vrele(dvp);
7025b6c6a9aShannken return error;
7035b6c6a9aShannken }
7045b6c6a9aShannken
7055b6c6a9aShannken KASSERT(dvp != NULL);
7065b6c6a9aShannken KASSERT(dvp->v_type == VDIR);
7075b6c6a9aShannken
7085b6c6a9aShannken vp = dvp;
7095b6c6a9aShannken
7105b6c6a9aShannken if (msdosfs_rmdired_p(vp)) {
7115b6c6a9aShannken vput(vp);
7125b6c6a9aShannken return ENOENT;
7135b6c6a9aShannken }
7145b6c6a9aShannken }
7155b6c6a9aShannken }
7165b6c6a9aShannken
7175b6c6a9aShannken /*
7185b6c6a9aShannken * msdosfs_read_dotdot: Store in *cn_ret the cluster number of the
7195b6c6a9aShannken * parent of the directory vp.
7205b6c6a9aShannken */
7215b6c6a9aShannken static int
msdosfs_read_dotdot(struct vnode * vp,kauth_cred_t cred,unsigned long * cn_ret)7225b6c6a9aShannken msdosfs_read_dotdot(struct vnode *vp, kauth_cred_t cred, unsigned long *cn_ret)
7235b6c6a9aShannken {
7245b6c6a9aShannken struct msdosfsmount *pmp;
7255b6c6a9aShannken unsigned long start_cn, cn;
7265b6c6a9aShannken struct buf *bp;
7275b6c6a9aShannken struct direntry *ep;
7285b6c6a9aShannken int error;
7295b6c6a9aShannken
7305b6c6a9aShannken KASSERT(vp != NULL);
7315b6c6a9aShannken KASSERT(cn_ret != NULL);
7325b6c6a9aShannken KASSERT(vp->v_type == VDIR);
7335b6c6a9aShannken KASSERT(VTODE(vp) != NULL);
7345b6c6a9aShannken
7355b6c6a9aShannken pmp = VTODE(vp)->de_pmp;
7365b6c6a9aShannken KASSERT(pmp != NULL);
7375b6c6a9aShannken
7385b6c6a9aShannken start_cn = VTODE(vp)->de_StartCluster;
7395b6c6a9aShannken error = bread(pmp->pm_devvp, de_bn2kb(pmp, cntobn(pmp, start_cn)),
7405b6c6a9aShannken pmp->pm_bpcluster, 0, &bp);
7415b6c6a9aShannken if (error)
7425b6c6a9aShannken return error;
7435b6c6a9aShannken
7445b6c6a9aShannken ep = (struct direntry *)bp->b_data + 1;
7455b6c6a9aShannken if (((ep->deAttributes & ATTR_DIRECTORY) == ATTR_DIRECTORY) &&
7465b6c6a9aShannken (memcmp(ep->deName, ".. ", 11) == 0)) {
7475b6c6a9aShannken cn = getushort(ep->deStartCluster);
7485b6c6a9aShannken if (FAT32(pmp))
7495b6c6a9aShannken cn |= getushort(ep->deHighClust) << 16;
7505b6c6a9aShannken *cn_ret = cn;
7515b6c6a9aShannken error = 0;
7525b6c6a9aShannken } else {
7535b6c6a9aShannken error = ENOTDIR;
7545b6c6a9aShannken }
7555b6c6a9aShannken
7565b6c6a9aShannken brelse(bp, 0);
7575b6c6a9aShannken
7585b6c6a9aShannken return error;
7595b6c6a9aShannken }
7605b6c6a9aShannken
7615b6c6a9aShannken /*
7625b6c6a9aShannken * msdosfs_rename_replace_dotdot: Change the target of the `..' entry of
7635b6c6a9aShannken * the directory vp from fdvp to tdvp.
7645b6c6a9aShannken */
7655b6c6a9aShannken static int
msdosfs_rename_replace_dotdot(struct vnode * vp,struct vnode * fdvp,struct vnode * tdvp,kauth_cred_t cred)7665b6c6a9aShannken msdosfs_rename_replace_dotdot(struct vnode *vp,
7675b6c6a9aShannken struct vnode *fdvp, struct vnode *tdvp,
7685b6c6a9aShannken kauth_cred_t cred)
7695b6c6a9aShannken {
7705b6c6a9aShannken struct msdosfsmount *pmp;
7715b6c6a9aShannken struct direntry *dotdotp;
7725b6c6a9aShannken struct buf *bp;
7735b6c6a9aShannken daddr_t bn;
7745b6c6a9aShannken u_long cn;
7755b6c6a9aShannken int error;
7765b6c6a9aShannken
7775b6c6a9aShannken pmp = VFSTOMSDOSFS(fdvp->v_mount);
7785b6c6a9aShannken
7795b6c6a9aShannken cn = VTODE(vp)->de_StartCluster;
780e99cb814Shannken if (cn == MSDOSFSROOT) {
781e99cb814Shannken /* this should never happen */
782e99cb814Shannken panic("msdosfs_rename: updating .. in root directory?");
783e99cb814Shannken } else
784e99cb814Shannken bn = cntobn(pmp, cn);
7855b6c6a9aShannken
786e99cb814Shannken error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn),
787e99cb814Shannken pmp->pm_bpcluster, B_MODIFY, &bp);
7885b6c6a9aShannken if (error)
7895b6c6a9aShannken return error;
7905b6c6a9aShannken
791e99cb814Shannken dotdotp = (struct direntry *)bp->b_data + 1;
7925b6c6a9aShannken putushort(dotdotp->deStartCluster, VTODE(tdvp)->de_StartCluster);
793e99cb814Shannken if (FAT32(pmp)) {
794e99cb814Shannken putushort(dotdotp->deHighClust,
7955b6c6a9aShannken VTODE(tdvp)->de_StartCluster >> 16);
796e99cb814Shannken } else {
797e99cb814Shannken putushort(dotdotp->deHighClust, 0);
798e99cb814Shannken }
799e99cb814Shannken
8005b6c6a9aShannken error = bwrite(bp);
801e99cb814Shannken
8025b6c6a9aShannken return error;
803e99cb814Shannken }
804e99cb814Shannken
805e99cb814Shannken /*
8065b6c6a9aShannken * msdosfs_gro_lock_directory: Lock the directory vp, but fail if it has
8075b6c6a9aShannken * been rmdir'd.
808e99cb814Shannken */
8095b6c6a9aShannken static int
msdosfs_gro_lock_directory(struct mount * mp,struct vnode * vp)8105b6c6a9aShannken msdosfs_gro_lock_directory(struct mount *mp, struct vnode *vp)
811e99cb814Shannken {
8125b6c6a9aShannken int error;
813e99cb814Shannken
8145b6c6a9aShannken (void)mp;
8155b6c6a9aShannken KASSERT(vp != NULL);
816e99cb814Shannken
817e99cb814Shannken error = vn_lock(vp, LK_EXCLUSIVE);
8185b6c6a9aShannken if (error)
8195b6c6a9aShannken return error;
8205b6c6a9aShannken
8215b6c6a9aShannken KASSERT(mp != NULL);
8225b6c6a9aShannken KASSERT(vp->v_mount == mp);
8235b6c6a9aShannken
8245b6c6a9aShannken if (msdosfs_rmdired_p(vp)) {
8255b6c6a9aShannken VOP_UNLOCK(vp);
8265b6c6a9aShannken return ENOENT;
827e99cb814Shannken }
8285b6c6a9aShannken
8295b6c6a9aShannken return 0;
830e99cb814Shannken }
8315b6c6a9aShannken
8325b6c6a9aShannken static const struct genfs_rename_ops msdosfs_genfs_rename_ops = {
8335b6c6a9aShannken .gro_directory_empty_p = msdosfs_gro_directory_empty_p,
8345b6c6a9aShannken .gro_rename_check_possible = msdosfs_gro_rename_check_possible,
8355b6c6a9aShannken .gro_rename_check_permitted = msdosfs_gro_rename_check_permitted,
8365b6c6a9aShannken .gro_remove_check_possible = msdosfs_gro_remove_check_possible,
8375b6c6a9aShannken .gro_remove_check_permitted = msdosfs_gro_remove_check_permitted,
8385b6c6a9aShannken .gro_rename = msdosfs_gro_rename,
8395b6c6a9aShannken .gro_remove = msdosfs_gro_remove,
8405b6c6a9aShannken .gro_lookup = msdosfs_gro_lookup,
8415b6c6a9aShannken .gro_genealogy = msdosfs_gro_genealogy,
8425b6c6a9aShannken .gro_lock_directory = msdosfs_gro_lock_directory,
8435b6c6a9aShannken };
844