diff --git a/sys/fs/msdosfs/msdosfs_lookup.c b/sys/fs/msdosfs/msdosfs_lookup.c --- a/sys/fs/msdosfs/msdosfs_lookup.c +++ b/sys/fs/msdosfs/msdosfs_lookup.c @@ -684,6 +684,7 @@ return error; } ndep = bptoep(pmp, bp, ddep->de_fndoffset); + rootde_alloced(ddep); DE_EXTERNALIZE(ndep, dep); @@ -721,6 +722,7 @@ ndep--; ddep->de_fndoffset -= sizeof(struct direntry); } + rootde_alloced(ddep); if (!unix2winfn(un, unlen, (struct winentry *)ndep, cnt++, chksum, pmp)) break; @@ -1015,6 +1017,7 @@ */ offset -= sizeof(struct direntry); ep--->deName[0] = SLOT_DELETED; + rootde_freed(pdep); if ((pmp->pm_flags & MSDOSFSMNT_NOWIN95) || !(offset & pmp->pm_crbomask) || ep->deAttributes != ATTR_WIN95) diff --git a/sys/fs/msdosfs/msdosfs_vfsops.c b/sys/fs/msdosfs/msdosfs_vfsops.c --- a/sys/fs/msdosfs/msdosfs_vfsops.c +++ b/sys/fs/msdosfs/msdosfs_vfsops.c @@ -409,6 +409,67 @@ return (0); } +static int +rootdir_free(struct msdosfsmount* pmp) +{ + struct buf *bp; + struct direntry *dep; + u_long readsize; + int dirclu; + int diridx; + int dirmax; + int dirleft; + int ffree; + + dirclu = pmp->pm_firstcluster - pmp->pm_rootdirsize; + dirleft = pmp->pm_RootDirEnts; + readsize = MAXBCACHEBUF; + +#ifdef MSDOSFS_DEBUG + printf("rootdir_free: blkpersec=%lu fatblksize=%lu readsize=%lu firstclu=%lu dirclu=%lu rootdirsize=%lu\n", + pmp->pm_BlkPerSec, pmp->pm_fatblocksize, readsize, pmp->pm_firstcluster, dirclu, pmp->pm_rootdirsize); +#endif + ffree = pmp->pm_RootDirEnts; + while (dirleft > 0 && ffree > 0) { + if (readsize > dirleft * sizeof(struct direntry)) + readsize = roundup(dirleft * sizeof(struct direntry), DEV_BSIZE); +#ifdef MSDOSFS_DEBUG + printf("rootdir_free: dirclu=%lu readsize=%lu\n", dirclu, readsize); +#endif + if (bread(pmp->pm_devvp, dirclu, readsize, NOCRED, &bp) != 0) { + dirleft = 0; + ffree = -1; + printf("rootdir_free: read error\n"); + } + dirmax = readsize / sizeof(struct direntry); + for (diridx = 0; diridx < dirmax && dirleft > 0; diridx++, dirleft--) { + dep = (struct direntry*)bp->b_data + diridx; +#ifdef MSDOSFS_DEBUG + if (dep->deName[0] == SLOT_DELETED) + printf("rootdir_free: idx=%d \n", diridx); + else if (dep->deName[0] == SLOT_EMPTY) + printf("rootdir_free: idx=%d \n", diridx); + else if (dep->deAttributes == ATTR_WIN95) + printf("rootdir_free: idx=%d \n", diridx); + else if (dep->deAttributes & ATTR_VOLUME) + printf("rootdir_free: idx=%d label='%11.11s'\n", diridx, dep->deName); + else if (dep->deAttributes & ATTR_DIRECTORY) + printf("rootdir_free: idx=%d dir='%11.11s'\n", diridx, dep->deName); + else + printf("rootdir_free: idx=%d file='%11.11s'\n", diridx, dep->deName); +#endif + if (dep->deName[0] == SLOT_EMPTY) + dirleft = 0; + else if (dep->deName[0] != SLOT_DELETED) + ffree--; + } + brelse(bp); + bp = NULL; + dirclu += readsize / DEV_BSIZE; + } + return (ffree); +} + static int mountmsdosfs(struct vnode *odevvp, struct mount *mp) { @@ -747,6 +808,15 @@ goto error_exit; pmp->pm_fmod = 1; } + + if (FAT32(pmp)) { + pmp->pm_rootdirfree = 0; + } else { + pmp->pm_rootdirfree = rootdir_free(pmp); + if (pmp->pm_rootdirfree < 0) + goto error_exit; + } + mp->mnt_data = pmp; mp->mnt_stat.f_fsid.val[0] = dev2udev(dev); mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; @@ -948,8 +1018,8 @@ sbp->f_blocks = pmp->pm_maxcluster + 1; sbp->f_bfree = pmp->pm_freeclustercount; sbp->f_bavail = pmp->pm_freeclustercount; - sbp->f_files = pmp->pm_RootDirEnts; /* XXX */ - sbp->f_ffree = 0; /* what to put in here? */ + sbp->f_files = pmp->pm_RootDirEnts; + sbp->f_ffree = pmp->pm_rootdirfree; return (0); } diff --git a/sys/fs/msdosfs/msdosfsmount.h b/sys/fs/msdosfs/msdosfsmount.h --- a/sys/fs/msdosfs/msdosfsmount.h +++ b/sys/fs/msdosfs/msdosfsmount.h @@ -114,6 +114,7 @@ void *pm_w2u; /* Unicode->Local iconv handle */ void *pm_u2d; /* Unicode->DOS iconv handle */ void *pm_d2u; /* DOS->Local iconv handle */ + u_short pm_rootdirfree; /* number of free slots in FAT12/16 root directory */ #ifndef MAKEFS struct lock pm_fatlock; /* lockmgr protecting allocations */ struct lock pm_checkpath_lock; /* protects doscheckpath result */ @@ -222,6 +223,22 @@ ? roottobn((pmp), (dirofs)) \ : cntobn((pmp), (dirclu))) +/* + * Decrement the number of used entries in a fixed size FAT12/16 root + * directory + */ +#define rootde_alloced(dep) \ + if ((dep)->de_StartCluster == MSDOSFSROOT) \ + (dep)->de_pmp->pm_rootdirfree--; + +/* + * Increment the number of used entries in a fixed size FAT12/16 root + * directory + */ +#define rootde_freed(dep) \ + if ((dep)->de_StartCluster == MSDOSFSROOT) \ + (dep)->de_pmp->pm_rootdirfree++; + #define MSDOSFS_LOCK_MP(pmp) \ lockmgr(&(pmp)->pm_fatlock, LK_EXCLUSIVE, NULL) #define MSDOSFS_UNLOCK_MP(pmp) \