Annotation of Net2/pcfs/pcfs_fat.c, revision 1.1

1.1     ! root        1: /*
        !             2:  *  Written by Paul Popelka ([email protected])
        !             3:  *
        !             4:  *  You can do anything you want with this software,
        !             5:  *    just don't say you wrote it,
        !             6:  *    and don't remove this notice.
        !             7:  *
        !             8:  *  This software is provided "as is".
        !             9:  *
        !            10:  *  The author supplies this software to be publicly
        !            11:  *  redistributed on the understanding that the author
        !            12:  *  is not responsible for the correct functioning of
        !            13:  *  this software in any circumstances and is not liable
        !            14:  *  for any damages caused by this software.
        !            15:  *
        !            16:  *  October 1992
        !            17:  *
        !            18:  *     pcfs_fat.c,v 1.3 1993/05/20 03:34:12 cgd Exp
        !            19:  */
        !            20: 
        !            21: /*
        !            22:  *  kernel include files.
        !            23:  */
        !            24: #include "param.h"
        !            25: #include "systm.h"
        !            26: #include "buf.h"
        !            27: #include "file.h"
        !            28: #include "namei.h"
        !            29: #include "mount.h"     /* to define statfs structure */
        !            30: #include "vnode.h"     /* to define vattr structure */
        !            31: #include "errno.h"
        !            32: 
        !            33: /*
        !            34:  *  pcfs include files.
        !            35:  */
        !            36: #include "bpb.h"
        !            37: #include "pcfsmount.h"
        !            38: #include "direntry.h"
        !            39: #include "denode.h"
        !            40: #include "fat.h"
        !            41: 
        !            42: /*
        !            43:  *  Fat cache stats.
        !            44:  */
        !            45: int fc_fileextends;            /* # of file extends                    */
        !            46: int fc_lfcempty;               /* # of time last file cluster cache entry
        !            47:                                 * was empty */
        !            48: int fc_bmapcalls;              /* # of times pcbmap was called         */
        !            49: #define        LMMAX   20
        !            50: int fc_lmdistance[LMMAX];      /* counters for how far off the last cluster
        !            51:                                 * mapped entry was. */
        !            52: int fc_largedistance;          /* off by more than LMMAX               */
        !            53: 
        !            54: /* Byte offset in FAT on filesystem pmp, cluster cn */
        !            55: #define        FATOFS(pmp, cn) (FAT12(pmp) ? (cn) * 3 / 2 : (cn) * 2)
        !            56: 
        !            57: 
        !            58: static void fatblock (pmp, ofs, bnp, sizep, bop)
        !            59:        struct pcfsmount *pmp;
        !            60:        u_long ofs;
        !            61:        u_long *bnp;
        !            62:        u_long *sizep;
        !            63:        u_long *bop;
        !            64: {
        !            65:        u_long bn, size;
        !            66: 
        !            67:        bn = ofs / pmp->pm_fatblocksize * pmp->pm_fatblocksec;
        !            68:        size = min (pmp->pm_fatblocksec, pmp->pm_FATsecs - bn)
        !            69:                * pmp->pm_BytesPerSec;
        !            70:        bn += pmp->pm_fatblk;
        !            71:        if (bnp)
        !            72:                *bnp = bn;
        !            73:        if (sizep)
        !            74:                *sizep = size;
        !            75:        if (bop)
        !            76:                *bop = ofs % pmp->pm_fatblocksize;
        !            77: }
        !            78: 
        !            79: /*
        !            80:  *  Map the logical cluster number of a file into
        !            81:  *  a physical disk sector that is filesystem relative.
        !            82:  *  dep - address of denode representing the file of interest
        !            83:  *  findcn - file relative cluster whose filesystem relative
        !            84:  *    cluster number and/or block number are/is to be found
        !            85:  *  bnp - address of where to place the file system relative
        !            86:  *    block number.  If this pointer is null then don't return
        !            87:  *    this quantity.
        !            88:  *  cnp - address of where to place the file system relative
        !            89:  *    cluster number.  If this pointer is null then don't return
        !            90:  *    this quantity.
        !            91:  *  NOTE:
        !            92:  *    Either bnp or cnp must be non-null.
        !            93:  *    This function has one side effect.  If the requested
        !            94:  *    file relative cluster is beyond the end of file, then
        !            95:  *    the actual number of clusters in the file is returned
        !            96:  *    in *cnp.  This is useful for determining how long a
        !            97:  *    directory is.  If cnp is null, nothing is returned.
        !            98:  */
        !            99: int
        !           100: pcbmap(dep, findcn, bnp, cnp)
        !           101:        struct denode *dep;
        !           102:        u_long findcn;          /* file relative cluster to get         */
        !           103:        daddr_t *bnp;           /* returned filesys relative blk number */
        !           104:        u_long *cnp;            /* returned cluster number              */
        !           105: {
        !           106:        int error;
        !           107:        u_long i;
        !           108:        u_long cn;
        !           109:        u_long prevcn;
        !           110:        u_long byteoffset;
        !           111:        u_long bn;
        !           112:        u_long bo;
        !           113:        struct buf *bp = NULL;
        !           114:        u_long bp_bn = -1;
        !           115:        struct pcfsmount *pmp = dep->de_pmp;
        !           116:        u_long bsize;
        !           117:        int fat12 = FAT12(pmp); /* 12 bit fat   */
        !           118: 
        !           119:        fc_bmapcalls++;
        !           120: 
        !           121: /*
        !           122:  *  If they don't give us someplace to return a value
        !           123:  *  then don't bother doing anything.
        !           124:  */
        !           125:        if (bnp == NULL  &&  cnp == NULL)
        !           126:                return 0;
        !           127: 
        !           128:        cn = dep->de_StartCluster;
        !           129: /*
        !           130:  *  The "file" that makes up the root directory is contiguous,
        !           131:  *  permanently allocated, of fixed size, and is not made up
        !           132:  *  of clusters.  If the cluster number is beyond the end of
        !           133:  *  the root directory, then return the number of clusters in
        !           134:  *  the file.
        !           135:  */
        !           136:        if (cn == PCFSROOT) {
        !           137:                if (dep->de_Attributes & ATTR_DIRECTORY) {
        !           138:                        if (findcn * pmp->pm_SectPerClust > pmp->pm_rootdirsize) {
        !           139:                                if (cnp)
        !           140:                                        *cnp = pmp->pm_rootdirsize / pmp->pm_SectPerClust;
        !           141:                                return E2BIG;
        !           142:                        }
        !           143:                        if (bnp)
        !           144:                                *bnp = pmp->pm_rootdirblk + (findcn * pmp->pm_SectPerClust);
        !           145:                        if (cnp)
        !           146:                                *cnp = PCFSROOT;
        !           147:                        return 0;
        !           148:                }
        !           149:                else {  /* just an empty file */
        !           150:                        if (cnp)
        !           151:                                *cnp = 0;
        !           152:                        return E2BIG;
        !           153:                }
        !           154:        }
        !           155: 
        !           156: /*
        !           157:  *  Rummage around in the fat cache, maybe we can avoid
        !           158:  *  tromping thru every fat entry for the file.
        !           159:  *  And, keep track of how far off the cache was from
        !           160:  *  where we wanted to be.
        !           161:  */
        !           162:        i = 0;
        !           163:        fc_lookup(dep, findcn, &i, &cn);
        !           164:        if ((bn = findcn - i) >= LMMAX)
        !           165:                fc_largedistance++;
        !           166:        else
        !           167:                fc_lmdistance[bn]++;
        !           168: 
        !           169: /*
        !           170:  *  Handle all other files or directories the normal way.
        !           171:  */
        !           172:        for (; i < findcn; i++) {
        !           173:                if (PCFSEOF(cn))
        !           174:                        goto hiteof;
        !           175:                byteoffset = FATOFS(pmp, cn);
        !           176:                fatblock(pmp, byteoffset, &bn, &bsize, &bo);
        !           177:                if (bn != bp_bn) {
        !           178:                        if (bp)
        !           179:                                brelse(bp);
        !           180:                        error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp);
        !           181:                        if (error) {
        !           182:                                brelse(bp);
        !           183:                                return error;
        !           184:                        }
        !           185:                        bp_bn = bn;
        !           186:                }
        !           187:                prevcn = cn;
        !           188:                cn = getushort(&bp->b_un.b_addr[bo]);
        !           189:                if (fat12) {
        !           190:                        if (prevcn & 1)
        !           191:                                cn >>= 4;
        !           192:                        cn &= 0x0fff;
        !           193: /*
        !           194:  *  Force the special cluster numbers in the range
        !           195:  *  0x0ff0-0x0fff to be the same as for 16 bit cluster
        !           196:  *  numbers to let the rest of pcfs think it is always
        !           197:  *  dealing with 16 bit fats.
        !           198:  */
        !           199:                        if ((cn & 0x0ff0) == 0x0ff0)
        !           200:                                cn |= 0xf000;
        !           201:                }
        !           202:        }
        !           203: 
        !           204:        if (!PCFSEOF(cn)) {
        !           205:                if (bp)
        !           206:                        brelse(bp);
        !           207:                if (bnp)
        !           208:                        *bnp = cntobn(pmp, cn);
        !           209:                if (cnp)
        !           210:                        *cnp = cn;
        !           211:                fc_setcache(dep, FC_LASTMAP, i, cn);
        !           212:                return 0;
        !           213:        }
        !           214: 
        !           215: hiteof:;
        !           216:        if (cnp)
        !           217:                *cnp = i;
        !           218:        if (bp)
        !           219:                brelse(bp);
        !           220:        /* update last file cluster entry in the fat cache */
        !           221:        fc_setcache(dep, FC_LASTFC, i-1, prevcn);
        !           222:        return E2BIG;
        !           223: }
        !           224: 
        !           225: /*
        !           226:  *  Find the closest entry in the fat cache to the
        !           227:  *  cluster we are looking for.
        !           228:  */
        !           229: fc_lookup(dep, findcn, frcnp, fsrcnp)
        !           230:        struct denode *dep;
        !           231:        u_long findcn;
        !           232:        u_long *frcnp;
        !           233:        u_long *fsrcnp;
        !           234: {
        !           235:        int i;
        !           236:        u_long cn;
        !           237:        struct fatcache *closest = 0;
        !           238: 
        !           239:        for (i = 0; i < FC_SIZE; i++) {
        !           240:                cn = dep->de_fc[i].fc_frcn;
        !           241:                if (cn != FCE_EMPTY  &&  cn <= findcn) {
        !           242:                        if (closest == 0  ||  cn > closest->fc_frcn)
        !           243:                                closest = &dep->de_fc[i];
        !           244:                }
        !           245:        }
        !           246:        if (closest) {
        !           247:                *frcnp  = closest->fc_frcn;
        !           248:                *fsrcnp = closest->fc_fsrcn;
        !           249:        }
        !           250: }
        !           251: 
        !           252: /*
        !           253:  *  Purge the fat cache in denode dep of all entries
        !           254:  *  relating to file relative cluster frcn and beyond.
        !           255:  */
        !           256: fc_purge(dep, frcn)
        !           257:        struct denode *dep;
        !           258:        u_int frcn;
        !           259: {
        !           260:        int i;
        !           261:        struct fatcache *fcp;
        !           262: 
        !           263:        fcp = dep->de_fc;
        !           264:        for (i = 0; i < FC_SIZE; i++, fcp++) {
        !           265:                if (fcp->fc_frcn != FCE_EMPTY  &&  fcp->fc_frcn >= frcn)
        !           266:                        fcp->fc_frcn = FCE_EMPTY;
        !           267:        }
        !           268: }
        !           269: 
        !           270: /*
        !           271:  *  Once the first fat is updated the other copies of
        !           272:  *  the fat must also be updated.  This function does
        !           273:  *  this.
        !           274:  *  pmp - pcfsmount structure for filesystem to update
        !           275:  *  bp - addr of modified fat block
        !           276:  *  fatbn - block number relative to begin of filesystem
        !           277:  *    of the modified fat block.
        !           278:  */
        !           279: void
        !           280: updateotherfats(pmp, bp, fatbn)
        !           281:        struct pcfsmount *pmp;
        !           282:        struct buf *bp;
        !           283:        u_long fatbn;
        !           284: {
        !           285:        int i;
        !           286:        struct buf *bpn;
        !           287: 
        !           288: #if defined(PCFSDEBUG)
        !           289: printf("updateotherfats(pmp %08x, bp %08x, fatbn %d)\n",
        !           290:        pmp, bp, fatbn);
        !           291: #endif /* defined(PCFSDEBUG) */
        !           292: 
        !           293: /*
        !           294:  *  Now copy the block(s) of the modified fat to the other
        !           295:  *  copies of the fat and write them out.  This is faster
        !           296:  *  than reading in the other fats and then writing them
        !           297:  *  back out.  This could tie up the fat for quite a while.
        !           298:  *  Preventing others from accessing it.  To prevent us
        !           299:  *  from going after the fat quite so much we use delayed
        !           300:  *  writes, unless they specfied "synchronous" when the
        !           301:  *  filesystem was mounted.  If synch is asked for then
        !           302:  *  use bwrite()'s and really slow things down.
        !           303:  */
        !           304:        for (i = 1; i < pmp->pm_FATs; i++) {
        !           305:                fatbn += pmp->pm_FATsecs;
        !           306:                /* getblk() never fails */
        !           307:                bpn = getblk(pmp->pm_devvp, fatbn, bp->b_bcount);
        !           308:                bcopy(bp->b_un.b_addr, bpn->b_un.b_addr,
        !           309:                        bp->b_bcount);
        !           310:                if (pmp->pm_waitonfat)
        !           311:                        bwrite(bpn);
        !           312:                else
        !           313:                        bdwrite(bpn);
        !           314:        }
        !           315: }
        !           316: 
        !           317: /*
        !           318:  *  Updating entries in 12 bit fats is a pain in the butt.
        !           319:  *
        !           320:  *  The following picture shows where nibbles go when
        !           321:  *  moving from a 12 bit cluster number into the appropriate
        !           322:  *  bytes in the FAT.
        !           323:  *
        !           324:  *      byte m        byte m+1      byte m+2
        !           325:  *    +----+----+   +----+----+   +----+----+
        !           326:  *    |  0    1 |   |  2    3 |   |  4    5 |   FAT bytes
        !           327:  *    +----+----+   +----+----+   +----+----+
        !           328:  *
        !           329:  *       +----+----+----+ +----+----+----+
        !           330:  *       |  3    0    1 | |  4    5    2 |
        !           331:  *       +----+----+----+ +----+----+----+
        !           332:  *         cluster n        cluster n+1
        !           333:  *
        !           334:  *    Where n is even.
        !           335:  *    m = n + (n >> 2)
        !           336:  *
        !           337:  *     (Function no longer used)
        !           338:  */
        !           339: 
        !           340: 
        !           341: extern inline void
        !           342: usemap_alloc (struct pcfsmount *pmp, u_long cn)
        !           343: {
        !           344:        pmp->pm_inusemap[cn / 8] |= 1 << (cn % 8);
        !           345:        pmp->pm_freeclustercount--;
        !           346:        /* This assumes that the lowest available cluster was allocated */
        !           347:        pmp->pm_lookhere = cn + 1;
        !           348: }
        !           349: 
        !           350: extern inline void
        !           351: usemap_free (struct pcfsmount *pmp, u_long cn)
        !           352: {
        !           353:        pmp->pm_freeclustercount++;
        !           354:        pmp->pm_inusemap[cn / 8] &= ~(1 << (cn % 8));
        !           355:        if (pmp->pm_lookhere > cn)
        !           356:                pmp->pm_lookhere = cn;
        !           357: }
        !           358: 
        !           359: int
        !           360: clusterfree(pmp, cluster, oldcnp)
        !           361:        struct pcfsmount *pmp;
        !           362:        u_long cluster;
        !           363:        u_long *oldcnp;
        !           364: {
        !           365:        int error;
        !           366:        u_long oldcn;
        !           367: 
        !           368:        error = fatentry(FAT_GET_AND_SET, pmp, cluster, &oldcn, PCFSFREE);
        !           369:        if (error == 0) {
        !           370: /*
        !           371:  *  If the cluster was successfully marked free, then update the count of
        !           372:  *  free clusters, and turn off the "allocated" bit in the
        !           373:  *  "in use" cluster bit map.
        !           374:  */
        !           375:                usemap_free(pmp, cluster);
        !           376:                if (oldcnp)
        !           377:                        *oldcnp = oldcn;
        !           378:        }
        !           379:        return error;
        !           380: }
        !           381: 
        !           382: /*
        !           383:  *  Get or Set or 'Get and Set' the cluster'th entry in the
        !           384:  *  fat.
        !           385:  *  function - whether to get or set a fat entry
        !           386:  *  pmp - address of the pcfsmount structure for the
        !           387:  *    filesystem whose fat is to be manipulated.
        !           388:  *  cluster - which cluster is of interest
        !           389:  *  oldcontents - address of a word that is to receive
        !           390:  *    the contents of the cluster'th entry if this is
        !           391:  *    a get function
        !           392:  *  newcontents - the new value to be written into the
        !           393:  *    cluster'th element of the fat if this is a set
        !           394:  *    function.
        !           395:  *
        !           396:  *  This function can also be used to free a cluster
        !           397:  *  by setting the fat entry for a cluster to 0.
        !           398:  *
        !           399:  *  All copies of the fat are updated if this is a set
        !           400:  *  function.
        !           401:  *  NOTE:
        !           402:  *    If fatentry() marks a cluster as free it does not
        !           403:  *    update the inusemap in the pcfsmount structure.
        !           404:  *    This is left to the caller.
        !           405:  */
        !           406: int
        !           407: fatentry(function, pmp, cn, oldcontents, newcontents)
        !           408:        int function;
        !           409:        struct pcfsmount *pmp;
        !           410:        u_long cn;
        !           411:        u_long *oldcontents;
        !           412:        u_long newcontents;
        !           413: {
        !           414:        int error;
        !           415:        u_long readcn;
        !           416:        u_long bn, bo, bsize, byteoffset;
        !           417:        struct buf *bp;
        !           418: /*printf("fatentry(func %d, pmp %08x, clust %d, oldcon %08x, newcon %d)\n",
        !           419:        function, pmp, cluster, oldcontents, newcontents);*/
        !           420: 
        !           421: #ifdef DIAGNOSTIC
        !           422: /*
        !           423:  *  Be sure they asked us to do something.
        !           424:  */
        !           425:        if ((function & (FAT_SET | FAT_GET)) == 0) {
        !           426:                printf("fatentry(): function code doesn't specify get or set\n");
        !           427:                return EINVAL;
        !           428:        }
        !           429: 
        !           430: /*
        !           431:  *  If they asked us to return a cluster number
        !           432:  *  but didn't tell us where to put it, give them
        !           433:  *  an error.
        !           434:  */
        !           435:        if ((function & FAT_GET)  &&  oldcontents == NULL) {
        !           436:                printf("fatentry(): get function with no place to put result\n");
        !           437:                return EINVAL;
        !           438:        }
        !           439: #endif
        !           440: 
        !           441: /*
        !           442:  *  Be sure the requested cluster is in the filesystem.
        !           443:  */
        !           444:        if (cn < CLUST_FIRST || cn > pmp->pm_maxcluster)
        !           445:                return EINVAL;
        !           446: 
        !           447:        byteoffset = FATOFS(pmp, cn);
        !           448:        fatblock(pmp, byteoffset, &bn, &bsize, &bo);
        !           449:        error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp);
        !           450:        if (error) {
        !           451:                brelse(bp);
        !           452:                return error;
        !           453:        }
        !           454:        if (function & FAT_GET) {
        !           455:                readcn = getushort(&bp->b_un.b_addr[bo]);
        !           456:                if (FAT12(pmp)) {
        !           457:                        if (cn & 1)
        !           458:                                readcn >>= 4;
        !           459:                        readcn &= 0x0fff;
        !           460:                        /* map certain 12 bit fat entries to 16 bit */
        !           461:                        if ((readcn & 0x0ff0) == 0x0ff0)
        !           462:                                readcn |= 0xf000;
        !           463:                }
        !           464:                *oldcontents = readcn;
        !           465:        }
        !           466:        if (function & FAT_SET) {
        !           467:                if (FAT12(pmp)) {
        !           468:                        readcn = getushort(&bp->b_un.b_addr[bo]);
        !           469:                        if (cn & 1) {
        !           470:                                readcn &= 0x000f;
        !           471:                                readcn |= (newcontents << 4);
        !           472:                        }
        !           473:                        else {
        !           474:                                readcn &= 0xf000;
        !           475:                                readcn |= (newcontents << 0);
        !           476:                        }
        !           477:                        putushort(&bp->b_un.b_addr[bo], readcn);
        !           478:                }
        !           479:                else
        !           480:                        putushort(&bp->b_un.b_addr[bo], newcontents);
        !           481:                updateotherfats(pmp, bp, bn);
        !           482: /*
        !           483:  *  Write out the first fat last.
        !           484:  */
        !           485:                if (pmp->pm_waitonfat)
        !           486:                        bwrite(bp);
        !           487:                else
        !           488:                        bdwrite(bp);
        !           489:                bp = NULL;
        !           490:                pmp->pm_fmod++;
        !           491:        }
        !           492:        if (bp)
        !           493:                brelse(bp);
        !           494:        return 0;
        !           495: }
        !           496: 
        !           497: /*
        !           498:  *  Allocate a free cluster.
        !           499:  *  pmp - 
        !           500:  *  retcluster - put the allocated cluster's number here.
        !           501:  *  fillwith - put this value into the fat entry for the
        !           502:  *     allocated cluster.
        !           503:  */
        !           504: int
        !           505: clusteralloc(pmp, retcluster, fillwith)
        !           506:        struct pcfsmount *pmp;
        !           507:        u_long *retcluster;
        !           508:        u_long fillwith;
        !           509: {
        !           510:        int error;
        !           511:        u_long cn;
        !           512:        u_long idx, max_idx, bit, map;
        !           513: 
        !           514:        max_idx = pmp->pm_maxcluster / 8;
        !           515:        for (idx = pmp->pm_lookhere / 8; idx <= max_idx; idx++) {
        !           516:                map = pmp->pm_inusemap[idx];
        !           517:                if (map != 0xff) {
        !           518:                        for (bit = 0; bit < 8; bit++) {
        !           519:                                if ((map & (1 << bit)) == 0) {
        !           520:                                        cn = idx * 8 + bit;
        !           521:                                        goto found_one;
        !           522:                                }
        !           523:                        }
        !           524:                }
        !           525:        }
        !           526:        return ENOSPC;
        !           527: 
        !           528: found_one:;
        !           529:        error = fatentry(FAT_SET, pmp, cn, 0, fillwith);
        !           530:        if (error == 0) {
        !           531:                usemap_alloc(pmp, cn);
        !           532:                *retcluster = cn;
        !           533:        }
        !           534: #if defined(PCFSDEBUG)
        !           535: printf("clusteralloc(): allocated cluster %d\n", cn);
        !           536: #endif /* defined(PCFSDEBUG) */
        !           537:        return error;
        !           538: }
        !           539: 
        !           540: /*
        !           541:  *  Free a chain of clusters.
        !           542:  *  pmp - address of the pcfs mount structure for the
        !           543:  *    filesystem containing the cluster chain to be freed.
        !           544:  *  startcluster - number of the 1st cluster in the chain
        !           545:  *    of clusters to be freed.
        !           546:  */
        !           547: int
        !           548: freeclusterchain(pmp, startcluster)
        !           549:        struct pcfsmount *pmp;
        !           550:        u_long startcluster;
        !           551: {
        !           552:        u_long nextcluster;
        !           553:        int error = 0;
        !           554: 
        !           555:        while (startcluster >= CLUST_FIRST  &&  startcluster <= pmp->pm_maxcluster) {
        !           556:                error = clusterfree(pmp, startcluster, &nextcluster);
        !           557:                if (error) {
        !           558:                        printf("freeclusterchain(): free failed, cluster %d\n",
        !           559:                                startcluster);
        !           560:                        break;
        !           561:                }
        !           562:                startcluster = nextcluster;
        !           563:        }
        !           564:        return error;
        !           565: }
        !           566: 
        !           567: /*
        !           568:  *  Read in fat blocks looking for free clusters.
        !           569:  *  For every free cluster found turn off its
        !           570:  *  corresponding bit in the pm_inusemap.
        !           571:  */
        !           572: int
        !           573: fillinusemap(pmp)
        !           574:        struct pcfsmount *pmp;
        !           575: {
        !           576:        struct buf *bp = NULL;
        !           577:        u_long cn, readcn;
        !           578:        int error;
        !           579:        int fat12 = FAT12(pmp);
        !           580:        u_long bn, bo, bsize, byteoffset;
        !           581: 
        !           582: /*
        !           583:  *  Mark all clusters in use, we mark the free ones in the
        !           584:  *  fat scan loop further down.
        !           585:  */
        !           586:        for (cn = 0; cn < (pmp->pm_maxcluster >> 3) + 1; cn++)
        !           587:                pmp->pm_inusemap[cn] = 0xff;
        !           588: 
        !           589: /*
        !           590:  *  Figure how many free clusters are in the filesystem
        !           591:  *  by ripping thougth the fat counting the number of
        !           592:  *  entries whose content is zero.  These represent free
        !           593:  *  clusters.
        !           594:  */
        !           595:        pmp->pm_freeclustercount = 0;
        !           596:        pmp->pm_lookhere = pmp->pm_maxcluster + 1;
        !           597:        for (cn = CLUST_FIRST; cn <= pmp->pm_maxcluster; cn++) {
        !           598:                byteoffset = FATOFS(pmp, cn);
        !           599:                bo = byteoffset % pmp->pm_fatblocksize;
        !           600:                if (!bo || !bp) {
        !           601:                        /* Read new FAT block */
        !           602:                        if (bp)
        !           603:                                brelse(bp);
        !           604:                        fatblock(pmp, byteoffset, &bn, &bsize, NULL);
        !           605:                        error = bread(pmp->pm_devvp, bn, bsize, NOCRED, &bp);
        !           606:                        if (error) {
        !           607:                                brelse(bp);
        !           608:                                return error;
        !           609:                        }
        !           610:                }
        !           611:                readcn = getushort(&bp->b_un.b_addr[bo]);
        !           612:                if (fat12) {
        !           613:                        if (cn & 1)
        !           614:                                readcn >>= 4;
        !           615:                        readcn &= 0x0fff;
        !           616:                }
        !           617:                
        !           618:                if (readcn == 0)
        !           619:                        usemap_free(pmp, cn);
        !           620:        }
        !           621:        brelse(bp);
        !           622:        return 0;
        !           623: }
        !           624: 
        !           625: /*
        !           626:  *  Allocate a new cluster and chain it onto the end of the
        !           627:  *  file.
        !           628:  *  dep - the file to extend
        !           629:  *  bpp - where to return the address of the buf header for the
        !           630:  *        new file block
        !           631:  *  ncp - where to put cluster number of the newly allocated file block
        !           632:  *        If this pointer is 0, do not return the cluster number.
        !           633:  *
        !           634:  *  NOTE:
        !           635:  *   This function is not responsible for turning on the DEUPD
        !           636:  *   bit if the de_flag field of the denode and it does not
        !           637:  *   change the de_FileSize field.  This is left for the caller
        !           638:  *   to do.
        !           639:  */
        !           640: int
        !           641: extendfile(dep, bpp, ncp)
        !           642:        struct denode *dep;
        !           643:        struct buf **bpp;
        !           644:        u_int *ncp;
        !           645: {
        !           646:        int error = 0;
        !           647:        u_long frcn;
        !           648:        u_long cn;
        !           649:        struct pcfsmount *pmp = dep->de_pmp;
        !           650: 
        !           651: /*
        !           652:  *  Don't try to extend the root directory
        !           653:  */
        !           654:        if (DETOV(dep)->v_flag & VROOT) {
        !           655:                printf("extendfile(): attempt to extend root directory\n");
        !           656:                return ENOSPC;
        !           657:        }
        !           658: 
        !           659: /*
        !           660:  *  If the "file's last cluster" cache entry is empty,
        !           661:  *  and the file is not empty,
        !           662:  *  then fill the cache entry by calling pcbmap().
        !           663:  */
        !           664:        fc_fileextends++;
        !           665:        if (dep->de_fc[FC_LASTFC].fc_frcn == FCE_EMPTY  &&
        !           666:            dep->de_StartCluster != 0) {
        !           667:                fc_lfcempty++;
        !           668:                error = pcbmap(dep, 0xffff, 0, &cn);
        !           669:                /* we expect it to return E2BIG */
        !           670:                if (error != E2BIG)
        !           671:                        return error;
        !           672:                error = 0;
        !           673:        }
        !           674: 
        !           675: /*
        !           676:  *  Allocate another cluster and chain onto the end of the file.
        !           677:  *  If the file is empty we make de_StartCluster point to the
        !           678:  *  new block.  Note that de_StartCluster being 0 is sufficient
        !           679:  *  to be sure the file is empty since we exclude attempts to
        !           680:  *  extend the root directory above, and the root dir is the
        !           681:  *  only file with a startcluster of 0 that has blocks allocated
        !           682:  *  (sort of).
        !           683:  */
        !           684:        if (error = clusteralloc(pmp, &cn, CLUST_EOFE))
        !           685:                return error;
        !           686:        if (dep->de_StartCluster == 0) {
        !           687:                dep->de_StartCluster = cn;
        !           688:                frcn = 0;
        !           689:        } else {
        !           690:                error = fatentry(FAT_SET, pmp, dep->de_fc[FC_LASTFC].fc_fsrcn,
        !           691:                        0, cn);
        !           692:                if (error) {
        !           693:                        clusterfree(pmp, cn, NULL);
        !           694:                        return error;
        !           695:                }
        !           696: 
        !           697:                frcn = dep->de_fc[FC_LASTFC].fc_frcn + 1;
        !           698:        }
        !           699: 
        !           700: /*
        !           701:  *  Update the "last cluster of the file" entry in the denode's
        !           702:  *  fat cache.
        !           703:  */
        !           704:        fc_setcache(dep, FC_LASTFC, frcn, cn);
        !           705: 
        !           706: /*
        !           707:  *  Get the buf header for the new block of the file.
        !           708:  */
        !           709:        if (dep->de_Attributes & ATTR_DIRECTORY)
        !           710:                *bpp = getblk(pmp->pm_devvp, cntobn(pmp, cn),
        !           711:                        pmp->pm_bpcluster);
        !           712:        else
        !           713:                *bpp = getblk(DETOV(dep), frcn, pmp->pm_bpcluster);
        !           714:        clrbuf(*bpp);
        !           715: 
        !           716:        if (dep->de_Attributes & ATTR_DIRECTORY)
        !           717:                /* If we extend a directory, me must record the new size */
        !           718:                dep->de_FileSize = (frcn + 1) * pmp->pm_bpcluster;
        !           719: 
        !           720: /*
        !           721:  *  Give them the filesystem relative cluster number
        !           722:  *  if they want it.
        !           723:  */
        !           724:        if (ncp)
        !           725:                *ncp = cn;
        !           726:        return 0;
        !           727: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.