Module Name:    src
Committed By:   hannken
Date:           Sat Oct 23 07:41:38 UTC 2021

Modified Files:
        src/sys/fs/msdosfs: files.msdosfs msdosfs_lookup.c msdosfs_vnops.c
        src/sys/modules/msdos: Makefile
        src/sys/rump/fs/lib/libmsdos: Makefile
Added Files:
        src/sys/fs/msdosfs: msdosfs_rename.c

Log Message:
Move msdosfs_rename() and doscheckpath() to new file msdosfs_rename.c.

No functional change.


To generate a diff of this commit:
cvs rdiff -u -r1.3 -r1.4 src/sys/fs/msdosfs/files.msdosfs
cvs rdiff -u -r1.38 -r1.39 src/sys/fs/msdosfs/msdosfs_lookup.c
cvs rdiff -u -r0 -r1.1 src/sys/fs/msdosfs/msdosfs_rename.c
cvs rdiff -u -r1.108 -r1.109 src/sys/fs/msdosfs/msdosfs_vnops.c
cvs rdiff -u -r1.3 -r1.4 src/sys/modules/msdos/Makefile
cvs rdiff -u -r1.5 -r1.6 src/sys/rump/fs/lib/libmsdos/Makefile

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/fs/msdosfs/files.msdosfs
diff -u src/sys/fs/msdosfs/files.msdosfs:1.3 src/sys/fs/msdosfs/files.msdosfs:1.4
--- src/sys/fs/msdosfs/files.msdosfs:1.3	Sat Feb  6 10:40:58 2016
+++ src/sys/fs/msdosfs/files.msdosfs	Sat Oct 23 07:41:37 2021
@@ -1,4 +1,4 @@
-#	$NetBSD: files.msdosfs,v 1.3 2016/02/06 10:40:58 mlelstv Exp $
+#	$NetBSD: files.msdosfs,v 1.4 2021/10/23 07:41:37 hannken Exp $
 
 deffs	MSDOSFS
 
@@ -7,6 +7,7 @@ file	fs/msdosfs/msdosfs_conv.c		msdosfs
 file	fs/msdosfs/msdosfs_denode.c		msdosfs
 file	fs/msdosfs/msdosfs_fat.c		msdosfs
 file	fs/msdosfs/msdosfs_lookup.c		msdosfs
+file	fs/msdosfs/msdosfs_rename.c		msdosfs
 file	fs/msdosfs/msdosfs_vfsops.c		msdosfs
 file	fs/msdosfs/msdosfs_vnops.c		msdosfs
 file	fs/msdosfs/msdosfs_unicode.c		msdosfs

Index: src/sys/fs/msdosfs/msdosfs_lookup.c
diff -u src/sys/fs/msdosfs/msdosfs_lookup.c:1.38 src/sys/fs/msdosfs/msdosfs_lookup.c:1.39
--- src/sys/fs/msdosfs/msdosfs_lookup.c:1.38	Sat Oct 23 07:38:33 2021
+++ src/sys/fs/msdosfs/msdosfs_lookup.c	Sat Oct 23 07:41:37 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: msdosfs_lookup.c,v 1.38 2021/10/23 07:38:33 hannken Exp $	*/
+/*	$NetBSD: msdosfs_lookup.c,v 1.39 2021/10/23 07:41:37 hannken Exp $	*/
 
 /*-
  * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
@@ -52,7 +52,7 @@
 #endif
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: msdosfs_lookup.c,v 1.38 2021/10/23 07:38:33 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: msdosfs_lookup.c,v 1.39 2021/10/23 07:41:37 hannken Exp $");
 
 #include <sys/param.h>
 
@@ -830,116 +830,6 @@ dosdirempty(struct denode *dep)
 }
 
 /*
- * Check to see if the directory described by target is in some
- * subdirectory of source.  This prevents something like the following from
- * succeeding and leaving a bunch or files and directories orphaned. mv
- * /a/b/c /a/b/c/d/e/f Where c and f are directories.
- *
- * source - the inode for /a/b/c
- * target - the inode for /a/b/c/d/e/f
- *
- * Returns 0 if target is NOT a subdirectory of source.
- * Otherwise returns a non-zero error number.
- * The target inode is always unlocked on return.
- */
-int
-doscheckpath(struct denode *source, struct denode *target)
-{
-	u_long scn;
-	struct msdosfsmount *pmp;
-	struct direntry *ep;
-	struct denode *dep;
-	struct buf *bp = NULL;
-	int error = 0;
-
-	dep = target;
-	if ((target->de_Attributes & ATTR_DIRECTORY) == 0 ||
-	    (source->de_Attributes & ATTR_DIRECTORY) == 0) {
-		error = ENOTDIR;
-		goto out;
-	}
-	if (dep->de_StartCluster == source->de_StartCluster) {
-		error = EEXIST;
-		goto out;
-	}
-	if (dep->de_StartCluster == MSDOSFSROOT)
-		goto out;
-	pmp = dep->de_pmp;
-#ifdef	DIAGNOSTIC
-	if (pmp != source->de_pmp)
-		panic("doscheckpath: source and target on different filesystems");
-#endif
-	if (FAT32(pmp) && dep->de_StartCluster == pmp->pm_rootdirblk)
-		goto out;
-
-	for (;;) {
-		if ((dep->de_Attributes & ATTR_DIRECTORY) == 0) {
-			error = ENOTDIR;
-			break;
-		}
-		scn = dep->de_StartCluster;
-		error = bread(pmp->pm_devvp, de_bn2kb(pmp, cntobn(pmp, scn)),
-			      pmp->pm_bpcluster, 0, &bp);
-		if (error)
-			break;
-
-		ep = (struct direntry *) bp->b_data + 1;
-		if ((ep->deAttributes & ATTR_DIRECTORY) == 0 ||
-		    memcmp(ep->deName, "..         ", 11) != 0) {
-			error = ENOTDIR;
-			break;
-		}
-		scn = getushort(ep->deStartCluster);
-		if (FAT32(pmp))
-			scn |= getushort(ep->deHighClust) << 16;
-
-		if (scn == source->de_StartCluster) {
-			error = EINVAL;
-			break;
-		}
-		if (scn == MSDOSFSROOT)
-			break;
-		if (FAT32(pmp) && scn == pmp->pm_rootdirblk) {
-			/*
-			 * scn should be 0 in this case,
-			 * but we silently ignore the error.
-			 */
-			break;
-		}
-
-		vput(DETOV(dep));
-		brelse(bp, 0);
-		bp = NULL;
-#ifdef MAKEFS
-		/* NOTE: deget() clears dep on error */
-		if ((error = deget(pmp, scn, 0, &dep)) != 0)
-			break;
-#else
-		struct vnode *vp;
-
-		dep = NULL;
-		error = deget(pmp, scn, 0, &vp);
-		if (error)
-			break;
-		error = vn_lock(vp, LK_EXCLUSIVE);
-		if (error) {
-			vrele(vp);
-			break;
-		}
-		dep = VTODE(vp);
-#endif
-	}
-out:
-	if (bp)
-		brelse(bp, 0);
-	if (error == ENOTDIR)
-		printf("doscheckpath(): .. not a directory?\n");
-	if (dep != NULL)
-		vput(DETOV(dep));
-	return (error);
-}
-
-/*
  * Read in the disk block containing the directory entry (dirclu, dirofs)
  * and return the address of the buf header, and the address of the
  * directory entry within the block.

Index: src/sys/fs/msdosfs/msdosfs_vnops.c
diff -u src/sys/fs/msdosfs/msdosfs_vnops.c:1.108 src/sys/fs/msdosfs/msdosfs_vnops.c:1.109
--- src/sys/fs/msdosfs/msdosfs_vnops.c:1.108	Sat Oct 23 07:38:33 2021
+++ src/sys/fs/msdosfs/msdosfs_vnops.c	Sat Oct 23 07:41:37 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: msdosfs_vnops.c,v 1.108 2021/10/23 07:38:33 hannken Exp $	*/
+/*	$NetBSD: msdosfs_vnops.c,v 1.109 2021/10/23 07:41:37 hannken Exp $	*/
 
 /*-
  * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
@@ -48,7 +48,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: msdosfs_vnops.c,v 1.108 2021/10/23 07:38:33 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: msdosfs_vnops.c,v 1.109 2021/10/23 07:41:37 hannken Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -739,389 +739,6 @@ msdosfs_remove(void *v)
 	return (error);
 }
 
-/*
- * Renames on files require moving the denode to a new hash queue since the
- * denode's location is used to compute which hash queue to put the file
- * in. Unless it is a rename in place.  For example "mv a b".
- *
- * What follows is the basic algorithm:
- *
- * if (file move) {
- *	if (dest file exists) {
- *		remove dest file
- *	}
- *	if (dest and src in same directory) {
- *		rewrite name in existing directory slot
- *	} else {
- *		write new entry in dest directory
- *		update offset and dirclust in denode
- *		move denode to new hash chain
- *		clear old directory entry
- *	}
- * } else {
- *	directory move
- *	if (dest directory exists) {
- *		if (dest is not empty) {
- *			return ENOTEMPTY
- *		}
- *		remove dest directory
- *	}
- *	if (dest and src in same directory) {
- *		rewrite name in existing entry
- *	} else {
- *		be sure dest is not a child of src directory
- *		write entry in dest directory
- *		update "." and ".." in moved directory
- *		update offset and dirclust in denode
- *		move denode to new hash chain
- *		clear old directory entry for moved directory
- *	}
- * }
- *
- * On entry:
- *	source's parent directory is unlocked
- *	source file or directory is unlocked
- *	destination's parent directory is locked
- *	destination file or directory is locked if it exists
- *
- * On exit:
- *	all denodes should be released
- *
- * Notes:
- * I'm not sure how the memory containing the pathnames pointed at by the
- * componentname structures is freed, there may be some memory bleeding
- * for each rename done.
- *
- * --More-- Notes:
- * This routine needs help.  badly.
- */
-int
-msdosfs_rename(void *v)
-{
-	struct vop_rename_args /* {
-		struct vnode *a_fdvp;
-		struct vnode *a_fvp;
-		struct componentname *a_fcnp;
-		struct vnode *a_tdvp;
-		struct vnode *a_tvp;
-		struct componentname *a_tcnp;
-	} */ *ap = v;
-	struct vnode *tvp = ap->a_tvp;
-	struct vnode *tdvp = ap->a_tdvp;
-	struct vnode *fvp = ap->a_fvp;
-	struct vnode *fdvp = ap->a_fdvp;
-	struct componentname *tcnp = ap->a_tcnp;
-	struct componentname *fcnp = ap->a_fcnp;
-	struct denode *ip, *xp, *dp, *zp;
-	u_char toname[12], oldname[12];
-	u_long from_diroffset, to_diroffset;
-	u_char to_count;
-	int doingdirectory = 0, newparent = 0;
-	int error;
-	u_long cn;
-	daddr_t bn;
-	struct msdosfsmount *pmp;
-	struct direntry *dotdotp;
-	struct buf *bp;
-
-	pmp = VFSTOMSDOSFS(fdvp->v_mount);
-
-	/*
-	 * Check for cross-device rename.
-	 */
-	if ((fvp->v_mount != tdvp->v_mount) ||
-	    (tvp && (fvp->v_mount != tvp->v_mount))) {
-		error = EXDEV;
-abortit:
-		VOP_ABORTOP(tdvp, tcnp);
-		if (tdvp == tvp)
-			vrele(tdvp);
-		else
-			vput(tdvp);
-		if (tvp)
-			vput(tvp);
-		VOP_ABORTOP(fdvp, fcnp);
-		vrele(fdvp);
-		vrele(fvp);
-		return (error);
-	}
-
-	/*
-	 * If source and dest are the same, do nothing.
-	 */
-	if (tvp == fvp) {
-		error = 0;
-		goto abortit;
-	}
-
-	/*
-	 * XXX: This can deadlock since we hold tdvp/tvp locked.
-	 * But I'm not going to fix it now.
-	 */
-	if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0)
-		goto abortit;
-	dp = VTODE(fdvp);
-	ip = VTODE(fvp);
-
-	/*
-	 * Be sure we are not renaming ".", "..", or an alias of ".". This
-	 * leads to a crippled directory tree.  It's pretty tough to do a
-	 * "ls" or "pwd" with the "." directory entry missing, and "cd .."
-	 * doesn't work if the ".." entry is missing.
-	 */
-	if (ip->de_Attributes & ATTR_DIRECTORY) {
-		/*
-		 * Avoid ".", "..", and aliases of "." for obvious reasons.
-		 */
-		if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
-		    dp == ip ||
-		    (fcnp->cn_flags & ISDOTDOT) ||
-		    (tcnp->cn_flags & ISDOTDOT) ||
-		    (ip->de_flag & DE_RENAME)) {
-			VOP_UNLOCK(fvp);
-			error = EINVAL;
-			goto abortit;
-		}
-		ip->de_flag |= DE_RENAME;
-		doingdirectory++;
-	}
-	VN_KNOTE(fdvp, NOTE_WRITE);		/* XXXLUKEM/XXX: right place? */
-
-	/*
-	 * When the target exists, both the directory
-	 * and target vnodes are returned locked.
-	 */
-	dp = VTODE(tdvp);
-	xp = tvp ? VTODE(tvp) : NULL;
-	/*
-	 * Remember direntry place to use for destination
-	 */
-	to_diroffset = dp->de_crap.mlr_fndoffset;
-	to_count = dp->de_crap.mlr_fndcnt;
-
-	/*
-	 * If ".." must be changed (ie the directory gets a new
-	 * parent) then the source directory must not be in the
-	 * directory hierarchy above the target, as this would
-	 * orphan everything below the source directory. Also
-	 * the user must have write permission in the source so
-	 * as to be able to change "..". We must repeat the call
-	 * to namei, as the parent directory is unlocked by the
-	 * call to doscheckpath().
-	 */
-	error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred);
-	VOP_UNLOCK(fvp);
-	if (VTODE(fdvp)->de_StartCluster != VTODE(tdvp)->de_StartCluster)
-		newparent = 1;
-
-	if (doingdirectory && newparent) {
-		if (error)	/* write access check above */
-			goto tdvpbad;
-		if (xp != NULL)
-			vput(tvp);
-		tvp = NULL;
-		/*
-		 * doscheckpath() vput()'s tdvp (dp == VTODE(tdvp)),
-		 * so we have to get an extra ref to it first, and
-		 * because it's been unlocked we need to do a relookup
-		 * afterwards in case tvp has changed.
-		 */
-		vref(tdvp);
-		if ((error = doscheckpath(ip, dp)) != 0)
-			goto bad;
-		vn_lock(tdvp, LK_EXCLUSIVE | LK_RETRY);
-		if ((error = relookup(tdvp, &tvp, tcnp, 0)) != 0) {
-			VOP_UNLOCK(tdvp);
-			goto bad;
-		}
-		dp = VTODE(tdvp);
-		xp = tvp ? VTODE(tvp) : NULL;
-	}
-
-	if (xp != NULL) {
-		/*
-		 * Target must be empty if a directory and have no links
-		 * to it. Also, ensure source and target are compatible
-		 * (both directories, or both not directories).
-		 */
-		if (xp->de_Attributes & ATTR_DIRECTORY) {
-			if (!dosdirempty(xp)) {
-				error = ENOTEMPTY;
-				goto tdvpbad;
-			}
-			if (!doingdirectory) {
-				error = ENOTDIR;
-				goto tdvpbad;
-			}
-		} else if (doingdirectory) {
-			error = EISDIR;
-			goto tdvpbad;
-		}
-		if ((error = removede(dp, xp, &dp->de_crap)) != 0)
-			goto tdvpbad;
-		VN_KNOTE(tdvp, NOTE_WRITE);
-		VN_KNOTE(tvp, NOTE_DELETE);
-		cache_purge(tvp);
-		vput(tvp);
-		tvp = NULL;
-		xp = NULL;
-	}
-
-	/*
-	 * Convert the filename in tcnp into a dos filename. We copy this
-	 * into the denode and directory entry for the destination
-	 * file/directory.
-	 */
-	if ((error = uniqdosname(VTODE(tdvp), tcnp, toname)) != 0) {
-		goto abortit;
-	}
-
-	/*
-	 * Since from wasn't locked at various places above,
-	 * have to do a relookup here.
-	 */
-	fcnp->cn_flags &= ~MODMASK;
-	fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
-	VOP_UNLOCK(tdvp);
-	vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY);
-	if ((error = relookup(fdvp, &fvp, fcnp, 0))) {
-		VOP_UNLOCK(fdvp);
-		vrele(ap->a_fvp);
-		vrele(tdvp);
-		return (error);
-	}
-	if (fvp == NULL) {
-		/*
-		 * From name has disappeared.
-		 */
-		if (doingdirectory)
-			panic("rename: lost dir entry");
-		vput(fdvp);
-		vrele(ap->a_fvp);
-		vrele(tdvp);
-		return 0;
-	}
-	VOP_UNLOCK(fdvp);
-	xp = VTODE(fvp);
-	zp = VTODE(fdvp);
-	from_diroffset = zp->de_crap.mlr_fndoffset;
-
-	/*
-	 * Ensure that the directory entry still exists and has not
-	 * changed till now. If the source is a file the entry may
-	 * have been unlinked or renamed. In either case there is
-	 * no further work to be done. If the source is a directory
-	 * then it cannot have been rmdir'ed or renamed; this is
-	 * prohibited by the DE_RENAME flag.
-	 */
-	if (xp != ip) {
-		if (doingdirectory)
-			panic("rename: lost dir entry");
-		vrele(ap->a_fvp);
-		xp = NULL;
-	} else {
-		vrele(fvp);
-		xp = NULL;
-
-		/*
-		 * First write a new entry in the destination
-		 * directory and mark the entry in the source directory
-		 * as deleted.  Then move the denode to the correct hash
-		 * chain for its new location in the filesystem.  And, if
-		 * we moved a directory, then update its .. entry to point
-		 * to the new parent directory.
-		 */
-		memcpy(oldname, ip->de_Name, 11);
-		memcpy(ip->de_Name, toname, 11);	/* update denode */
-		dp->de_crap.mlr_fndoffset = to_diroffset;
-		dp->de_crap.mlr_fndcnt = to_count;
-		error = createde(ip, dp, &dp->de_crap, (struct denode **)0,
-		    tcnp);
-		if (error) {
-			memcpy(ip->de_Name, oldname, 11);
-			VOP_UNLOCK(fvp);
-			goto bad;
-		}
-		ip->de_refcnt++;
-		zp->de_crap.mlr_fndoffset = from_diroffset;
-		if ((error = removede(zp, ip, &zp->de_crap)) != 0) {
-			/* XXX should really panic here, fs is corrupt */
-			VOP_UNLOCK(fvp);
-			goto bad;
-		}
-		cache_purge(fvp);
-		if (!doingdirectory) {
-			struct denode_key old_key = ip->de_key;
-			struct denode_key new_key = ip->de_key;
-
-			error = pcbmap(dp, de_cluster(pmp, to_diroffset), 0,
-				       &new_key.dk_dirclust, 0);
-			if (error) {
-				/* XXX should really panic here, fs is corrupt */
-				VOP_UNLOCK(fvp);
-				goto bad;
-			}
-			new_key.dk_diroffset = to_diroffset;
-			if (new_key.dk_dirclust != MSDOSFSROOT)
-				new_key.dk_diroffset &= pmp->pm_crbomask;
-			vcache_rekey_enter(pmp->pm_mountp, fvp, &old_key,
-			    sizeof(old_key), &new_key, sizeof(new_key));
-			ip->de_key = new_key;
-			vcache_rekey_exit(pmp->pm_mountp, fvp, &old_key,
-			    sizeof(old_key), &ip->de_key, sizeof(ip->de_key));
-		}
-	}
-
-	/*
-	 * If we moved a directory to a new parent directory, then we must
-	 * fixup the ".." entry in the moved directory.
-	 */
-	if (doingdirectory && newparent) {
-		cn = ip->de_StartCluster;
-		if (cn == MSDOSFSROOT) {
-			/* this should never happen */
-			panic("msdosfs_rename: updating .. in root directory?");
-		} else
-			bn = cntobn(pmp, cn);
-		error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn),
-		    pmp->pm_bpcluster, B_MODIFY, &bp);
-		if (error) {
-			/* XXX should really panic here, fs is corrupt */
-			VOP_UNLOCK(fvp);
-			goto bad;
-		}
-		dotdotp = (struct direntry *)bp->b_data + 1;
-		putushort(dotdotp->deStartCluster, dp->de_StartCluster);
-		if (FAT32(pmp)) {
-			putushort(dotdotp->deHighClust,
-				dp->de_StartCluster >> 16);
-		} else {
-			putushort(dotdotp->deHighClust, 0);
-		}
-		if ((error = bwrite(bp)) != 0) {
-			/* XXX should really panic here, fs is corrupt */
-			VOP_UNLOCK(fvp);
-			goto bad;
-		}
-	}
-
-	VN_KNOTE(fvp, NOTE_RENAME);
-	VOP_UNLOCK(fvp);
-bad:
-	if (tvp)
-		vput(tvp);
-	vrele(tdvp);
-	ip->de_flag &= ~DE_RENAME;
-	vrele(fdvp);
-	vrele(fvp);
-	return (error);
-
-	/* XXX: uuuh */
-tdvpbad:
-	VOP_UNLOCK(tdvp);
-	goto bad;
-}
-
 static const struct {
 	struct direntry dot;
 	struct direntry dotdot;

Index: src/sys/modules/msdos/Makefile
diff -u src/sys/modules/msdos/Makefile:1.3 src/sys/modules/msdos/Makefile:1.4
--- src/sys/modules/msdos/Makefile:1.3	Sun Feb 17 04:05:54 2019
+++ src/sys/modules/msdos/Makefile	Sat Oct 23 07:41:37 2021
@@ -1,4 +1,4 @@
-#	$NetBSD: Makefile,v 1.3 2019/02/17 04:05:54 rin Exp $
+#	$NetBSD: Makefile,v 1.4 2021/10/23 07:41:37 hannken Exp $
 
 .include "../Makefile.inc"
 
@@ -6,7 +6,7 @@
 
 KMOD=	msdos
 SRCS=	msdosfs_conv.c msdosfs_denode.c msdosfs_fat.c msdosfs_lookup.c \
-	msdosfs_vfsops.c msdosfs_vnops.c msdosfs_unicode.c
+	msdosfs_rename.c msdosfs_vfsops.c msdosfs_vnops.c msdosfs_unicode.c
 
 WARNS=	3
 

Index: src/sys/rump/fs/lib/libmsdos/Makefile
diff -u src/sys/rump/fs/lib/libmsdos/Makefile:1.5 src/sys/rump/fs/lib/libmsdos/Makefile:1.6
--- src/sys/rump/fs/lib/libmsdos/Makefile:1.5	Sun Sep  6 07:20:30 2020
+++ src/sys/rump/fs/lib/libmsdos/Makefile	Sat Oct 23 07:41:38 2021
@@ -1,4 +1,4 @@
-#	$NetBSD: Makefile,v 1.5 2020/09/06 07:20:30 mrg Exp $
+#	$NetBSD: Makefile,v 1.6 2021/10/23 07:41:38 hannken Exp $
 #
 
 .PATH:  ${.CURDIR}/../../../../fs/msdosfs
@@ -7,7 +7,7 @@ LIB=	rumpfs_msdos
 COMMENT=FAT
 
 SRCS=	msdosfs_conv.c msdosfs_fat.c msdosfs_vfsops.c msdosfs_denode.c	\
-	msdosfs_lookup.c msdosfs_vnops.c msdosfs_unicode.c
+	msdosfs_lookup.c msdosfs_rename.c msdosfs_vnops.c msdosfs_unicode.c
 
 CWARNFLAGS.gcc+=	${GCC_NO_ADDR_OF_PACKED_MEMBER}
 

Added files:

Index: src/sys/fs/msdosfs/msdosfs_rename.c
diff -u /dev/null src/sys/fs/msdosfs/msdosfs_rename.c:1.1
--- /dev/null	Sat Oct 23 07:41:38 2021
+++ src/sys/fs/msdosfs/msdosfs_rename.c	Sat Oct 23 07:41:37 2021
@@ -0,0 +1,513 @@
+/*	$NetBSD: msdosfs_rename.c,v 1.1 2021/10/23 07:41:37 hannken Exp $	*/
+
+/*-
+ * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
+ * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
+ * All rights reserved.
+ * Original code by Paul Popelka (pa...@uts.amdahl.com) (see below).
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *	This product includes software developed by TooLs GmbH.
+ * 4. The name of TooLs GmbH may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+/*
+ * Written by Paul Popelka (pa...@uts.amdahl.com)
+ *
+ * You can do anything you want with this software, just don't say you wrote
+ * it, and don't remove this notice.
+ *
+ * This software is provided "as is".
+ *
+ * The author supplies this software to be publicly redistributed on the
+ * understanding that the author is not responsible for the correct
+ * functioning of this software in any circumstances and is not liable for
+ * any damages caused by this software.
+ *
+ * October 1992
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/namei.h>
+#include <sys/resourcevar.h>	/* defines plimit structure in proc struct */
+#include <sys/kernel.h>
+#include <sys/file.h>		/* define FWRITE ... */
+#include <sys/stat.h>
+#include <sys/buf.h>
+#include <sys/proc.h>
+#include <sys/mount.h>
+#include <sys/vnode.h>
+#include <sys/signalvar.h>
+#include <sys/malloc.h>
+#include <sys/dirent.h>
+#include <sys/lockf.h>
+#include <sys/kauth.h>
+
+#include <miscfs/genfs/genfs.h>
+#include <miscfs/specfs/specdev.h> /* XXX */	/* defines v_rdev */
+
+#include <uvm/uvm_extern.h>
+
+#include <fs/msdosfs/bpb.h>
+#include <fs/msdosfs/direntry.h>
+#include <fs/msdosfs/denode.h>
+#include <fs/msdosfs/msdosfsmount.h>
+#include <fs/msdosfs/fat.h>
+
+int
+msdosfs_rename(void *v)
+{
+	struct vop_rename_args /* {
+		struct vnode *a_fdvp;
+		struct vnode *a_fvp;
+		struct componentname *a_fcnp;
+		struct vnode *a_tdvp;
+		struct vnode *a_tvp;
+		struct componentname *a_tcnp;
+	} */ *ap = v;
+	struct vnode *tvp = ap->a_tvp;
+	struct vnode *tdvp = ap->a_tdvp;
+	struct vnode *fvp = ap->a_fvp;
+	struct vnode *fdvp = ap->a_fdvp;
+	struct componentname *tcnp = ap->a_tcnp;
+	struct componentname *fcnp = ap->a_fcnp;
+	struct denode *ip, *xp, *dp, *zp;
+	u_char toname[12], oldname[12];
+	u_long from_diroffset, to_diroffset;
+	u_char to_count;
+	int doingdirectory = 0, newparent = 0;
+	int error;
+	u_long cn;
+	daddr_t bn;
+	struct msdosfsmount *pmp;
+	struct direntry *dotdotp;
+	struct buf *bp;
+
+	pmp = VFSTOMSDOSFS(fdvp->v_mount);
+
+	/*
+	 * Check for cross-device rename.
+	 */
+	if ((fvp->v_mount != tdvp->v_mount) ||
+	    (tvp && (fvp->v_mount != tvp->v_mount))) {
+		error = EXDEV;
+abortit:
+		VOP_ABORTOP(tdvp, tcnp);
+		if (tdvp == tvp)
+			vrele(tdvp);
+		else
+			vput(tdvp);
+		if (tvp)
+			vput(tvp);
+		VOP_ABORTOP(fdvp, fcnp);
+		vrele(fdvp);
+		vrele(fvp);
+		return (error);
+	}
+
+	/*
+	 * If source and dest are the same, do nothing.
+	 */
+	if (tvp == fvp) {
+		error = 0;
+		goto abortit;
+	}
+
+	/*
+	 * XXX: This can deadlock since we hold tdvp/tvp locked.
+	 * But I'm not going to fix it now.
+	 */
+	if ((error = vn_lock(fvp, LK_EXCLUSIVE)) != 0)
+		goto abortit;
+	dp = VTODE(fdvp);
+	ip = VTODE(fvp);
+
+	/*
+	 * Be sure we are not renaming ".", "..", or an alias of ".". This
+	 * leads to a crippled directory tree.  It's pretty tough to do a
+	 * "ls" or "pwd" with the "." directory entry missing, and "cd .."
+	 * doesn't work if the ".." entry is missing.
+	 */
+	if (ip->de_Attributes & ATTR_DIRECTORY) {
+		/*
+		 * Avoid ".", "..", and aliases of "." for obvious reasons.
+		 */
+		if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
+		    dp == ip ||
+		    (fcnp->cn_flags & ISDOTDOT) ||
+		    (tcnp->cn_flags & ISDOTDOT) ||
+		    (ip->de_flag & DE_RENAME)) {
+			VOP_UNLOCK(fvp);
+			error = EINVAL;
+			goto abortit;
+		}
+		ip->de_flag |= DE_RENAME;
+		doingdirectory++;
+	}
+	VN_KNOTE(fdvp, NOTE_WRITE);		/* XXXLUKEM/XXX: right place? */
+
+	/*
+	 * When the target exists, both the directory
+	 * and target vnodes are returned locked.
+	 */
+	dp = VTODE(tdvp);
+	xp = tvp ? VTODE(tvp) : NULL;
+	/*
+	 * Remember direntry place to use for destination
+	 */
+	to_diroffset = dp->de_crap.mlr_fndoffset;
+	to_count = dp->de_crap.mlr_fndcnt;
+
+	/*
+	 * If ".." must be changed (ie the directory gets a new
+	 * parent) then the source directory must not be in the
+	 * directory hierarchy above the target, as this would
+	 * orphan everything below the source directory. Also
+	 * the user must have write permission in the source so
+	 * as to be able to change "..". We must repeat the call
+	 * to namei, as the parent directory is unlocked by the
+	 * call to doscheckpath().
+	 */
+	error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred);
+	VOP_UNLOCK(fvp);
+	if (VTODE(fdvp)->de_StartCluster != VTODE(tdvp)->de_StartCluster)
+		newparent = 1;
+
+	if (doingdirectory && newparent) {
+		if (error)	/* write access check above */
+			goto tdvpbad;
+		if (xp != NULL)
+			vput(tvp);
+		tvp = NULL;
+		/*
+		 * doscheckpath() vput()'s tdvp (dp == VTODE(tdvp)),
+		 * so we have to get an extra ref to it first, and
+		 * because it's been unlocked we need to do a relookup
+		 * afterwards in case tvp has changed.
+		 */
+		vref(tdvp);
+		if ((error = doscheckpath(ip, dp)) != 0)
+			goto bad;
+		vn_lock(tdvp, LK_EXCLUSIVE | LK_RETRY);
+		if ((error = relookup(tdvp, &tvp, tcnp, 0)) != 0) {
+			VOP_UNLOCK(tdvp);
+			goto bad;
+		}
+		dp = VTODE(tdvp);
+		xp = tvp ? VTODE(tvp) : NULL;
+	}
+
+	if (xp != NULL) {
+		/*
+		 * Target must be empty if a directory and have no links
+		 * to it. Also, ensure source and target are compatible
+		 * (both directories, or both not directories).
+		 */
+		if (xp->de_Attributes & ATTR_DIRECTORY) {
+			if (!dosdirempty(xp)) {
+				error = ENOTEMPTY;
+				goto tdvpbad;
+			}
+			if (!doingdirectory) {
+				error = ENOTDIR;
+				goto tdvpbad;
+			}
+		} else if (doingdirectory) {
+			error = EISDIR;
+			goto tdvpbad;
+		}
+		if ((error = removede(dp, xp, &dp->de_crap)) != 0)
+			goto tdvpbad;
+		VN_KNOTE(tdvp, NOTE_WRITE);
+		VN_KNOTE(tvp, NOTE_DELETE);
+		cache_purge(tvp);
+		vput(tvp);
+		tvp = NULL;
+		xp = NULL;
+	}
+
+	/*
+	 * Convert the filename in tcnp into a dos filename. We copy this
+	 * into the denode and directory entry for the destination
+	 * file/directory.
+	 */
+	if ((error = uniqdosname(VTODE(tdvp), tcnp, toname)) != 0) {
+		goto abortit;
+	}
+
+	/*
+	 * Since from wasn't locked at various places above,
+	 * have to do a relookup here.
+	 */
+	fcnp->cn_flags &= ~MODMASK;
+	fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
+	VOP_UNLOCK(tdvp);
+	vn_lock(fdvp, LK_EXCLUSIVE | LK_RETRY);
+	if ((error = relookup(fdvp, &fvp, fcnp, 0))) {
+		VOP_UNLOCK(fdvp);
+		vrele(ap->a_fvp);
+		vrele(tdvp);
+		return (error);
+	}
+	if (fvp == NULL) {
+		/*
+		 * From name has disappeared.
+		 */
+		if (doingdirectory)
+			panic("rename: lost dir entry");
+		vput(fdvp);
+		vrele(ap->a_fvp);
+		vrele(tdvp);
+		return 0;
+	}
+	VOP_UNLOCK(fdvp);
+	xp = VTODE(fvp);
+	zp = VTODE(fdvp);
+	from_diroffset = zp->de_crap.mlr_fndoffset;
+
+	/*
+	 * Ensure that the directory entry still exists and has not
+	 * changed till now. If the source is a file the entry may
+	 * have been unlinked or renamed. In either case there is
+	 * no further work to be done. If the source is a directory
+	 * then it cannot have been rmdir'ed or renamed; this is
+	 * prohibited by the DE_RENAME flag.
+	 */
+	if (xp != ip) {
+		if (doingdirectory)
+			panic("rename: lost dir entry");
+		vrele(ap->a_fvp);
+		xp = NULL;
+	} else {
+		vrele(fvp);
+		xp = NULL;
+
+		/*
+		 * First write a new entry in the destination
+		 * directory and mark the entry in the source directory
+		 * as deleted.  Then move the denode to the correct hash
+		 * chain for its new location in the filesystem.  And, if
+		 * we moved a directory, then update its .. entry to point
+		 * to the new parent directory.
+		 */
+		memcpy(oldname, ip->de_Name, 11);
+		memcpy(ip->de_Name, toname, 11);	/* update denode */
+		dp->de_crap.mlr_fndoffset = to_diroffset;
+		dp->de_crap.mlr_fndcnt = to_count;
+		error = createde(ip, dp, &dp->de_crap, (struct denode **)0,
+		    tcnp);
+		if (error) {
+			memcpy(ip->de_Name, oldname, 11);
+			VOP_UNLOCK(fvp);
+			goto bad;
+		}
+		ip->de_refcnt++;
+		zp->de_crap.mlr_fndoffset = from_diroffset;
+		if ((error = removede(zp, ip, &zp->de_crap)) != 0) {
+			/* XXX should really panic here, fs is corrupt */
+			VOP_UNLOCK(fvp);
+			goto bad;
+		}
+		cache_purge(fvp);
+		if (!doingdirectory) {
+			struct denode_key old_key = ip->de_key;
+			struct denode_key new_key = ip->de_key;
+
+			error = pcbmap(dp, de_cluster(pmp, to_diroffset), 0,
+				       &new_key.dk_dirclust, 0);
+			if (error) {
+				/* XXX should really panic here, fs is corrupt */
+				VOP_UNLOCK(fvp);
+				goto bad;
+			}
+			new_key.dk_diroffset = to_diroffset;
+			if (new_key.dk_dirclust != MSDOSFSROOT)
+				new_key.dk_diroffset &= pmp->pm_crbomask;
+			vcache_rekey_enter(pmp->pm_mountp, fvp, &old_key,
+			    sizeof(old_key), &new_key, sizeof(new_key));
+			ip->de_key = new_key;
+			vcache_rekey_exit(pmp->pm_mountp, fvp, &old_key,
+			    sizeof(old_key), &ip->de_key, sizeof(ip->de_key));
+		}
+	}
+
+	/*
+	 * If we moved a directory to a new parent directory, then we must
+	 * fixup the ".." entry in the moved directory.
+	 */
+	if (doingdirectory && newparent) {
+		cn = ip->de_StartCluster;
+		if (cn == MSDOSFSROOT) {
+			/* this should never happen */
+			panic("msdosfs_rename: updating .. in root directory?");
+		} else
+			bn = cntobn(pmp, cn);
+		error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn),
+		    pmp->pm_bpcluster, B_MODIFY, &bp);
+		if (error) {
+			/* XXX should really panic here, fs is corrupt */
+			VOP_UNLOCK(fvp);
+			goto bad;
+		}
+		dotdotp = (struct direntry *)bp->b_data + 1;
+		putushort(dotdotp->deStartCluster, dp->de_StartCluster);
+		if (FAT32(pmp)) {
+			putushort(dotdotp->deHighClust,
+				dp->de_StartCluster >> 16);
+		} else {
+			putushort(dotdotp->deHighClust, 0);
+		}
+		if ((error = bwrite(bp)) != 0) {
+			/* XXX should really panic here, fs is corrupt */
+			VOP_UNLOCK(fvp);
+			goto bad;
+		}
+	}
+
+	VN_KNOTE(fvp, NOTE_RENAME);
+	VOP_UNLOCK(fvp);
+bad:
+	if (tvp)
+		vput(tvp);
+	vrele(tdvp);
+	ip->de_flag &= ~DE_RENAME;
+	vrele(fdvp);
+	vrele(fvp);
+	return (error);
+
+	/* XXX: uuuh */
+tdvpbad:
+	VOP_UNLOCK(tdvp);
+	goto bad;
+}
+
+/*
+ * Check to see if the directory described by target is in some
+ * subdirectory of source.  This prevents something like the following from
+ * succeeding and leaving a bunch or files and directories orphaned. mv
+ * /a/b/c /a/b/c/d/e/f Where c and f are directories.
+ *
+ * source - the inode for /a/b/c
+ * target - the inode for /a/b/c/d/e/f
+ *
+ * Returns 0 if target is NOT a subdirectory of source.
+ * Otherwise returns a non-zero error number.
+ * The target inode is always unlocked on return.
+ */
+int
+doscheckpath(struct denode *source, struct denode *target)
+{
+	u_long scn;
+	struct msdosfsmount *pmp;
+	struct direntry *ep;
+	struct denode *dep;
+	struct buf *bp = NULL;
+	int error = 0;
+
+	dep = target;
+	if ((target->de_Attributes & ATTR_DIRECTORY) == 0 ||
+	    (source->de_Attributes & ATTR_DIRECTORY) == 0) {
+		error = ENOTDIR;
+		goto out;
+	}
+	if (dep->de_StartCluster == source->de_StartCluster) {
+		error = EEXIST;
+		goto out;
+	}
+	if (dep->de_StartCluster == MSDOSFSROOT)
+		goto out;
+	pmp = dep->de_pmp;
+#ifdef	DIAGNOSTIC
+	if (pmp != source->de_pmp)
+		panic("doscheckpath: source and target on different filesystems");
+#endif
+	if (FAT32(pmp) && dep->de_StartCluster == pmp->pm_rootdirblk)
+		goto out;
+
+	for (;;) {
+		if ((dep->de_Attributes & ATTR_DIRECTORY) == 0) {
+			error = ENOTDIR;
+			break;
+		}
+		scn = dep->de_StartCluster;
+		error = bread(pmp->pm_devvp, de_bn2kb(pmp, cntobn(pmp, scn)),
+			      pmp->pm_bpcluster, 0, &bp);
+		if (error)
+			break;
+
+		ep = (struct direntry *) bp->b_data + 1;
+		if ((ep->deAttributes & ATTR_DIRECTORY) == 0 ||
+		    memcmp(ep->deName, "..         ", 11) != 0) {
+			error = ENOTDIR;
+			break;
+		}
+		scn = getushort(ep->deStartCluster);
+		if (FAT32(pmp))
+			scn |= getushort(ep->deHighClust) << 16;
+
+		if (scn == source->de_StartCluster) {
+			error = EINVAL;
+			break;
+		}
+		if (scn == MSDOSFSROOT)
+			break;
+		if (FAT32(pmp) && scn == pmp->pm_rootdirblk) {
+			/*
+			 * scn should be 0 in this case,
+			 * but we silently ignore the error.
+			 */
+			break;
+		}
+
+		vput(DETOV(dep));
+		brelse(bp, 0);
+		bp = NULL;
+#ifdef MAKEFS
+		/* NOTE: deget() clears dep on error */
+		if ((error = deget(pmp, scn, 0, &dep)) != 0)
+			break;
+#else
+		struct vnode *vp;
+
+		dep = NULL;
+		error = deget(pmp, scn, 0, &vp);
+		if (error)
+			break;
+		error = vn_lock(vp, LK_EXCLUSIVE);
+		if (error) {
+			vrele(vp);
+			break;
+		}
+		dep = VTODE(vp);
+#endif
+	}
+out:
+	if (bp)
+		brelse(bp, 0);
+	if (error == ENOTDIR)
+		printf("doscheckpath(): .. not a directory?\n");
+	if (dep != NULL)
+		vput(DETOV(dep));
+	return (error);
+}

Reply via email to