Don't allow setattr on msdos directories (fixes pr kern/1436)

Correct handling of rmdir'ing open directories
Correct implementation of rename (includes renaming of directories)
Handle root directories that are not multiple clusters in size
This commit is contained in:
ws 1995-09-09 19:38:00 +00:00
parent 166530c153
commit 6820273c34
8 changed files with 244 additions and 238 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: denode.h,v 1.15 1995/06/02 15:33:22 mycroft Exp $ */
/* $NetBSD: denode.h,v 1.16 1995/09/09 19:38:00 ws Exp $ */
/*-
* Copyright (C) 1994 Wolfgang Solfrank.
@ -167,6 +167,7 @@ struct denode {
#define DE_WANTED 0x0002 /* Denode is wanted by a process. */
#define DE_UPDATE 0x0004 /* Modification time update request. */
#define DE_MODIFIED 0x0008 /* Denode has been modified. */
#define DE_RENAME 0x0010 /* Denode is in the process of being renamed */
/*
* Transfer directory entries between internal and external form.
@ -216,7 +217,7 @@ struct defid {
u_short defid_pad; /* force long alignment */
u_long defid_dirclust; /* cluster this dir entry came from */
u_long defid_dirofs; /* index of entry within the cluster */
u_long defid_dirofs; /* offset of entry within the cluster */
/* u_long defid_gen; /* generation number */
};

View File

@ -1,4 +1,4 @@
/* $NetBSD: fat.h,v 1.7 1995/07/24 06:37:47 leo Exp $ */
/* $NetBSD: fat.h,v 1.8 1995/09/09 19:38:01 ws Exp $ */
/*-
* Copyright (C) 1994 Wolfgang Solfrank.
@ -99,7 +99,7 @@
*/
#define DE_CLEAR 1 /* Zero out the blocks allocated */
int pcbmap __P((struct denode *, u_long, daddr_t *, u_long *));
int pcbmap __P((struct denode *, u_long, daddr_t *, u_long *, int *));
int clusterfree __P((struct msdosfsmount *, u_long, u_long *));
int clusteralloc __P((struct msdosfsmount *, u_long, u_long, u_long, u_long *, u_long *));
int extendfile __P((struct denode *, u_long, struct buf **, u_long *, int));

View File

@ -1,4 +1,4 @@
/* $NetBSD: msdosfs_denode.c,v 1.14 1995/06/02 16:19:55 mycroft Exp $ */
/* $NetBSD: msdosfs_denode.c,v 1.15 1995/09/09 19:38:03 ws Exp $ */
/*-
* Copyright (C) 1994 Wolfgang Solfrank.
@ -64,7 +64,8 @@
struct denode **dehashtbl;
u_long dehash; /* size of hash table - 1 */
#define DEHASH(dev, deno) (((dev) + (deno)) & dehash)
#define DEHASH(dev, dcl, doff) (((dev) + (dcl) + (doff) / sizeof(struct direntry)) \
& dehash)
int
msdosfs_init()
@ -82,7 +83,7 @@ msdosfs_hashget(dev, dirclust, diroff)
struct denode *dep;
for (;;)
for (dep = dehashtbl[DEHASH(dev, dirclust + diroff)];;
for (dep = dehashtbl[DEHASH(dev, dirclust, diroff)];;
dep = dep->de_next) {
if (dep == NULL)
return (NULL);
@ -109,7 +110,7 @@ msdosfs_hashins(dep)
{
struct denode **depp, *deq;
depp = &dehashtbl[DEHASH(dep->de_dev, dep->de_dirclust + dep->de_diroffset)];
depp = &dehashtbl[DEHASH(dep->de_dev, dep->de_dirclust, dep->de_diroffset)];
if (deq = *depp)
deq->de_prev = &dep->de_next;
dep->de_next = deq;
@ -280,7 +281,7 @@ deget(pmp, dirclust, diroffset, direntptr, depp)
if (ldep->de_StartCluster == MSDOSFSROOT)
nvp->v_flag |= VROOT;
else {
error = pcbmap(ldep, 0xffff, 0, &size);
error = pcbmap(ldep, 0xffff, 0, &size, 0);
if (error == E2BIG) {
ldep->de_FileSize = size << pmp->pm_cnshift;
error = 0;
@ -323,6 +324,9 @@ deupdat(dep, waitfor)
dep->de_flag &= ~DE_MODIFIED;
if (dep->de_Attributes & ATTR_DIRECTORY)
panic("deupdat: directory");
if (vp->v_mount->mnt_flag & MNT_RDONLY ||
dep->de_refcnt <= 0)
return (0);
@ -412,7 +416,7 @@ detrunc(dep, length, flags, cred, p)
dep->de_StartCluster = 0;
eofentry = ~0;
} else {
if (error = pcbmap(dep, de_clcount(pmp, length) - 1, 0, &eofentry)) {
if (error = pcbmap(dep, de_clcount(pmp, length) - 1, 0, &eofentry, 0)) {
#ifdef MSDOSFS_DEBUG
printf("detrunc(): pcbmap fails %d\n", error);
#endif
@ -459,7 +463,8 @@ detrunc(dep, length, flags, cred, p)
* we free the trailing clusters.
*/
dep->de_FileSize = length;
dep->de_flag |= DE_UPDATE|DE_MODIFIED;
if (!isadir)
dep->de_flag |= DE_UPDATE|DE_MODIFIED;
vflags = (length > 0 ? V_SAVE : 0) | V_SAVEMETA;
vinvalbuf(DETOV(dep), vflags, cred, p, 0, 0);
allerror = deupdat(dep, 1);
@ -651,11 +656,8 @@ msdosfs_inactive(ap)
printf("msdosfs_inactive(): dep %08x, refcnt %d, mntflag %x, MNT_RDONLY %x\n",
dep, dep->de_refcnt, vp->v_mount->mnt_flag, MNT_RDONLY);
#endif
if (dep->de_refcnt <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0) {
if (dep->de_refcnt <= 0 && (vp->v_mount->mnt_flag & MNT_RDONLY) == 0)
error = detrunc(dep, (u_long)0, 0, NOCRED, NULL);
dep->de_Name[0] = SLOT_DELETED;
dep->de_flag |= DE_MODIFIED;
}
deupdat(dep, 0);
VOP_UNLOCK(vp);
/*

View File

@ -1,4 +1,4 @@
/* $NetBSD: msdosfs_fat.c,v 1.18 1995/07/24 21:20:28 cgd Exp $ */
/* $NetBSD: msdosfs_fat.c,v 1.19 1995/09/09 19:38:04 ws Exp $ */
/*-
* Copyright (C) 1994 Wolfgang Solfrank.
@ -125,11 +125,12 @@ fatblock(pmp, ofs, bnp, sizep, bop)
* If cnp is null, nothing is returned.
*/
int
pcbmap(dep, findcn, bnp, cnp)
pcbmap(dep, findcn, bnp, cnp, sp)
struct denode *dep;
u_long findcn; /* file relative cluster to get */
daddr_t *bnp; /* returned filesys relative blk number */
u_long *cnp; /* returned cluster number */
int *sp; /* returned block size */
{
int error;
u_long i;
@ -150,7 +151,7 @@ pcbmap(dep, findcn, bnp, cnp)
* If they don't give us someplace to return a value then don't
* bother doing anything.
*/
if (bnp == NULL && cnp == NULL)
if (bnp == NULL && cnp == NULL && sp == NULL)
return (0);
cn = dep->de_StartCluster;
@ -168,9 +169,12 @@ pcbmap(dep, findcn, bnp, cnp)
return (E2BIG);
}
if (bnp)
*bnp = pmp->pm_rootdirblk + (findcn * pmp->pm_SectPerClust);
*bnp = pmp->pm_rootdirblk + findcn * pmp->pm_SectPerClust;
if (cnp)
*cnp = MSDOSFSROOT;
if (sp)
*sp = min(pmp->pm_bpcluster,
dep->de_FileSize - findcn * pmp->pm_bpcluster);
return (0);
} else { /* just an empty file */
if (cnp)
@ -179,6 +183,12 @@ pcbmap(dep, findcn, bnp, cnp)
}
}
/*
* All other files do I/O in cluster sized blocks
*/
if (sp)
*sp = pmp->pm_bpcluster;
/*
* Rummage around in the fat cache, maybe we can avoid tromping
* thru every fat entry for the file. And, keep track of how far
@ -690,7 +700,7 @@ clusteralloc(pmp, start, count, fillwith, retcluster, got)
* Start at a (pseudo) random place to maximize cluster runs
* under multiple writers.
*/
foundcn = newst = (start * 1103515245 + 12345) % (pmp->pm_maxcluster + 1);
newst = (start * 1103515245 + 12345) % (pmp->pm_maxcluster + 1);
foundl = 0;
for (cn = newst; cn <= pmp->pm_maxcluster;) {
@ -889,7 +899,7 @@ extendfile(dep, count, bpp, ncp, flags)
if (dep->de_fc[FC_LASTFC].fc_frcn == FCE_EMPTY &&
dep->de_StartCluster != 0) {
fc_lfcempty++;
error = pcbmap(dep, 0xffff, 0, &cn);
error = pcbmap(dep, 0xffff, 0, &cn, 0);
/* we expect it to return E2BIG */
if (error != E2BIG)
return (error);
@ -954,7 +964,7 @@ extendfile(dep, count, bpp, ncp, flags)
/*
* Do the bmap now, as in msdosfs_write
*/
if (pcbmap(dep, bp->b_lblkno, &bp->b_blkno, 0))
if (pcbmap(dep, bp->b_lblkno, &bp->b_blkno, 0, 0))
bp->b_blkno = -1;
if (bp->b_blkno == -1)
panic("extendfile: pcbmap");

View File

@ -1,4 +1,4 @@
/* $NetBSD: msdosfs_lookup.c,v 1.16 1994/12/27 21:53:31 mycroft Exp $ */
/* $NetBSD: msdosfs_lookup.c,v 1.17 1995/09/09 19:38:06 ws Exp $ */
/*-
* Copyright (C) 1994 Wolfgang Solfrank.
@ -99,6 +99,7 @@ msdosfs_lookup(ap)
u_long cluster;
int rootreloff;
int diroff;
int blsize;
int isadir; /* ~0 if found direntry is a directory */
u_long scn; /* starting cluster number */
struct vnode *pdp;
@ -240,16 +241,17 @@ msdosfs_lookup(ap)
*/
rootreloff = 0;
for (frcn = 0;; frcn++) {
if (error = pcbmap(dp, frcn, &bn, &cluster)) {
if (error = pcbmap(dp, frcn, &bn, &cluster, &blsize)) {
if (error == E2BIG)
break;
return (error);
}
if (error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, NOCRED, &bp))
if (error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp))
return (error);
for (diroff = 0; diroff < pmp->pm_depclust;
diroff++, rootreloff++) {
dep = (struct direntry *)bp->b_data + diroff;
for (diroff = 0; diroff < blsize;
diroff += sizeof(struct direntry),
rootreloff += sizeof(struct direntry)) {
dep = (struct direntry *)(bp->b_data + diroff);
/*
* If the slot is empty and we are still looking
* for an empty then remember this one. If the
@ -354,7 +356,7 @@ notfound:;
dp->de_fndoffset = slotoffset;
dp->de_fndclust = slotcluster;
}
/* dp->de_flag |= DE_UPDATE; /* never update dos directories */
/*
* We return with the directory locked, so that
* the parameters we set up above will still be
@ -663,7 +665,7 @@ int
dosdirempty(dep)
struct denode *dep;
{
int dei;
int blsize;
int error;
u_long cn;
daddr_t bn;
@ -677,14 +679,14 @@ dosdirempty(dep)
* we hit end of file.
*/
for (cn = 0;; cn++) {
error = pcbmap(dep, cn, &bn, 0);
error = pcbmap(dep, cn, &bn, 0, &blsize);
if (error == E2BIG)
return (1); /* it's empty */
if (error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, NOCRED,
&bp))
if (error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp))
return (error);
dentp = (struct direntry *)bp->b_data;
for (dei = 0; dei < pmp->pm_depclust; dei++, dentp++) {
for (dentp = (struct direntry *)bp->b_data;
(char *)dentp < bp->b_data + blsize;
dentp++) {
if (dentp->deName[0] != SLOT_DELETED &&
(dentp->deAttributes & ATTR_VOLUME) == 0) {
/*
@ -706,8 +708,8 @@ dosdirempty(dep)
bcmp(dentp->deName, ".. ", 11)) {
brelse(bp);
#ifdef MSDOSFS_DEBUG
printf("dosdirempty(): entry %d found %02x, %02x\n",
dei, dentp->deName[0], dentp->deName[1]);
printf("dosdirempty(): entry found %02x, %02x\n",
dentp->deName[0], dentp->deName[1]);
#endif
return (0); /* not empty */
}
@ -810,9 +812,16 @@ readep(pmp, dirclust, diroffset, bpp, epp)
{
int error;
daddr_t bn;
int blsize;
u_long boff;
boff = diroffset & ~pmp->pm_crbomask;
blsize = pmp->pm_bpcluster;
if (dirclust == MSDOSFSROOT
&& boff + blsize > (pmp->pm_rootdirsize << pmp->pm_bnshift))
blsize = (pmp->pm_rootdirsize << pmp->pm_bnshift) - boff;
bn = detobn(pmp, dirclust, diroffset);
if (error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, NOCRED, bpp)) {
if (error = bread(pmp->pm_devvp, bn, blsize, NOCRED, bpp)) {
*bpp = NULL;
return (error);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: msdosfs_vfsops.c,v 1.31 1995/07/24 06:38:22 leo Exp $ */
/* $NetBSD: msdosfs_vfsops.c,v 1.32 1995/09/09 19:38:08 ws Exp $ */
/*-
* Copyright (C) 1994 Wolfgang Solfrank.
@ -211,8 +211,6 @@ msdosfs_mountfs(devvp, mp, p)
int ronly, error;
#ifdef atari
int bsize, dtype, tmp;
#else /* !atari */
int size, bpc, bit, i;
#endif /* !atari */
/*
@ -252,16 +250,10 @@ msdosfs_mountfs(devvp, mp, p)
goto error_exit;
}
#else /* !atari */
if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0)
size = DEV_BSIZE;
else
size = dpart.disklab->d_secsize;
/*
* Read the boot sector of the filesystem, and then check the boot
* signature. If not a dos boot sector then error out. We could
* also add some checking on the bsOemName field. So far I've seen
* the following values: "IBM 3.3" "MSDOS3.3" "MSDOS5.0"
* signature. If not a dos boot sector then error out.
*/
bp = NULL;
pmp = NULL;
@ -398,19 +390,6 @@ msdosfs_mountfs(devvp, mp, p)
#endif /* !atari */
pmp->pm_fatblocksec = pmp->pm_fatblocksize / pmp->pm_BytesPerSec;
#ifdef atari
/*
* The following check will almost always fail for a gemdos fs.
* The root directory is kept as a number of logical sectors,
* not as a number of clusters. The driver assumes it can
* handle the root directory like any other directory. It
* might be a lot of work to fix this. Let's ignore it.
*/
#else /* !atari */
if ((pmp->pm_rootdirsize % pmp->pm_SectPerClust) != 0)
printf("mountmsdosfs(): root directory is not a multiple of the clustersize in length\n");
#endif /* !atari */
#ifdef atari
/*
* Be prepared for block size != 512
@ -426,7 +405,6 @@ msdosfs_mountfs(devvp, mp, p)
* > 0 and a power of 2.
*/
bsize = pmp->pm_SectPerClust * pmp->pm_BytesPerSec;
pmp->pm_depclust = bsize / sizeof(struct direntry);
pmp->pm_crbomask = bsize - 1;
pmp->pm_bpcluster = bsize;
for (tmp = 0; bsize >>= 1; ++tmp)
@ -438,26 +416,14 @@ msdosfs_mountfs(devvp, mp, p)
* Compute mask and shift value for isolating cluster relative byte
* offsets and cluster numbers from a file offset.
*/
bpc = pmp->pm_SectPerClust * pmp->pm_BytesPerSec;
pmp->pm_bpcluster = bpc;
pmp->pm_depclust = bpc / sizeof(struct direntry);
pmp->pm_crbomask = bpc - 1;
if (bpc == 0) {
pmp->pm_bpcluster = pmp->pm_SectPerClust * pmp->pm_BytesPerSec;
pmp->pm_crbomask = pmp->pm_bpcluster - 1;
pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1;
if (pmp->pm_cnshift < 0
|| pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) {
error = EINVAL;
goto error_exit;
}
bit = 1;
for (i = 0; i < 32; i++) {
if (bit & bpc) {
if (bit ^ bpc) {
error = EINVAL;
goto error_exit;
}
pmp->pm_cnshift = i;
break;
}
bit <<= 1;
}
pmp->pm_brbomask = 0x01ff; /* 512 byte blocks only (so far) */
pmp->pm_bnshift = 9; /* shift right 9 bits to get bn */

View File

@ -1,4 +1,4 @@
/* $NetBSD: msdosfs_vnops.c,v 1.36 1995/07/24 21:20:34 cgd Exp $ */
/* $NetBSD: msdosfs_vnops.c,v 1.37 1995/09/09 19:38:10 ws Exp $ */
/*-
* Copyright (C) 1994 Wolfgang Solfrank.
@ -260,7 +260,8 @@ msdosfs_getattr(ap)
} else {
if ((cn = dep->de_dirclust) == MSDOSFSROOT)
cn = 1;
cn = (cn << 16) | (dep->de_diroffset & 0xffff);
cn = (cn << 16)
| ((dep->de_diroffset / sizeof(struct direntry)) & 0xffff);
}
vap->va_fileid = cn;
vap->va_mode = (S_IXUSR|S_IXGRP|S_IXOTH) | (S_IRUSR|S_IRGRP|S_IROTH) |
@ -325,9 +326,10 @@ msdosfs_setattr(ap)
#endif
return (EINVAL);
}
if (ap->a_vp->v_type == VDIR)
return EISDIR;
if (vap->va_size != VNOVAL) {
if (ap->a_vp->v_type == VDIR)
return (EISDIR);
if (error = detrunc(dep, (u_long)vap->va_size, 0, cred, ap->a_p))
return (error);
}
@ -338,8 +340,7 @@ msdosfs_setattr(ap)
(error = VOP_ACCESS(ap->a_vp, VWRITE, cred, ap->a_p))))
return (error);
unix2dostime(&vap->va_mtime, &dep->de_Date, &dep->de_Time);
if ((dep->de_Attributes & ATTR_DIRECTORY) == 0)
dep->de_Attributes |= ATTR_ARCHIVE;
dep->de_Attributes |= ATTR_ARCHIVE;
dep->de_flag |= DE_MODIFIED;
}
/*
@ -385,6 +386,7 @@ msdosfs_read(ap)
{
int error = 0;
int diff;
int blsize;
int isadir;
long n;
long on;
@ -412,22 +414,21 @@ msdosfs_read(ap)
diff = dep->de_FileSize - uio->uio_offset;
if (diff <= 0)
return (0);
if (diff < n)
n = diff;
/* convert cluster # to block # if a directory */
if (isadir) {
error = pcbmap(dep, lbn, &lbn, 0);
error = pcbmap(dep, lbn, &lbn, 0, &blsize);
if (error)
return (error);
}
if (diff < n)
n = diff;
/*
* If we are operating on a directory file then be sure to
* do i/o with the vnode for the filesystem instead of the
* vnode for the directory.
*/
if (isadir) {
error = bread(pmp->pm_devvp, lbn, pmp->pm_bpcluster,
NOCRED, &bp);
error = bread(pmp->pm_devvp, lbn, blsize, NOCRED, &bp);
} else {
rablock = lbn + 1;
if (vp->v_lastr + 1 == lbn &&
@ -464,7 +465,6 @@ msdosfs_write(ap)
} */ *ap;
{
int n;
int isadir;
int croffset;
int resid;
u_long osize;
@ -488,25 +488,12 @@ msdosfs_write(ap)
dep->de_diroffset, dep->de_dirclust, dep->de_StartCluster);
#endif
switch (vp->v_type) {
case VREG:
if (vp->v_type == VREG) {
if (ioflag & IO_APPEND)
uio->uio_offset = dep->de_FileSize;
isadir = 0;
thisvp = vp;
break;
case VDIR:
if ((ioflag & IO_SYNC) == 0)
panic("msdosfs_write(): non-sync directory update");
isadir = 1;
thisvp = pmp->pm_devvp;
break;
default:
} else
panic("msdosfs_write(): bad file type");
break;
}
if (uio->uio_offset < 0)
return (EINVAL);
@ -566,10 +553,7 @@ msdosfs_write(ap)
do {
bn = de_blk(pmp, uio->uio_offset);
if (isadir) {
if (error = pcbmap(dep, bn, &bn, 0))
break;
} else if (bn > lastcn) {
if (bn > lastcn) {
error = ENOSPC;
break;
}
@ -588,18 +572,16 @@ msdosfs_write(ap)
* Do the bmap now, since pcbmap needs buffers
* for the fat table. (see msdosfs_strategy)
*/
if (!isadir) {
if (bp->b_blkno == bp->b_lblkno) {
if (error = pcbmap(dep, bp->b_lblkno,
&bp->b_blkno, 0))
bp->b_blkno = -1;
}
if (bp->b_blkno == -1) {
brelse(bp);
if (!error)
error = EIO; /* XXX */
break;
}
if (bp->b_blkno == bp->b_lblkno) {
if (error = pcbmap(dep, bp->b_lblkno,
&bp->b_blkno, 0, 0))
bp->b_blkno = -1;
}
if (bp->b_blkno == -1) {
brelse(bp);
if (!error)
error = EIO; /* XXX */
break;
}
} else {
/*
@ -857,7 +839,8 @@ msdosfs_rename(ap)
register struct componentname *tcnp = ap->a_tcnp;
register struct componentname *fcnp = ap->a_fcnp;
register struct denode *ip, *xp, *dp;
u_char toname[11];
u_char toname[11], oldname[11];
u_long to_dirclust, to_diroffset;
int doingdirectory = 0, newparent = 0;
int error;
u_long cn;
@ -918,11 +901,13 @@ abortit:
* Avoid ".", "..", and aliases of "." for obvious reasons.
*/
if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
dp == ip || (fcnp->cn_flags & ISDOTDOT)) {
dp == ip || (fcnp->cn_flags & ISDOTDOT) ||
(ip->de_flag & DE_RENAME)) {
VOP_UNLOCK(fvp);
error = EINVAL;
goto abortit;
}
ip->de_flag |= DE_RENAME;
doingdirectory++;
}
@ -932,6 +917,11 @@ abortit:
*/
dp = VTODE(tdvp);
xp = tvp ? VTODE(tvp) : NULL;
/*
* Remember direntry place to use for destination
*/
to_dirclust = dp->de_fndclust;
to_diroffset = dp->de_fndoffset;
/*
* If ".." must be changed (ie the directory gets a new
@ -947,6 +937,7 @@ abortit:
VOP_UNLOCK(fvp);
if (VTODE(fdvp)->de_StartCluster != VTODE(tdvp)->de_StartCluster)
newparent = 1;
vrele(fdvp);
if (doingdirectory && newparent) {
if (error) /* write access check above */
goto bad;
@ -964,8 +955,6 @@ abortit:
}
if (xp != NULL) {
u_long to_dirclust, to_diroffset;
/*
* Target must be empty if a directory and have no links
* to it. Also, ensure source and target are compatible
@ -985,108 +974,155 @@ abortit:
error = EISDIR;
goto bad;
}
to_dirclust = xp->de_dirclust;
to_diroffset = xp->de_diroffset;
if (error = removede(dp, xp))
goto bad;
vput(tvp);
xp = NULL;
/*
* Remember where the slot was for createde().
*/
dp->de_fndclust = to_dirclust;
dp->de_fndoffset = to_diroffset;
}
/*
* If the source and destination are in the same directory then
* just read in the directory entry, change the name in the
* directory entry and write it back to disk.
* Since from wasn't locked at various places above,
* have to do a relookup here.
*/
VOP_LOCK(fvp);
if (newparent == 0) {
if (error = readep(dp->de_pmp,
ip->de_dirclust,
ip->de_diroffset,
&bp, &ep)) {
VOP_UNLOCK(fvp);
goto bad;
}
bcopy(toname, ep->deName, 11);
if (error = bwrite(bp)) {
VOP_UNLOCK(fvp);
goto bad;
}
bcopy(toname, ip->de_Name, 11); /* update denode */
fcnp->cn_flags &= ~MODMASK;
fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
if ((fcnp->cn_flags & SAVESTART) == 0)
panic("msdosfs_rename: lost from startdir");
if (!newparent)
VOP_UNLOCK(tdvp);
(void) relookup(fdvp, &fvp, fcnp);
if (fvp == NULL) {
/*
* From name has disappeared.
*/
if (doingdirectory)
panic("rename: lost dir entry");
vrele(ap->a_fvp);
if (newparent)
VOP_UNLOCK(tdvp);
vrele(tdvp);
return 0;
}
xp = VTODE(fvp);
/*
* 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);
VOP_UNLOCK(fvp);
if (newparent)
VOP_UNLOCK(fdvp);
xp = NULL;
} else {
struct denode *zp;
vrele(fvp);
xp = NULL;
/*
* If the source and destination are in different
* directories, then mark the entry in the source directory
* as deleted and write a new entry in the destination
* directory. 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.
* If the source and destination are in the same directory then
* just read in the directory entry, change the name in the
* directory entry and write it back to disk.
*/
bcopy(toname, ip->de_Name, 11); /* update denode */
if (error = createde(ip, dp, (struct denode **)0)) {
/* XXX should put back filename */
VOP_UNLOCK(fvp);
goto bad;
}
VOP_LOCK(fdvp);
zp = VTODE(fdvp);
if (error = readep(zp->de_pmp, zp->de_fndclust, zp->de_fndoffset,
&bp, &ep)) {
VOP_UNLOCK(fvp);
if (!newparent) {
if (error = readep(dp->de_pmp,
dp->de_fndclust,
dp->de_fndoffset,
&bp, &ep)) {
VOP_UNLOCK(fvp);
goto bad;
}
bcopy(toname, ep->deName, 11);
if (error = bwrite(bp)) {
VOP_UNLOCK(fvp);
goto bad;
}
bcopy(toname, ip->de_Name, 11); /* update denode */
} else {
struct denode *zp;
/*
* If the source and destination are in different
* directories, then 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.
*/
bcopy(ip->de_Name, oldname, 11);
bcopy(toname, ip->de_Name, 11); /* update denode */
dp->de_fndclust = to_dirclust;
dp->de_fndoffset = to_diroffset;
if (error = createde(ip, dp, (struct denode **)0)) {
bcopy(oldname, ip->de_Name, 11);
VOP_UNLOCK(fdvp);
VOP_UNLOCK(fvp);
goto bad;
}
zp = VTODE(fdvp);
if (error = readep(zp->de_pmp, zp->de_fndclust, zp->de_fndoffset,
&bp, &ep)) {
/* XXX should really panic here, fs is corrupt */
VOP_UNLOCK(fdvp);
VOP_UNLOCK(fvp);
goto bad;
}
ep->deName[0] = SLOT_DELETED;
if (error = bwrite(bp)) {
/* XXX should really panic here, fs is corrupt */
VOP_UNLOCK(fdvp);
VOP_UNLOCK(fvp);
goto bad;
}
if (!doingdirectory) {
ip->de_dirclust = to_dirclust;
ip->de_diroffset = to_diroffset;
}
reinsert(ip);
VOP_UNLOCK(fdvp);
goto bad;
}
ep->deName[0] = SLOT_DELETED;
if (error = bwrite(bp)) {
VOP_UNLOCK(fvp);
VOP_UNLOCK(fdvp);
goto bad;
/*
* 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?\n");
} else
bn = cntobn(pmp, cn);
if (error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, NOCRED,
&bp)) {
/* 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 (error = bwrite(bp)) {
/* XXX should really panic here, fs is corrupt */
VOP_UNLOCK(fvp);
goto bad;
}
}
ip->de_dirclust = dp->de_fndclust;
ip->de_diroffset = dp->de_fndoffset;
reinsert(ip);
VOP_UNLOCK(fdvp);
}
/*
* 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?\n");
} else
bn = cntobn(pmp, cn);
if (error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, NOCRED,
&bp)) {
/* 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 (error = bwrite(bp)) {
/* XXX should really panic here, fs is corrupt */
VOP_UNLOCK(fvp);
goto bad;
}
}
VOP_UNLOCK(fvp);
bad:
if (xp)
vput(tvp);
vput(tdvp);
out:
ip->de_flag &= ~DE_RENAME;
vrele(fdvp);
vrele(fvp);
return (error);
@ -1233,7 +1269,7 @@ msdosfs_rmdir(ap)
* non-empty.)
*/
error = 0;
if (!dosdirempty(ip)) {
if (!dosdirempty(ip) || ip->de_flag & DE_RENAME) {
error = ENOTEMPTY;
goto out;
}
@ -1302,6 +1338,7 @@ msdosfs_readdir(ap)
int error = 0;
int diff;
long n;
int blsize;
long on;
long lost;
long count;
@ -1364,7 +1401,7 @@ msdosfs_readdir(ap)
*/
bias = 2 * sizeof(struct direntry);
if (offset < bias) {
for (n = offset / sizeof(struct direntry);
for (n = (int)offset / sizeof(struct direntry);
n < 2; n++) {
dirbuf.d_fileno = 1;
dirbuf.d_type = DT_DIR;
@ -1386,7 +1423,7 @@ msdosfs_readdir(ap)
offset += sizeof(struct direntry);
if (cookies) {
*cookies++ = offset;
if (!--ncookies)
if (--ncookies <= 0)
goto out;
}
}
@ -1401,13 +1438,13 @@ msdosfs_readdir(ap)
if (diff <= 0)
break;
n = min(n, diff);
if (error = pcbmap(dep, lbn, &bn, &cn))
if (error = pcbmap(dep, lbn, &bn, &cn, &blsize))
break;
if (error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, NOCRED, &bp)) {
if (error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp)) {
brelse(bp);
return (error);
}
n = min(n, pmp->pm_bpcluster - bp->b_resid);
n = min(n, blsize - bp->b_resid);
/*
* Convert from dos directory entries to fs-independent
@ -1472,7 +1509,7 @@ msdosfs_readdir(ap)
offset += sizeof(struct direntry);
if (cookies) {
*cookies++ = offset;
if (--ncookies) {
if (--ncookies <= 0) {
brelse(bp);
goto out;
}
@ -1636,7 +1673,7 @@ msdosfs_bmap(ap)
*ap->a_runp = 0;
}
return (pcbmap(dep, ap->a_bn << (pmp->pm_cnshift - pmp->pm_bnshift),
ap->a_bnp, 0));
ap->a_bnp, 0, 0));
}
int
@ -1671,7 +1708,7 @@ msdosfs_strategy(ap)
* don't allow files with holes, so we shouldn't ever see this.
*/
if (bp->b_blkno == bp->b_lblkno) {
if (error = pcbmap(dep, bp->b_lblkno, &bp->b_blkno, 0))
if (error = pcbmap(dep, bp->b_lblkno, &bp->b_blkno, 0, 0))
bp->b_blkno = -1;
if (bp->b_blkno == -1)
clrbuf(bp);

View File

@ -1,4 +1,4 @@
/* $NetBSD: msdosfsmount.h,v 1.10 1995/07/24 06:38:52 leo Exp $ */
/* $NetBSD: msdosfsmount.h,v 1.11 1995/09/09 19:38:12 ws Exp $ */
/*-
* Copyright (C) 1994 Wolfgang Solfrank.
@ -70,7 +70,6 @@ struct msdosfsmount {
u_long pm_cnshift; /* shift file offset right this amount to get a cluster number */
u_long pm_crbomask; /* and a file offset with this mask to get cluster rel offset */
u_long pm_bpcluster; /* bytes per cluster */
u_long pm_depclust; /* directory entries per cluster */
u_long pm_fmod; /* ~0 if fs is modified, this can rollover to 0 */
u_long pm_fatblocksize; /* size of fat blocks in bytes */
u_long pm_fatblocksec; /* size of fat blocks in sectors */
@ -89,24 +88,6 @@ struct msdosfsmount {
/* Number of bits in one pm_inusemap item: */
#define N_INUSEBITS (8 * sizeof(u_int))
/*
* How to compute pm_cnshift and pm_crbomask.
*
* pm_crbomask = (pm_SectPerClust * pm_BytesPerSect) - 1
* if (bytesperclust == * 0)
* return EBADBLKSZ;
* bit = 1;
* for (i = 0; i < 32; i++) {
* if (bit & bytesperclust) {
* if (bit ^ bytesperclust)
* return EBADBLKSZ;
* pm_cnshift = * i;
* break;
* }
* bit <<= 1;
* }
*/
/*
* Shorthand for fields in the bpb contained in the msdosfsmount structure.
*/
@ -133,13 +114,13 @@ struct msdosfsmount {
* Map a filesystem relative block number back into a cluster number.
*/
#define bntocn(pmp, bn) \
((((bn) - pmp->pm_firstcluster)/ (pmp)->pm_SectPerClust) + CLUST_FIRST)
((((bn) - pmp->pm_firstcluster) / (pmp)->pm_SectPerClust) + CLUST_FIRST)
/*
* Calculate block number for directory entry in root dir, offset dirofs
*/
#define roottobn(pmp, dirofs) \
(((dirofs) / (pmp)->pm_depclust) * (pmp)->pm_SectPerClust \
(((dirofs) / (pmp)->pm_bpcluster) * (pmp)->pm_SectPerClust \
+ (pmp)->pm_rootdirblk)
/*
@ -155,8 +136,8 @@ struct msdosfsmount {
* Convert pointer to buffer -> pointer to direntry
*/
#define bptoep(pmp, bp, dirofs) \
((struct direntry *)((bp)->b_data) \
+ (dirofs) % (pmp)->pm_depclust)
((struct direntry *)(((bp)->b_data) \
+ ((dirofs) & (pmp)->pm_crbomask)))
/*