[BACK]Return to msdosfs_fat.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / fs / msdosfs

Annotation of src/sys/fs/msdosfs/msdosfs_fat.c, Revision 1.16

1.16    ! hannken     1: /*     $NetBSD: msdosfs_fat.c,v 1.15 2007/10/08 18:04:04 ad Exp $      */
1.1       jdolecek    2:
                      3: /*-
                      4:  * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
                      5:  * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
                      6:  * All rights reserved.
                      7:  * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
                      8:  *
                      9:  * Redistribution and use in source and binary forms, with or without
                     10:  * modification, are permitted provided that the following conditions
                     11:  * are met:
                     12:  * 1. Redistributions of source code must retain the above copyright
                     13:  *    notice, this list of conditions and the following disclaimer.
                     14:  * 2. Redistributions in binary form must reproduce the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer in the
                     16:  *    documentation and/or other materials provided with the distribution.
                     17:  * 3. All advertising materials mentioning features or use of this software
                     18:  *    must display the following acknowledgement:
                     19:  *     This product includes software developed by TooLs GmbH.
                     20:  * 4. The name of TooLs GmbH may not be used to endorse or promote products
                     21:  *    derived from this software without specific prior written permission.
                     22:  *
                     23:  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
                     24:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     25:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     26:  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
                     27:  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
                     28:  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
                     29:  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
                     30:  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
                     31:  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
                     32:  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     33:  */
                     34: /*
                     35:  * Written by Paul Popelka (paulp@uts.amdahl.com)
                     36:  *
                     37:  * You can do anything you want with this software, just don't say you wrote
                     38:  * it, and don't remove this notice.
                     39:  *
                     40:  * This software is provided "as is".
                     41:  *
                     42:  * The author supplies this software to be publicly redistributed on the
                     43:  * understanding that the author is not responsible for the correct
                     44:  * functioning of this software in any circumstances and is not liable for
                     45:  * any damages caused by this software.
                     46:  *
                     47:  * October 1992
                     48:  */
                     49:
                     50: #include <sys/cdefs.h>
1.16    ! hannken    51: __KERNEL_RCSID(0, "$NetBSD: msdosfs_fat.c,v 1.15 2007/10/08 18:04:04 ad Exp $");
1.1       jdolecek   52:
                     53: /*
                     54:  * kernel include files.
                     55:  */
                     56: #include <sys/param.h>
                     57: #include <sys/systm.h>
                     58: #include <sys/buf.h>
                     59: #include <sys/file.h>
                     60: #include <sys/namei.h>
1.3       christos   61: #include <sys/mount.h>         /* to define statvfs structure */
1.1       jdolecek   62: #include <sys/vnode.h>         /* to define vattr structure */
                     63: #include <sys/errno.h>
                     64: #include <sys/dirent.h>
1.10      elad       65: #include <sys/kauth.h>
1.1       jdolecek   66:
                     67: /*
                     68:  * msdosfs include files.
                     69:  */
                     70: #include <fs/msdosfs/bpb.h>
                     71: #include <fs/msdosfs/msdosfsmount.h>
                     72: #include <fs/msdosfs/direntry.h>
                     73: #include <fs/msdosfs/denode.h>
                     74: #include <fs/msdosfs/fat.h>
                     75:
                     76: /*
                     77:  * Fat cache stats.
                     78:  */
                     79: int fc_fileextends;            /* # of file extends                     */
                     80: int fc_lfcempty;               /* # of time last file cluster cache entry
                     81:                                 * was empty */
                     82: int fc_bmapcalls;              /* # of times pcbmap was called          */
                     83:
                     84: #define        LMMAX   20
                     85: int fc_lmdistance[LMMAX];      /* counters for how far off the last
                     86:                                 * cluster mapped entry was. */
                     87: int fc_largedistance;          /* off by more than LMMAX                */
1.11      xtraeme    88: int fc_wherefrom, fc_whereto, fc_lastclust;
                     89: int pm_fatblocksize;
                     90:
                     91: #ifdef MSDOSFS_DEBUG
                     92: void print_fat_stats(void);
                     93:
                     94: void
                     95: print_fat_stats(void)
                     96: {
                     97:        int i;
                     98:
                     99:        printf("fc_fileextends=%d fc_lfcempty=%d fc_bmapcalls=%d "
                    100:            "fc_largedistance=%d [%d->%d=%d] fc_lastclust=%d pm_fatblocksize=%d\n",
                    101:            fc_fileextends, fc_lfcempty, fc_bmapcalls, fc_largedistance,
                    102:            fc_wherefrom, fc_whereto, fc_whereto-fc_wherefrom,
                    103:            fc_lastclust, pm_fatblocksize);
                    104:
                    105:        fc_fileextends = fc_lfcempty = fc_bmapcalls = 0;
                    106:        fc_wherefrom = fc_whereto = fc_lastclust = 0;
                    107:
                    108:        for (i = 0; i < LMMAX; i++) {
                    109:                printf("%d:%d ", i, fc_lmdistance[i]);
                    110:        fc_lmdistance[i] = 0;
                    111:        }
                    112:
                    113:        printf("\n");
                    114: }
                    115: #endif
1.1       jdolecek  116:
1.5       xtraeme   117: static void fatblock(struct msdosfsmount *, u_long, u_long *, u_long *,
                    118:                          u_long *);
                    119: void updatefats(struct msdosfsmount *, struct buf *, u_long);
1.7       perry     120: static inline void usemap_free(struct msdosfsmount *, u_long);
                    121: static inline void usemap_alloc(struct msdosfsmount *, u_long);
1.5       xtraeme   122: static int fatchain(struct msdosfsmount *, u_long, u_long, u_long);
                    123: int chainlength(struct msdosfsmount *, u_long, u_long);
                    124: int chainalloc(struct msdosfsmount *, u_long, u_long, u_long, u_long *,
                    125:                    u_long *);
1.1       jdolecek  126:
                    127: static void
                    128: fatblock(pmp, ofs, bnp, sizep, bop)
                    129:        struct msdosfsmount *pmp;
                    130:        u_long ofs;
                    131:        u_long *bnp;
                    132:        u_long *sizep;
                    133:        u_long *bop;
                    134: {
                    135:        u_long bn, size;
                    136:
                    137:        bn = ofs / pmp->pm_fatblocksize * pmp->pm_fatblocksec;
                    138:        size = min(pmp->pm_fatblocksec, pmp->pm_FATsecs - bn)
                    139:            * pmp->pm_BytesPerSec;
                    140:        bn += pmp->pm_fatblk + pmp->pm_curfat * pmp->pm_FATsecs;
                    141:
                    142:        if (bnp)
                    143:                *bnp = bn;
                    144:        if (sizep)
                    145:                *sizep = size;
                    146:        if (bop)
                    147:                *bop = ofs % pmp->pm_fatblocksize;
1.11      xtraeme   148:
                    149:        pm_fatblocksize =  pmp->pm_fatblocksize;
1.1       jdolecek  150: }
                    151:
                    152: /*
                    153:  * Map the logical cluster number of a file into a physical disk sector
                    154:  * that is filesystem relative.
                    155:  *
                    156:  * dep   - address of denode representing the file of interest
                    157:  * findcn - file relative cluster whose filesystem relative cluster number
                    158:  *         and/or block number are/is to be found
                    159:  * bnp   - address of where to place the file system relative block number.
                    160:  *         If this pointer is null then don't return this quantity.
                    161:  * cnp   - address of where to place the file system relative cluster number.
                    162:  *         If this pointer is null then don't return this quantity.
                    163:  *
                    164:  * NOTE: Either bnp or cnp must be non-null.
                    165:  * This function has one side effect.  If the requested file relative cluster
                    166:  * is beyond the end of file, then the actual number of clusters in the file
                    167:  * is returned in *cnp.  This is useful for determining how long a directory is.
                    168:  *  If cnp is null, nothing is returned.
                    169:  */
                    170: int
                    171: pcbmap(dep, findcn, bnp, cnp, sp)
                    172:        struct denode *dep;
                    173:        u_long findcn;          /* file relative cluster to get          */
1.12      scw       174:        daddr_t *bnp;           /* returned filesys rel sector number    */
1.1       jdolecek  175:        u_long *cnp;            /* returned cluster number               */
                    176:        int *sp;                /* returned block size                   */
                    177: {
                    178:        int error;
                    179:        u_long i;
                    180:        u_long cn;
                    181:        u_long prevcn = 0; /* XXX: prevcn could be used unititialized */
                    182:        u_long byteoffset;
                    183:        u_long bn;
                    184:        u_long bo;
                    185:        struct buf *bp = NULL;
                    186:        u_long bp_bn = -1;
                    187:        struct msdosfsmount *pmp = dep->de_pmp;
                    188:        u_long bsize;
                    189:
                    190:        fc_bmapcalls++;
                    191:
                    192:        /*
                    193:         * If they don't give us someplace to return a value then don't
                    194:         * bother doing anything.
                    195:         */
                    196:        if (bnp == NULL && cnp == NULL && sp == NULL)
                    197:                return (0);
                    198:
                    199:        cn = dep->de_StartCluster;
                    200:        /*
                    201:         * The "file" that makes up the root directory is contiguous,
                    202:         * permanently allocated, of fixed size, and is not made up of
                    203:         * clusters.  If the cluster number is beyond the end of the root
                    204:         * directory, then return the number of clusters in the file.
                    205:         */
                    206:        if (cn == MSDOSFSROOT) {
                    207:                if (dep->de_Attributes & ATTR_DIRECTORY) {
                    208:                        if (de_cn2off(pmp, findcn) >= dep->de_FileSize) {
                    209:                                if (cnp)
                    210:                                        *cnp = de_bn2cn(pmp, pmp->pm_rootdirsize);
                    211:                                return (E2BIG);
                    212:                        }
                    213:                        if (bnp)
                    214:                                *bnp = pmp->pm_rootdirblk + de_cn2bn(pmp, findcn);
                    215:                        if (cnp)
                    216:                                *cnp = MSDOSFSROOT;
                    217:                        if (sp)
                    218:                                *sp = min(pmp->pm_bpcluster,
                    219:                                    dep->de_FileSize - de_cn2off(pmp, findcn));
                    220:                        return (0);
                    221:                } else {                /* just an empty file */
                    222:                        if (cnp)
                    223:                                *cnp = 0;
                    224:                        return (E2BIG);
                    225:                }
                    226:        }
                    227:
                    228:        /*
                    229:         * All other files do I/O in cluster sized blocks
                    230:         */
                    231:        if (sp)
                    232:                *sp = pmp->pm_bpcluster;
                    233:
                    234:        /*
                    235:         * Rummage around in the fat cache, maybe we can avoid tromping
                    236:         * thru every fat entry for the file. And, keep track of how far
                    237:         * off the cache was from where we wanted to be.
                    238:         */
                    239:        i = 0;
                    240:        fc_lookup(dep, findcn, &i, &cn);
1.11      xtraeme   241:        if ((bn = findcn - i) >= LMMAX) {
1.1       jdolecek  242:                fc_largedistance++;
1.11      xtraeme   243:                fc_wherefrom = i;
                    244:                fc_whereto = findcn;
                    245:                fc_lastclust = dep->de_fc[FC_LASTFC].fc_frcn;
                    246:        } else
1.1       jdolecek  247:                fc_lmdistance[bn]++;
                    248:
                    249:        /*
                    250:         * Handle all other files or directories the normal way.
                    251:         */
                    252:        for (; i < findcn; i++) {
                    253:                /*
                    254:                 * Stop with all reserved clusters, not just with EOF.
                    255:                 */
                    256:                if (cn >= (CLUST_RSRVD & pmp->pm_fatmask))
                    257:                        goto hiteof;
                    258:                byteoffset = FATOFS(pmp, cn);
                    259:                fatblock(pmp, byteoffset, &bn, &bsize, &bo);
                    260:                if (bn != bp_bn) {
                    261:                        if (bp)
1.15      ad        262:                                brelse(bp, 0);
1.12      scw       263:                        error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), bsize,
1.16    ! hannken   264:                            NOCRED, 0, &bp);
1.1       jdolecek  265:                        if (error) {
1.15      ad        266:                                brelse(bp, 0);
1.1       jdolecek  267:                                return (error);
                    268:                        }
                    269:                        bp_bn = bn;
                    270:                }
                    271:                prevcn = cn;
1.2       briggs    272:                if (bo >= bsize) {
                    273:                        if (bp)
1.15      ad        274:                                brelse(bp, 0);
1.2       briggs    275:                        return (EIO);
                    276:                }
1.8       christos  277:                KASSERT(bp != NULL);
1.1       jdolecek  278:                if (FAT32(pmp))
1.13      christos  279:                        cn = getulong((char *)bp->b_data + bo);
1.1       jdolecek  280:                else
1.13      christos  281:                        cn = getushort((char *)bp->b_data + bo);
1.1       jdolecek  282:                if (FAT12(pmp) && (prevcn & 1))
                    283:                        cn >>= 4;
                    284:                cn &= pmp->pm_fatmask;
                    285:        }
                    286:
                    287:        if (!MSDOSFSEOF(cn, pmp->pm_fatmask)) {
                    288:                if (bp)
1.15      ad        289:                        brelse(bp, 0);
1.1       jdolecek  290:                if (bnp)
                    291:                        *bnp = cntobn(pmp, cn);
                    292:                if (cnp)
                    293:                        *cnp = cn;
                    294:                fc_setcache(dep, FC_LASTMAP, i, cn);
                    295:                return (0);
                    296:        }
                    297:
                    298: hiteof:;
                    299:        if (cnp)
                    300:                *cnp = i;
                    301:        if (bp)
1.15      ad        302:                brelse(bp, 0);
1.1       jdolecek  303:        /* update last file cluster entry in the fat cache */
                    304:        fc_setcache(dep, FC_LASTFC, i - 1, prevcn);
                    305:        return (E2BIG);
                    306: }
                    307:
                    308: /*
                    309:  * Find the closest entry in the fat cache to the cluster we are looking
                    310:  * for.
                    311:  */
                    312: void
                    313: fc_lookup(dep, findcn, frcnp, fsrcnp)
                    314:        struct denode *dep;
                    315:        u_long findcn;
                    316:        u_long *frcnp;
                    317:        u_long *fsrcnp;
                    318: {
                    319:        int i;
                    320:        u_long cn;
                    321:        struct fatcache *closest = 0;
                    322:
                    323:        for (i = 0; i < FC_SIZE; i++) {
                    324:                cn = dep->de_fc[i].fc_frcn;
                    325:                if (cn != FCE_EMPTY && cn <= findcn) {
                    326:                        if (closest == 0 || cn > closest->fc_frcn)
                    327:                                closest = &dep->de_fc[i];
                    328:                }
                    329:        }
                    330:        if (closest) {
                    331:                *frcnp = closest->fc_frcn;
                    332:                *fsrcnp = closest->fc_fsrcn;
                    333:        }
                    334: }
                    335:
                    336: /*
                    337:  * Purge the fat cache in denode dep of all entries relating to file
                    338:  * relative cluster frcn and beyond.
                    339:  */
                    340: void
                    341: fc_purge(dep, frcn)
                    342:        struct denode *dep;
                    343:        u_int frcn;
                    344: {
                    345:        int i;
                    346:        struct fatcache *fcp;
                    347:
                    348:        fcp = dep->de_fc;
                    349:        for (i = 0; i < FC_SIZE; i++, fcp++) {
                    350:                if (fcp->fc_frcn >= frcn)
                    351:                        fcp->fc_frcn = FCE_EMPTY;
                    352:        }
                    353: }
                    354:
                    355: /*
                    356:  * Update the fat.
                    357:  * If mirroring the fat, update all copies, with the first copy as last.
                    358:  * Else update only the current fat (ignoring the others).
                    359:  *
                    360:  * pmp  - msdosfsmount structure for filesystem to update
                    361:  * bp   - addr of modified fat block
                    362:  * fatbn - block number relative to begin of filesystem of the modified fat block.
                    363:  */
                    364: void
                    365: updatefats(pmp, bp, fatbn)
                    366:        struct msdosfsmount *pmp;
                    367:        struct buf *bp;
                    368:        u_long fatbn;
                    369: {
                    370:        int i;
                    371:        struct buf *bpn;
                    372:
                    373: #ifdef MSDOSFS_DEBUG
                    374:        printf("updatefats(pmp %p, bp %p, fatbn %lu)\n",
                    375:            pmp, bp, fatbn);
                    376: #endif
                    377:
                    378:        /*
                    379:         * If we have an FSInfo block, update it.
                    380:         */
                    381:        if (pmp->pm_fsinfo) {
                    382:                u_long cn = pmp->pm_nxtfree;
                    383:
                    384:                if (pmp->pm_freeclustercount
                    385:                    && (pmp->pm_inusemap[cn / N_INUSEBITS]
                    386:                        & (1 << (cn % N_INUSEBITS)))) {
                    387:                        /*
                    388:                         * The cluster indicated in FSInfo isn't free
                    389:                         * any longer.  Got get a new free one.
                    390:                         */
                    391:                        for (cn = 0; cn < pmp->pm_maxcluster; cn++)
                    392:                                if (pmp->pm_inusemap[cn / N_INUSEBITS] != (u_int)-1)
                    393:                                        break;
                    394:                        pmp->pm_nxtfree = cn
                    395:                                + ffs(pmp->pm_inusemap[cn / N_INUSEBITS]
                    396:                                      ^ (u_int)-1) - 1;
                    397:                }
1.12      scw       398:                /*
                    399:                 * XXX  If the fsinfo block is stored on media with
                    400:                 *      2KB or larger sectors, is the fsinfo structure
                    401:                 *      padded at the end or in the middle?
                    402:                 */
                    403:                if (bread(pmp->pm_devvp, de_bn2kb(pmp, pmp->pm_fsinfo),
1.16    ! hannken   404:                    pmp->pm_BytesPerSec, NOCRED, B_MODIFY, &bpn) != 0) {
1.1       jdolecek  405:                        /*
                    406:                         * Ignore the error, but turn off FSInfo update for the future.
                    407:                         */
                    408:                        pmp->pm_fsinfo = 0;
1.15      ad        409:                        brelse(bpn, 0);
1.1       jdolecek  410:                } else {
                    411:                        struct fsinfo *fp = (struct fsinfo *)bpn->b_data;
                    412:
                    413:                        putulong(fp->fsinfree, pmp->pm_freeclustercount);
                    414:                        putulong(fp->fsinxtfree, pmp->pm_nxtfree);
                    415:                        if (pmp->pm_flags & MSDOSFSMNT_WAITONFAT)
                    416:                                bwrite(bpn);
                    417:                        else
                    418:                                bdwrite(bpn);
                    419:                }
                    420:        }
                    421:
                    422:        if (pmp->pm_flags & MSDOSFS_FATMIRROR) {
                    423:                /*
                    424:                 * Now copy the block(s) of the modified fat to the other copies of
                    425:                 * the fat and write them out.  This is faster than reading in the
                    426:                 * other fats and then writing them back out.  This could tie up
                    427:                 * the fat for quite a while. Preventing others from accessing it.
                    428:                 * To prevent us from going after the fat quite so much we use
1.14      msaitoh   429:                 * delayed writes, unless they specified "synchronous" when the
1.1       jdolecek  430:                 * filesystem was mounted.  If synch is asked for then use
                    431:                 * bwrite()'s and really slow things down.
                    432:                 */
                    433:                for (i = 1; i < pmp->pm_FATs; i++) {
                    434:                        fatbn += pmp->pm_FATsecs;
                    435:                        /* getblk() never fails */
1.12      scw       436:                        bpn = getblk(pmp->pm_devvp, de_bn2kb(pmp, fatbn),
                    437:                            bp->b_bcount, 0, 0);
1.1       jdolecek  438:                        memcpy(bpn->b_data, bp->b_data, bp->b_bcount);
                    439:                        if (pmp->pm_flags & MSDOSFSMNT_WAITONFAT)
                    440:                                bwrite(bpn);
                    441:                        else
                    442:                                bdwrite(bpn);
                    443:                }
                    444:        }
                    445:
                    446:        /*
                    447:         * Write out the first (or current) fat last.
                    448:         */
                    449:        if (pmp->pm_flags & MSDOSFSMNT_WAITONFAT)
                    450:                bwrite(bp);
                    451:        else
                    452:                bdwrite(bp);
                    453:        /*
                    454:         * Maybe update fsinfo sector here?
                    455:         */
                    456: }
                    457:
                    458: /*
                    459:  * Updating entries in 12 bit fats is a pain in the butt.
                    460:  *
                    461:  * The following picture shows where nibbles go when moving from a 12 bit
                    462:  * cluster number into the appropriate bytes in the FAT.
                    463:  *
                    464:  *     byte m        byte m+1      byte m+2
                    465:  *     +----+----+   +----+----+   +----+----+
                    466:  *     |  0    1 |   |  2    3 |   |  4    5 |   FAT bytes
                    467:  *     +----+----+   +----+----+   +----+----+
                    468:  *
                    469:  *     +----+----+----+   +----+----+----+
                    470:  *     |  3    0    1 |   |  4    5    2 |
                    471:  *     +----+----+----+   +----+----+----+
                    472:  *     cluster n          cluster n+1
                    473:  *
                    474:  * Where n is even. m = n + (n >> 2)
                    475:  *
                    476:  */
1.7       perry     477: static inline void
1.1       jdolecek  478: usemap_alloc(pmp, cn)
                    479:        struct msdosfsmount *pmp;
                    480:        u_long cn;
                    481: {
                    482:
                    483:        pmp->pm_inusemap[cn / N_INUSEBITS] |= 1 << (cn % N_INUSEBITS);
                    484:        pmp->pm_freeclustercount--;
                    485: }
                    486:
1.7       perry     487: static inline void
1.1       jdolecek  488: usemap_free(pmp, cn)
                    489:        struct msdosfsmount *pmp;
                    490:        u_long cn;
                    491: {
                    492:
                    493:        pmp->pm_freeclustercount++;
                    494:        pmp->pm_inusemap[cn / N_INUSEBITS] &= ~(1 << (cn % N_INUSEBITS));
                    495: }
                    496:
                    497: int
                    498: clusterfree(pmp, cluster, oldcnp)
                    499:        struct msdosfsmount *pmp;
                    500:        u_long cluster;
                    501:        u_long *oldcnp;
                    502: {
                    503:        int error;
                    504:        u_long oldcn;
                    505:
                    506:        usemap_free(pmp, cluster);
                    507:        error = fatentry(FAT_GET_AND_SET, pmp, cluster, &oldcn, MSDOSFSFREE);
                    508:        if (error) {
                    509:                usemap_alloc(pmp, cluster);
                    510:                return (error);
                    511:        }
                    512:        /*
                    513:         * If the cluster was successfully marked free, then update
                    514:         * the count of free clusters, and turn off the "allocated"
                    515:         * bit in the "in use" cluster bit map.
                    516:         */
                    517:        if (oldcnp)
                    518:                *oldcnp = oldcn;
                    519:        return (0);
                    520: }
                    521:
                    522: /*
                    523:  * Get or Set or 'Get and Set' the cluster'th entry in the fat.
                    524:  *
                    525:  * function    - whether to get or set a fat entry
                    526:  * pmp         - address of the msdosfsmount structure for the filesystem
                    527:  *               whose fat is to be manipulated.
                    528:  * cn          - which cluster is of interest
                    529:  * oldcontents - address of a word that is to receive the contents of the
                    530:  *               cluster'th entry if this is a get function
                    531:  * newcontents - the new value to be written into the cluster'th element of
                    532:  *               the fat if this is a set function.
                    533:  *
                    534:  * This function can also be used to free a cluster by setting the fat entry
                    535:  * for a cluster to 0.
                    536:  *
                    537:  * All copies of the fat are updated if this is a set function. NOTE: If
                    538:  * fatentry() marks a cluster as free it does not update the inusemap in
                    539:  * the msdosfsmount structure. This is left to the caller.
                    540:  */
                    541: int
                    542: fatentry(function, pmp, cn, oldcontents, newcontents)
                    543:        int function;
                    544:        struct msdosfsmount *pmp;
                    545:        u_long cn;
                    546:        u_long *oldcontents;
                    547:        u_long newcontents;
                    548: {
                    549:        int error;
                    550:        u_long readcn;
                    551:        u_long bn, bo, bsize, byteoffset;
                    552:        struct buf *bp;
                    553:
                    554: #ifdef MSDOSFS_DEBUG
                    555:        printf("fatentry(func %d, pmp %p, clust %lu, oldcon %p, newcon %lx)\n",
                    556:             function, pmp, cn, oldcontents, newcontents);
                    557: #endif
                    558:
                    559: #ifdef DIAGNOSTIC
                    560:        /*
                    561:         * Be sure they asked us to do something.
                    562:         */
                    563:        if ((function & (FAT_SET | FAT_GET)) == 0) {
                    564:                printf("fatentry(): function code doesn't specify get or set\n");
                    565:                return (EINVAL);
                    566:        }
                    567:
                    568:        /*
                    569:         * If they asked us to return a cluster number but didn't tell us
                    570:         * where to put it, give them an error.
                    571:         */
                    572:        if ((function & FAT_GET) && oldcontents == NULL) {
                    573:                printf("fatentry(): get function with no place to put result\n");
                    574:                return (EINVAL);
                    575:        }
                    576: #endif
                    577:
                    578:        /*
                    579:         * Be sure the requested cluster is in the filesystem.
                    580:         */
                    581:        if (cn < CLUST_FIRST || cn > pmp->pm_maxcluster)
                    582:                return (EINVAL);
                    583:
                    584:        byteoffset = FATOFS(pmp, cn);
                    585:        fatblock(pmp, byteoffset, &bn, &bsize, &bo);
1.12      scw       586:        if ((error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), bsize, NOCRED,
1.16    ! hannken   587:            0, &bp)) != 0) {
1.15      ad        588:                brelse(bp, 0);
1.1       jdolecek  589:                return (error);
                    590:        }
                    591:
                    592:        if (function & FAT_GET) {
                    593:                if (FAT32(pmp))
1.13      christos  594:                        readcn = getulong((char *)bp->b_data + bo);
1.1       jdolecek  595:                else
1.13      christos  596:                        readcn = getushort((char *)bp->b_data + bo);
1.1       jdolecek  597:                if (FAT12(pmp) & (cn & 1))
                    598:                        readcn >>= 4;
                    599:                readcn &= pmp->pm_fatmask;
                    600:                *oldcontents = readcn;
                    601:        }
                    602:        if (function & FAT_SET) {
                    603:                switch (pmp->pm_fatmask) {
                    604:                case FAT12_MASK:
1.13      christos  605:                        readcn = getushort((char *)bp->b_data + bo);
1.1       jdolecek  606:                        if (cn & 1) {
                    607:                                readcn &= 0x000f;
                    608:                                readcn |= newcontents << 4;
                    609:                        } else {
                    610:                                readcn &= 0xf000;
                    611:                                readcn |= newcontents & 0xfff;
                    612:                        }
1.13      christos  613:                        putushort((char *)bp->b_data + bo, readcn);
1.1       jdolecek  614:                        break;
                    615:                case FAT16_MASK:
1.13      christos  616:                        putushort((char *)bp->b_data + bo, newcontents);
1.1       jdolecek  617:                        break;
                    618:                case FAT32_MASK:
                    619:                        /*
                    620:                         * According to spec we have to retain the
                    621:                         * high order bits of the fat entry.
                    622:                         */
1.13      christos  623:                        readcn = getulong((char *)bp->b_data + bo);
1.1       jdolecek  624:                        readcn &= ~FAT32_MASK;
                    625:                        readcn |= newcontents & FAT32_MASK;
1.13      christos  626:                        putulong((char *)bp->b_data + bo, readcn);
1.1       jdolecek  627:                        break;
                    628:                }
                    629:                updatefats(pmp, bp, bn);
                    630:                bp = NULL;
                    631:                pmp->pm_fmod = 1;
                    632:        }
                    633:        if (bp)
1.15      ad        634:                brelse(bp, 0);
1.1       jdolecek  635:        return (0);
                    636: }
                    637:
                    638: /*
                    639:  * Update a contiguous cluster chain
                    640:  *
                    641:  * pmp     - mount point
                    642:  * start    - first cluster of chain
                    643:  * count    - number of clusters in chain
                    644:  * fillwith - what to write into fat entry of last cluster
                    645:  */
                    646: static int
                    647: fatchain(pmp, start, count, fillwith)
                    648:        struct msdosfsmount *pmp;
                    649:        u_long start;
                    650:        u_long count;
                    651:        u_long fillwith;
                    652: {
                    653:        int error;
                    654:        u_long bn, bo, bsize, byteoffset, readcn, newc;
                    655:        struct buf *bp;
                    656:
                    657: #ifdef MSDOSFS_DEBUG
                    658:        printf("fatchain(pmp %p, start %lu, count %lu, fillwith %lx)\n",
                    659:            pmp, start, count, fillwith);
                    660: #endif
                    661:        /*
                    662:         * Be sure the clusters are in the filesystem.
                    663:         */
                    664:        if (start < CLUST_FIRST || start + count - 1 > pmp->pm_maxcluster)
                    665:                return (EINVAL);
                    666:
                    667:        while (count > 0) {
                    668:                byteoffset = FATOFS(pmp, start);
                    669:                fatblock(pmp, byteoffset, &bn, &bsize, &bo);
1.12      scw       670:                error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), bsize, NOCRED,
1.16    ! hannken   671:                    B_MODIFY, &bp);
1.1       jdolecek  672:                if (error) {
1.15      ad        673:                        brelse(bp, 0);
1.1       jdolecek  674:                        return (error);
                    675:                }
                    676:                while (count > 0) {
                    677:                        start++;
                    678:                        newc = --count > 0 ? start : fillwith;
                    679:                        switch (pmp->pm_fatmask) {
                    680:                        case FAT12_MASK:
1.13      christos  681:                                readcn = getushort((char *)bp->b_data + bo);
1.1       jdolecek  682:                                if (start & 1) {
                    683:                                        readcn &= 0xf000;
                    684:                                        readcn |= newc & 0xfff;
                    685:                                } else {
                    686:                                        readcn &= 0x000f;
                    687:                                        readcn |= newc << 4;
                    688:                                }
1.13      christos  689:                                putushort((char *)bp->b_data + bo, readcn);
1.1       jdolecek  690:                                bo++;
                    691:                                if (!(start & 1))
                    692:                                        bo++;
                    693:                                break;
                    694:                        case FAT16_MASK:
1.13      christos  695:                                putushort((char *)bp->b_data + bo, newc);
1.1       jdolecek  696:                                bo += 2;
                    697:                                break;
                    698:                        case FAT32_MASK:
1.13      christos  699:                                readcn = getulong((char *)bp->b_data + bo);
1.1       jdolecek  700:                                readcn &= ~pmp->pm_fatmask;
                    701:                                readcn |= newc & pmp->pm_fatmask;
1.13      christos  702:                                putulong((char *)bp->b_data + bo, readcn);
1.1       jdolecek  703:                                bo += 4;
                    704:                                break;
                    705:                        }
                    706:                        if (bo >= bsize)
                    707:                                break;
                    708:                }
                    709:                updatefats(pmp, bp, bn);
                    710:        }
                    711:        pmp->pm_fmod = 1;
                    712:        return (0);
                    713: }
                    714:
                    715: /*
                    716:  * Check the length of a free cluster chain starting at start.
                    717:  *
                    718:  * pmp  - mount point
                    719:  * start - start of chain
                    720:  * count - maximum interesting length
                    721:  */
                    722: int
                    723: chainlength(pmp, start, count)
                    724:        struct msdosfsmount *pmp;
                    725:        u_long start;
                    726:        u_long count;
                    727: {
                    728:        u_long idx, max_idx;
                    729:        u_int map;
                    730:        u_long len;
                    731:
                    732:        max_idx = pmp->pm_maxcluster / N_INUSEBITS;
                    733:        idx = start / N_INUSEBITS;
                    734:        start %= N_INUSEBITS;
                    735:        map = pmp->pm_inusemap[idx];
                    736:        map &= ~((1 << start) - 1);
                    737:        if (map) {
                    738:                len = ffs(map) - 1 - start;
                    739:                return (len > count ? count : len);
                    740:        }
                    741:        len = N_INUSEBITS - start;
                    742:        if (len >= count)
                    743:                return (count);
                    744:        while (++idx <= max_idx) {
                    745:                if (len >= count)
                    746:                        break;
                    747:                if ((map = pmp->pm_inusemap[idx]) != 0) {
                    748:                        len +=  ffs(map) - 1;
                    749:                        break;
                    750:                }
                    751:                len += N_INUSEBITS;
                    752:        }
                    753:        return (len > count ? count : len);
                    754: }
                    755:
                    756: /*
                    757:  * Allocate contigous free clusters.
                    758:  *
                    759:  * pmp       - mount point.
                    760:  * start      - start of cluster chain.
                    761:  * count      - number of clusters to allocate.
                    762:  * fillwith   - put this value into the fat entry for the
                    763:  *             last allocated cluster.
                    764:  * retcluster - put the first allocated cluster's number here.
                    765:  * got       - how many clusters were actually allocated.
                    766:  */
                    767: int
                    768: chainalloc(pmp, start, count, fillwith, retcluster, got)
                    769:        struct msdosfsmount *pmp;
                    770:        u_long start;
                    771:        u_long count;
                    772:        u_long fillwith;
                    773:        u_long *retcluster;
                    774:        u_long *got;
                    775: {
                    776:        int error;
                    777:        u_long cl, n;
                    778:
                    779:        for (cl = start, n = count; n-- > 0;)
                    780:                usemap_alloc(pmp, cl++);
                    781:        if ((error = fatchain(pmp, start, count, fillwith)) != 0)
                    782:                return (error);
                    783: #ifdef MSDOSFS_DEBUG
                    784:        printf("clusteralloc(): allocated cluster chain at %lu (%lu clusters)\n",
                    785:            start, count);
                    786: #endif
                    787:        if (retcluster)
                    788:                *retcluster = start;
                    789:        if (got)
                    790:                *got = count;
                    791:        return (0);
                    792: }
                    793:
                    794: /*
                    795:  * Allocate contiguous free clusters.
                    796:  *
                    797:  * pmp       - mount point.
                    798:  * start      - preferred start of cluster chain.
                    799:  * count      - number of clusters requested.
                    800:  * fillwith   - put this value into the fat entry for the
                    801:  *             last allocated cluster.
                    802:  * retcluster - put the first allocated cluster's number here.
                    803:  * got       - how many clusters were actually allocated.
                    804:  */
                    805: int
                    806: clusteralloc(pmp, start, count, retcluster, got)
                    807:        struct msdosfsmount *pmp;
                    808:        u_long start;
                    809:        u_long count;
                    810:        u_long *retcluster;
                    811:        u_long *got;
                    812: {
                    813:        u_long idx;
                    814:        u_long len, newst, foundl, cn, l;
                    815:        u_long foundcn = 0; /* XXX: foundcn could be used unititialized */
                    816:        u_long fillwith = CLUST_EOFE;
                    817:        u_int map;
                    818:
                    819: #ifdef MSDOSFS_DEBUG
                    820:        printf("clusteralloc(): find %lu clusters\n",count);
                    821: #endif
                    822:        if (start) {
                    823:                if ((len = chainlength(pmp, start, count)) >= count)
                    824:                        return (chainalloc(pmp, start, count, fillwith, retcluster, got));
                    825:        } else {
                    826:                /*
                    827:                 * This is a new file, initialize start
                    828:                 */
                    829:                struct timeval tv;
                    830:
                    831:                microtime(&tv);
                    832:                start = (tv.tv_usec >> 10) | tv.tv_usec;
                    833:                len = 0;
                    834:        }
                    835:
                    836:        /*
                    837:         * Start at a (pseudo) random place to maximize cluster runs
                    838:         * under multiple writers.
                    839:         */
                    840:        newst = (start * 1103515245 + 12345) % (pmp->pm_maxcluster + 1);
                    841:        foundl = 0;
                    842:
                    843:        for (cn = newst; cn <= pmp->pm_maxcluster;) {
                    844:                idx = cn / N_INUSEBITS;
                    845:                map = pmp->pm_inusemap[idx];
                    846:                map |= (1 << (cn % N_INUSEBITS)) - 1;
                    847:                if (map != (u_int)-1) {
                    848:                        cn = idx * N_INUSEBITS + ffs(map^(u_int)-1) - 1;
                    849:                        if ((l = chainlength(pmp, cn, count)) >= count)
                    850:                                return (chainalloc(pmp, cn, count, fillwith, retcluster, got));
                    851:                        if (l > foundl) {
                    852:                                foundcn = cn;
                    853:                                foundl = l;
                    854:                        }
                    855:                        cn += l + 1;
                    856:                        continue;
                    857:                }
                    858:                cn += N_INUSEBITS - cn % N_INUSEBITS;
                    859:        }
                    860:        for (cn = 0; cn < newst;) {
                    861:                idx = cn / N_INUSEBITS;
                    862:                map = pmp->pm_inusemap[idx];
                    863:                map |= (1 << (cn % N_INUSEBITS)) - 1;
                    864:                if (map != (u_int)-1) {
                    865:                        cn = idx * N_INUSEBITS + ffs(map^(u_int)-1) - 1;
                    866:                        if ((l = chainlength(pmp, cn, count)) >= count)
                    867:                                return (chainalloc(pmp, cn, count, fillwith, retcluster, got));
                    868:                        if (l > foundl) {
                    869:                                foundcn = cn;
                    870:                                foundl = l;
                    871:                        }
                    872:                        cn += l + 1;
                    873:                        continue;
                    874:                }
                    875:                cn += N_INUSEBITS - cn % N_INUSEBITS;
                    876:        }
                    877:
                    878:        if (!foundl)
                    879:                return (ENOSPC);
                    880:
                    881:        if (len)
                    882:                return (chainalloc(pmp, start, len, fillwith, retcluster, got));
                    883:        else
                    884:                return (chainalloc(pmp, foundcn, foundl, fillwith, retcluster, got));
                    885: }
                    886:
                    887:
                    888: /*
                    889:  * Free a chain of clusters.
                    890:  *
                    891:  * pmp         - address of the msdosfs mount structure for the filesystem
                    892:  *               containing the cluster chain to be freed.
                    893:  * startcluster - number of the 1st cluster in the chain of clusters to be
                    894:  *               freed.
                    895:  */
                    896: int
                    897: freeclusterchain(pmp, cluster)
                    898:        struct msdosfsmount *pmp;
                    899:        u_long cluster;
                    900: {
                    901:        int error;
                    902:        struct buf *bp = NULL;
                    903:        u_long bn, bo, bsize, byteoffset;
                    904:        u_long readcn, lbn = -1;
                    905:
                    906:        while (cluster >= CLUST_FIRST && cluster <= pmp->pm_maxcluster) {
                    907:                byteoffset = FATOFS(pmp, cluster);
                    908:                fatblock(pmp, byteoffset, &bn, &bsize, &bo);
                    909:                if (lbn != bn) {
                    910:                        if (bp)
                    911:                                updatefats(pmp, bp, lbn);
1.12      scw       912:                        error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), bsize,
1.16    ! hannken   913:                            NOCRED, B_MODIFY, &bp);
1.1       jdolecek  914:                        if (error) {
1.15      ad        915:                                brelse(bp, 0);
1.1       jdolecek  916:                                return (error);
                    917:                        }
                    918:                        lbn = bn;
                    919:                }
                    920:                usemap_free(pmp, cluster);
1.9       christos  921:                KASSERT(bp != NULL);
1.1       jdolecek  922:                switch (pmp->pm_fatmask) {
                    923:                case FAT12_MASK:
1.13      christos  924:                        readcn = getushort((char *)bp->b_data + bo);
1.1       jdolecek  925:                        if (cluster & 1) {
                    926:                                cluster = readcn >> 4;
                    927:                                readcn &= 0x000f;
                    928:                                readcn |= MSDOSFSFREE << 4;
                    929:                        } else {
                    930:                                cluster = readcn;
                    931:                                readcn &= 0xf000;
                    932:                                readcn |= MSDOSFSFREE & 0xfff;
                    933:                        }
1.13      christos  934:                        putushort((char *)bp->b_data + bo, readcn);
1.1       jdolecek  935:                        break;
                    936:                case FAT16_MASK:
1.13      christos  937:                        cluster = getushort((char *)bp->b_data + bo);
                    938:                        putushort((char *)bp->b_data + bo, MSDOSFSFREE);
1.1       jdolecek  939:                        break;
                    940:                case FAT32_MASK:
1.13      christos  941:                        cluster = getulong((char *)bp->b_data + bo);
                    942:                        putulong((char *)bp->b_data + bo,
1.1       jdolecek  943:                                 (MSDOSFSFREE & FAT32_MASK) | (cluster & ~FAT32_MASK));
                    944:                        break;
                    945:                }
                    946:                cluster &= pmp->pm_fatmask;
                    947:        }
                    948:        if (bp)
                    949:                updatefats(pmp, bp, bn);
                    950:        return (0);
                    951: }
                    952:
                    953: /*
                    954:  * Read in fat blocks looking for free clusters. For every free cluster
                    955:  * found turn off its corresponding bit in the pm_inusemap.
                    956:  */
                    957: int
                    958: fillinusemap(pmp)
                    959:        struct msdosfsmount *pmp;
                    960: {
                    961:        struct buf *bp = NULL;
                    962:        u_long cn, readcn;
                    963:        int error;
                    964:        u_long bn, bo, bsize, byteoffset;
                    965:
                    966:        /*
                    967:         * Mark all clusters in use, we mark the free ones in the fat scan
                    968:         * loop further down.
                    969:         */
                    970:        for (cn = 0; cn < (pmp->pm_maxcluster + N_INUSEBITS) / N_INUSEBITS; cn++)
                    971:                pmp->pm_inusemap[cn] = (u_int)-1;
                    972:
                    973:        /*
                    974:         * Figure how many free clusters are in the filesystem by ripping
                    975:         * through the fat counting the number of entries whose content is
                    976:         * zero.  These represent free clusters.
                    977:         */
                    978:        pmp->pm_freeclustercount = 0;
                    979:        for (cn = CLUST_FIRST; cn <= pmp->pm_maxcluster; cn++) {
                    980:                byteoffset = FATOFS(pmp, cn);
                    981:                bo = byteoffset % pmp->pm_fatblocksize;
                    982:                if (!bo || !bp) {
                    983:                        /* Read new FAT block */
                    984:                        if (bp)
1.15      ad        985:                                brelse(bp, 0);
1.1       jdolecek  986:                        fatblock(pmp, byteoffset, &bn, &bsize, NULL);
1.12      scw       987:                        error = bread(pmp->pm_devvp, de_bn2kb(pmp, bn), bsize,
1.16    ! hannken   988:                            NOCRED, 0, &bp);
1.1       jdolecek  989:                        if (error) {
1.15      ad        990:                                brelse(bp, 0);
1.1       jdolecek  991:                                return (error);
                    992:                        }
                    993:                }
                    994:                if (FAT32(pmp))
1.13      christos  995:                        readcn = getulong((char *)bp->b_data + bo);
1.1       jdolecek  996:                else
1.13      christos  997:                        readcn = getushort((char *)bp->b_data + bo);
1.1       jdolecek  998:                if (FAT12(pmp) && (cn & 1))
                    999:                        readcn >>= 4;
                   1000:                readcn &= pmp->pm_fatmask;
                   1001:
                   1002:                if (readcn == 0)
                   1003:                        usemap_free(pmp, cn);
                   1004:        }
1.15      ad       1005:        brelse(bp, 0);
1.1       jdolecek 1006:        return (0);
                   1007: }
                   1008:
                   1009: /*
                   1010:  * Allocate a new cluster and chain it onto the end of the file.
                   1011:  *
                   1012:  * dep  - the file to extend
                   1013:  * count - number of clusters to allocate
                   1014:  * bpp  - where to return the address of the buf header for the first new
                   1015:  *        file block
                   1016:  * ncp  - where to put cluster number of the first newly allocated cluster
                   1017:  *        If this pointer is 0, do not return the cluster number.
                   1018:  * flags - see fat.h
                   1019:  *
                   1020:  * NOTE: This function is not responsible for turning on the DE_UPDATE bit of
                   1021:  * the de_flag field of the denode and it does not change the de_FileSize
                   1022:  * field.  This is left for the caller to do.
                   1023:  */
                   1024:
                   1025: int
                   1026: extendfile(dep, count, bpp, ncp, flags)
                   1027:        struct denode *dep;
                   1028:        u_long count;
                   1029:        struct buf **bpp;
                   1030:        u_long *ncp;
                   1031:        int flags;
                   1032: {
                   1033:        int error;
                   1034:        u_long frcn = 0, cn, got;
                   1035:        struct msdosfsmount *pmp = dep->de_pmp;
                   1036:        struct buf *bp;
                   1037:
                   1038:        /*
                   1039:         * Don't try to extend the root directory
                   1040:         */
                   1041:        if (dep->de_StartCluster == MSDOSFSROOT
                   1042:            && (dep->de_Attributes & ATTR_DIRECTORY)) {
                   1043:                printf("extendfile(): attempt to extend root directory\n");
                   1044:                return (ENOSPC);
                   1045:        }
                   1046:
                   1047:        /*
                   1048:         * If the "file's last cluster" cache entry is empty, and the file
                   1049:         * is not empty, then fill the cache entry by calling pcbmap().
                   1050:         */
                   1051:        fc_fileextends++;
                   1052:        if (dep->de_fc[FC_LASTFC].fc_frcn == FCE_EMPTY &&
                   1053:            dep->de_StartCluster != 0) {
                   1054:                fc_lfcempty++;
                   1055:                error = pcbmap(dep, CLUST_END, 0, &cn, 0);
                   1056:                /* we expect it to return E2BIG */
                   1057:                if (error != E2BIG)
                   1058:                        return (error);
                   1059:        }
                   1060:
1.11      xtraeme  1061:        fc_last_to_nexttolast(dep);
                   1062:
1.1       jdolecek 1063:        while (count > 0) {
                   1064:
                   1065:                /*
                   1066:                 * Allocate a new cluster chain and cat onto the end of the
                   1067:                 * file.  If the file is empty we make de_StartCluster point
                   1068:                 * to the new block.  Note that de_StartCluster being 0 is
                   1069:                 * sufficient to be sure the file is empty since we exclude
                   1070:                 * attempts to extend the root directory above, and the root
                   1071:                 * dir is the only file with a startcluster of 0 that has
                   1072:                 * blocks allocated (sort of).
                   1073:                 */
                   1074:
                   1075:                if (dep->de_StartCluster == 0)
                   1076:                        cn = 0;
                   1077:                else
                   1078:                        cn = dep->de_fc[FC_LASTFC].fc_fsrcn + 1;
                   1079:                error = clusteralloc(pmp, cn, count, &cn, &got);
                   1080:                if (error)
                   1081:                        return (error);
                   1082:
                   1083:                count -= got;
                   1084:
                   1085:                /*
                   1086:                 * Give them the filesystem relative cluster number if they want
                   1087:                 * it.
                   1088:                 */
                   1089:                if (ncp) {
                   1090:                        *ncp = cn;
                   1091:                        ncp = NULL;
                   1092:                }
                   1093:
                   1094:                if (dep->de_StartCluster == 0) {
                   1095:                        dep->de_StartCluster = cn;
                   1096:                        frcn = 0;
                   1097:                } else {
                   1098:                        error = fatentry(FAT_SET, pmp,
                   1099:                                         dep->de_fc[FC_LASTFC].fc_fsrcn,
                   1100:                                         0, cn);
                   1101:                        if (error) {
                   1102:                                clusterfree(pmp, cn, NULL);
                   1103:                                return (error);
                   1104:                        }
                   1105:                        frcn = dep->de_fc[FC_LASTFC].fc_frcn + 1;
                   1106:                }
                   1107:
                   1108:                /*
                   1109:                 * Update the "last cluster of the file" entry in the
                   1110:                 * denode's fat cache.
                   1111:                 */
                   1112:
                   1113:                fc_setcache(dep, FC_LASTFC, frcn + got - 1, cn + got - 1);
                   1114:                if ((flags & DE_CLEAR) &&
                   1115:                    (dep->de_Attributes & ATTR_DIRECTORY)) {
                   1116:                        while (got-- > 0) {
1.12      scw      1117:                                bp = getblk(pmp->pm_devvp,
                   1118:                                    de_bn2kb(pmp, cntobn(pmp, cn++)),
                   1119:                                    pmp->pm_bpcluster, 0, 0);
1.1       jdolecek 1120:                                clrbuf(bp);
                   1121:                                if (bpp) {
                   1122:                                        *bpp = bp;
                   1123:                                                bpp = NULL;
                   1124:                                } else {
                   1125:                                        bdwrite(bp);
1.4       perry    1126:                                }
1.1       jdolecek 1127:                        }
                   1128:                }
                   1129:        }
                   1130:
                   1131:        return (0);
                   1132: }

CVSweb <webmaster@jp.NetBSD.org>