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:
parent
166530c153
commit
6820273c34
|
@ -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 */
|
||||
};
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
/*
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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)))
|
||||
|
||||
|
||||
/*
|
||||
|
|
Loading…
Reference in New Issue