The directory entry for dotdot was corrupted in the FAT32 case when moving

a directory to a subdir of the root directory from somewhere else.

For all directory moves that change the parent directory, the dotdot
entry must be fixed up.  For msdosfs, the root directory is magic for
non-FAT32.  It is less magic for FAT32, but needs the same magic for
the dotdot fixup.  It didn't have it.

Both chkdsk and fsck_msdosfs fix the corrupt directory entries with no
problems.

The fix is to use the same magic for dotdot in msdosfs_rename() as in
msdosfs_mkdir().

For msdosfs_mkdir(), document the magic. When writing the dotdot entry
in mkdir, use explicitly set pcl variable instead on relying on the
start cluster of the root directory typically has a value < 65536.

Submitted by:	bde
MFC after:	1 week
This commit is contained in:
Konstantin Belousov 2013-02-01 18:06:06 +00:00
parent 48efa33b49
commit 9ec062dddd
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=246217

View File

@ -973,7 +973,7 @@ msdosfs_rename(ap)
u_char to_count;
int doingdirectory = 0, newparent = 0;
int error;
u_long cn;
u_long cn, pcl;
daddr_t bn;
struct denode *fddep; /* from file's parent directory */
struct msdosfsmount *pmp;
@ -1246,9 +1246,12 @@ msdosfs_rename(ap)
goto bad;
}
dotdotp = (struct direntry *)bp->b_data + 1;
putushort(dotdotp->deStartCluster, dp->de_StartCluster);
pcl = dp->de_StartCluster;
if (FAT32(pmp) && pcl == pmp->pm_rootdirblk)
pcl = MSDOSFSROOT;
putushort(dotdotp->deStartCluster, pcl);
if (FAT32(pmp))
putushort(dotdotp->deHighClust, dp->de_StartCluster >> 16);
putushort(dotdotp->deHighClust, pcl >> 16);
if (DOINGASYNC(fvp))
bdwrite(bp);
else if ((error = bwrite(bp)) != 0) {
@ -1369,8 +1372,13 @@ msdosfs_mkdir(ap)
putushort(denp[0].deMDate, ndirent.de_MDate);
putushort(denp[0].deMTime, ndirent.de_MTime);
pcl = pdep->de_StartCluster;
/*
* Although the root directory has a non-magic starting cluster
* number for FAT32, chkdsk and fsck_msdosfs still require
* references to it in dotdot entries to be magic.
*/
if (FAT32(pmp) && pcl == pmp->pm_rootdirblk)
pcl = 0;
pcl = MSDOSFSROOT;
putushort(denp[1].deStartCluster, pcl);
putushort(denp[1].deCDate, ndirent.de_CDate);
putushort(denp[1].deCTime, ndirent.de_CTime);
@ -1380,7 +1388,7 @@ msdosfs_mkdir(ap)
putushort(denp[1].deMTime, ndirent.de_MTime);
if (FAT32(pmp)) {
putushort(denp[0].deHighClust, newcluster >> 16);
putushort(denp[1].deHighClust, pdep->de_StartCluster >> 16);
putushort(denp[1].deHighClust, pcl >> 16);
}
if (DOINGASYNC(ap->a_dvp))