[BACK]Return to msdosfs_lookup.c CVS log [TXT][DIR] Up to [local] / sys / msdosfs

Annotation of sys/msdosfs/msdosfs_lookup.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: msdosfs_lookup.c,v 1.19 2007/06/02 02:04:21 deraadt Exp $     */
        !             2: /*     $NetBSD: msdosfs_lookup.c,v 1.34 1997/10/18 22:12:27 ws Exp $   */
        !             3:
        !             4: /*-
        !             5:  * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
        !             6:  * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
        !             7:  * All rights reserved.
        !             8:  * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
        !             9:  *
        !            10:  * Redistribution and use in source and binary forms, with or without
        !            11:  * modification, are permitted provided that the following conditions
        !            12:  * are met:
        !            13:  * 1. Redistributions of source code must retain the above copyright
        !            14:  *    notice, this list of conditions and the following disclaimer.
        !            15:  * 2. Redistributions in binary form must reproduce the above copyright
        !            16:  *    notice, this list of conditions and the following disclaimer in the
        !            17:  *    documentation and/or other materials provided with the distribution.
        !            18:  * 3. All advertising materials mentioning features or use of this software
        !            19:  *    must display the following acknowledgement:
        !            20:  *     This product includes software developed by TooLs GmbH.
        !            21:  * 4. The name of TooLs GmbH may not be used to endorse or promote products
        !            22:  *    derived from this software without specific prior written permission.
        !            23:  *
        !            24:  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
        !            25:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
        !            26:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            27:  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
        !            28:  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
        !            29:  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
        !            30:  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
        !            31:  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
        !            32:  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
        !            33:  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        !            34:  */
        !            35: /*
        !            36:  * Written by Paul Popelka (paulp@uts.amdahl.com)
        !            37:  *
        !            38:  * You can do anything you want with this software, just don't say you wrote
        !            39:  * it, and don't remove this notice.
        !            40:  *
        !            41:  * This software is provided "as is".
        !            42:  *
        !            43:  * The author supplies this software to be publicly redistributed on the
        !            44:  * understanding that the author is not responsible for the correct
        !            45:  * functioning of this software in any circumstances and is not liable for
        !            46:  * any damages caused by this software.
        !            47:  *
        !            48:  * October 1992
        !            49:  */
        !            50:
        !            51: #include <sys/param.h>
        !            52: #include <sys/systm.h>
        !            53: #include <sys/namei.h>
        !            54: #include <sys/buf.h>
        !            55: #include <sys/vnode.h>
        !            56: #include <sys/mount.h>
        !            57: #include <sys/dirent.h>
        !            58:
        !            59: #include <msdosfs/bpb.h>
        !            60: #include <msdosfs/direntry.h>
        !            61: #include <msdosfs/denode.h>
        !            62: #include <msdosfs/msdosfsmount.h>
        !            63: #include <msdosfs/fat.h>
        !            64:
        !            65: /*
        !            66:  * When we search a directory the blocks containing directory entries are
        !            67:  * read and examined.  The directory entries contain information that would
        !            68:  * normally be in the inode of a unix filesystem.  This means that some of
        !            69:  * a directory's contents may also be in memory resident denodes (sort of
        !            70:  * an inode).  This can cause problems if we are searching while some other
        !            71:  * process is modifying a directory.  To prevent one process from accessing
        !            72:  * incompletely modified directory information we depend upon being the
        !            73:  * sole owner of a directory block.  bread/brelse provide this service.
        !            74:  * This being the case, when a process modifies a directory it must first
        !            75:  * acquire the disk block that contains the directory entry to be modified.
        !            76:  * Then update the disk block and the denode, and then write the disk block
        !            77:  * out to disk.  This way disk blocks containing directory entries and in
        !            78:  * memory denode's will be in synch.
        !            79:  */
        !            80: int
        !            81: msdosfs_lookup(v)
        !            82:        void *v;
        !            83: {
        !            84:        struct vop_lookup_args *ap = v;
        !            85:        struct vnode *vdp = ap->a_dvp;
        !            86:        struct vnode **vpp = ap->a_vpp;
        !            87:        struct componentname *cnp = ap->a_cnp;
        !            88:        struct proc *p = cnp->cn_proc;
        !            89:        daddr64_t bn;
        !            90:        int error;
        !            91:        int lockparent;
        !            92:        int wantparent;
        !            93:        int slotcount;
        !            94:        int slotoffset = 0;
        !            95:        int frcn;
        !            96:        uint32_t cluster;
        !            97:        int blkoff;
        !            98:        int diroff;
        !            99:        int blsize;
        !           100:        int isadir;             /* ~0 if found direntry is a directory   */
        !           101:        uint32_t scn;           /* starting cluster number               */
        !           102:        struct vnode *pdp;
        !           103:        struct denode *dp;
        !           104:        struct denode *tdp;
        !           105:        struct msdosfsmount *pmp;
        !           106:        struct buf *bp = 0;
        !           107:        struct direntry *dep;
        !           108:        u_char dosfilename[12];
        !           109:        u_char *adjp;
        !           110:        int adjlen;
        !           111:        int flags;
        !           112:        int nameiop = cnp->cn_nameiop;
        !           113:        int wincnt = 1;
        !           114:        int chksum = -1, chksum_ok;
        !           115:        int olddos = 1;
        !           116:
        !           117:        cnp->cn_flags &= ~PDIRUNLOCK; /* XXX why this ?? */
        !           118:        flags = cnp->cn_flags;
        !           119:
        !           120: #ifdef MSDOSFS_DEBUG
        !           121:        printf("msdosfs_lookup(): looking for %s\n", cnp->cn_nameptr);
        !           122: #endif
        !           123:        dp = VTODE(vdp);
        !           124:        pmp = dp->de_pmp;
        !           125:        *vpp = NULL;
        !           126:        lockparent = flags & LOCKPARENT;
        !           127:        wantparent = flags & (LOCKPARENT | WANTPARENT);
        !           128: #ifdef MSDOSFS_DEBUG
        !           129:        printf("msdosfs_lookup(): vdp %08x, dp %08x, Attr %02x\n",
        !           130:            vdp, dp, dp->de_Attributes);
        !           131: #endif
        !           132:
        !           133:        /*
        !           134:         * Check accessiblity of directory.
        !           135:         */
        !           136:        if ((dp->de_Attributes & ATTR_DIRECTORY) == 0)
        !           137:                return (ENOTDIR);
        !           138:        if ((error = VOP_ACCESS(vdp, VEXEC, cnp->cn_cred, cnp->cn_proc)) != 0)
        !           139:                return (error);
        !           140:
        !           141:        /*
        !           142:         * We now have a segment name to search for, and a directory to search.
        !           143:         *
        !           144:         * Before tediously performing a linear scan of the directory,
        !           145:         * check the name cache to see if the directory/name pair
        !           146:         * we are looking for is known already.
        !           147:         */
        !           148:        if ((error = cache_lookup(vdp, vpp, cnp)) >= 0)
        !           149:                return (error);
        !           150:
        !           151:        /*
        !           152:         * If they are going after the . or .. entry in the root directory,
        !           153:         * they won't find it.  DOS filesystems don't have them in the root
        !           154:         * directory.  So, we fake it. deget() is in on this scam too.
        !           155:         */
        !           156:        if ((vdp->v_flag & VROOT) && cnp->cn_nameptr[0] == '.' &&
        !           157:            (cnp->cn_namelen == 1 ||
        !           158:                (cnp->cn_namelen == 2 && cnp->cn_nameptr[1] == '.'))) {
        !           159:                isadir = ATTR_DIRECTORY;
        !           160:                scn = MSDOSFSROOT;
        !           161: #ifdef MSDOSFS_DEBUG
        !           162:                printf("msdosfs_lookup(): looking for . or .. in root directory\n");
        !           163: #endif
        !           164:                cluster = MSDOSFSROOT;
        !           165:                blkoff = MSDOSFSROOT_OFS;
        !           166:                goto foundroot;
        !           167:        }
        !           168:
        !           169:        switch (unix2dosfn((u_char *)cnp->cn_nameptr, dosfilename, cnp->cn_namelen, 0)) {
        !           170:        case 0:
        !           171:                return (EINVAL);
        !           172:        case 1:
        !           173:                break;
        !           174:        case 2:
        !           175:                wincnt = winSlotCnt((u_char *)cnp->cn_nameptr, cnp->cn_namelen) + 1;
        !           176:                break;
        !           177:        case 3:
        !           178:                olddos = 0;
        !           179:                wincnt = winSlotCnt((u_char *)cnp->cn_nameptr, cnp->cn_namelen) + 1;
        !           180:                break;
        !           181:        }
        !           182:        if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
        !           183:                wincnt = 1;
        !           184:
        !           185:        /*
        !           186:         * Suppress search for slots unless creating
        !           187:         * file and at end of pathname, in which case
        !           188:         * we watch for a place to put the new file in
        !           189:         * case it doesn't already exist.
        !           190:         */
        !           191:        slotcount = wincnt;
        !           192:        if ((nameiop == CREATE || nameiop == RENAME) &&
        !           193:            (flags & ISLASTCN))
        !           194:                slotcount = 0;
        !           195:
        !           196: #ifdef MSDOSFS_DEBUG
        !           197:        printf("msdosfs_lookup(): dos version of filename %s, length %d\n",
        !           198:            dosfilename, cnp->cn_namelen);
        !           199: #endif
        !           200:        /*
        !           201:         * We want to search the directory pointed to by vdp for the name
        !           202:         * pointed to by cnp->cn_nameptr.
        !           203:         *
        !           204:         * XXX UNIX allows filenames with trailing dots and blanks; we don't.
        !           205:         *     Most of the routines in msdosfs_conv.c adjust for this, but
        !           206:         *     winChkName() does not, so we do it here.  Otherwise, a file
        !           207:         *     such as ".foobar." cannot be retrieved properly.
        !           208:         *
        !           209:         *     (Note that this is also faster: perform the adjustment once,
        !           210:         *     rather than on each call to winChkName.  However, it is still
        !           211:         *     a nasty hack.)
        !           212:         */
        !           213:        adjp = cnp->cn_nameptr;
        !           214:        adjlen = cnp->cn_namelen;
        !           215:
        !           216:        for (adjp += adjlen; adjlen > 0; adjlen--)
        !           217:                if (*--adjp != ' ' && *adjp != '.')
        !           218:                        break;
        !           219:
        !           220:        tdp = NULL;
        !           221:        /*
        !           222:         * The outer loop ranges over the clusters that make up the
        !           223:         * directory.  Note that the root directory is different from all
        !           224:         * other directories.  It has a fixed number of blocks that are not
        !           225:         * part of the pool of allocatable clusters.  So, we treat it a
        !           226:         * little differently. The root directory starts at "cluster" 0.
        !           227:         */
        !           228:        diroff = 0;
        !           229:        for (frcn = 0;; frcn++) {
        !           230:                if ((error = pcbmap(dp, frcn, &bn, &cluster, &blsize)) != 0) {
        !           231:                        if (error == E2BIG)
        !           232:                                break;
        !           233:                        return (error);
        !           234:                }
        !           235:                error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp);
        !           236:                if (error) {
        !           237:                        brelse(bp);
        !           238:                        return (error);
        !           239:                }
        !           240:                for (blkoff = 0; blkoff < blsize;
        !           241:                     blkoff += sizeof(struct direntry),
        !           242:                     diroff += sizeof(struct direntry)) {
        !           243:                        dep = (struct direntry *)(bp->b_data + blkoff);
        !           244:                        /*
        !           245:                         * If the slot is empty and we are still looking
        !           246:                         * for an empty then remember this one.  If the
        !           247:                         * slot is not empty then check to see if it
        !           248:                         * matches what we are looking for.  If the slot
        !           249:                         * has never been filled with anything, then the
        !           250:                         * remainder of the directory has never been used,
        !           251:                         * so there is no point in searching it.
        !           252:                         */
        !           253:                        if (dep->deName[0] == SLOT_EMPTY ||
        !           254:                            dep->deName[0] == SLOT_DELETED) {
        !           255:                                /*
        !           256:                                 * Drop memory of previous long matches
        !           257:                                 */
        !           258:                                chksum = -1;
        !           259:
        !           260:                                if (slotcount < wincnt) {
        !           261:                                        slotcount++;
        !           262:                                        slotoffset = diroff;
        !           263:                                }
        !           264:                                if (dep->deName[0] == SLOT_EMPTY) {
        !           265:                                        brelse(bp);
        !           266:                                        goto notfound;
        !           267:                                }
        !           268:                        } else {
        !           269:                                /*
        !           270:                                 * If there wasn't enough space for our winentries,
        !           271:                                 * forget about the empty space
        !           272:                                 */
        !           273:                                if (slotcount < wincnt)
        !           274:                                        slotcount = 0;
        !           275:
        !           276:                                /*
        !           277:                                 * Check for Win95 long filename entry
        !           278:                                 */
        !           279:                                if (dep->deAttributes == ATTR_WIN95) {
        !           280:                                        if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
        !           281:                                                continue;
        !           282:
        !           283:                                        chksum = winChkName((u_char *)cnp->cn_nameptr,
        !           284:                                                            adjlen,
        !           285:                                                            (struct winentry *)dep,
        !           286:                                                            chksum);
        !           287:                                        continue;
        !           288:                                }
        !           289:
        !           290:                                /*
        !           291:                                 * Ignore volume labels (anywhere, not just
        !           292:                                 * the root directory).
        !           293:                                 */
        !           294:                                if (dep->deAttributes & ATTR_VOLUME) {
        !           295:                                        chksum = -1;
        !           296:                                        continue;
        !           297:                                }
        !           298:
        !           299:                                /*
        !           300:                                 * Check for a checksum or name match
        !           301:                                 */
        !           302:                                chksum_ok = (chksum == winChksum(dep->deName));
        !           303:                                if (!chksum_ok
        !           304:                                    && (!olddos || bcmp(dosfilename, dep->deName, 11))) {
        !           305:                                        chksum = -1;
        !           306:                                        continue;
        !           307:                                }
        !           308: #ifdef MSDOSFS_DEBUG
        !           309:                                printf("msdosfs_lookup(): match blkoff %d, diroff %d\n",
        !           310:                                    blkoff, diroff);
        !           311: #endif
        !           312:                                /*
        !           313:                                 * Remember where this directory
        !           314:                                 * entry came from for whoever did
        !           315:                                 * this lookup.
        !           316:                                 */
        !           317:                                dp->de_fndoffset = diroff;
        !           318:                                if (chksum_ok && nameiop == RENAME) {
        !           319:                                        /*
        !           320:                                         * Target had correct long name
        !           321:                                         * directory entries, reuse them as
        !           322:                                         * needed.
        !           323:                                         */
        !           324:                                        dp->de_fndcnt = wincnt - 1;
        !           325:                                } else {
        !           326:                                        /*
        !           327:                                         * Long name directory entries not
        !           328:                                         * present or corrupt, can only reuse
        !           329:                                         * dos directory entry.
        !           330:                                         */
        !           331:                                        dp->de_fndcnt = 0;
        !           332:                                }
        !           333:                                goto found;
        !           334:                        }
        !           335:                }       /* for (blkoff = 0; .... */
        !           336:                /*
        !           337:                 * Release the buffer holding the directory cluster just
        !           338:                 * searched.
        !           339:                 */
        !           340:                brelse(bp);
        !           341:        }       /* for (frcn = 0; ; frcn++) */
        !           342:
        !           343: notfound:;
        !           344:        /*
        !           345:         * We hold no disk buffers at this point.
        !           346:         */
        !           347:
        !           348:        /*
        !           349:         * Fixup the slot description to point to the place where
        !           350:         * we might put the new DOS direntry (putting the Win95
        !           351:         * long name entries before that)
        !           352:         */
        !           353:        if (!slotcount) {
        !           354:                slotcount = 1;
        !           355:                slotoffset = diroff;
        !           356:        }
        !           357:        if (wincnt > slotcount)
        !           358:                slotoffset += sizeof(struct direntry) * (wincnt - slotcount);
        !           359:
        !           360:        /*
        !           361:         * If we get here we didn't find the entry we were looking for. But
        !           362:         * that's ok if we are creating or renaming and are at the end of
        !           363:         * the pathname and the directory hasn't been removed.
        !           364:         */
        !           365: #ifdef MSDOSFS_DEBUG
        !           366:        printf("msdosfs_lookup(): op %d, refcnt %d\n",
        !           367:            nameiop, dp->de_refcnt);
        !           368:        printf("               slotcount %d, slotoffset %d\n",
        !           369:            slotcount, slotoffset);
        !           370: #endif
        !           371:        if ((nameiop == CREATE || nameiop == RENAME) &&
        !           372:            (flags & ISLASTCN) && dp->de_refcnt != 0) {
        !           373:                /*
        !           374:                 * Access for write is interpreted as allowing
        !           375:                 * creation of files in the directory.
        !           376:                 */
        !           377:                error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred, cnp->cn_proc);
        !           378:                if (error)
        !           379:                        return (error);
        !           380:                /*
        !           381:                 * Return an indication of where the new directory
        !           382:                 * entry should be put.
        !           383:                 */
        !           384:                dp->de_fndoffset = slotoffset;
        !           385:                dp->de_fndcnt = wincnt - 1;
        !           386:
        !           387:                /*
        !           388:                 * We return with the directory locked, so that
        !           389:                 * the parameters we set up above will still be
        !           390:                 * valid if we actually decide to do a direnter().
        !           391:                 * We return ni_vp == NULL to indicate that the entry
        !           392:                 * does not currently exist; we leave a pointer to
        !           393:                 * the (locked) directory inode in ndp->ni_dvp.
        !           394:                 * The pathname buffer is saved so that the name
        !           395:                 * can be obtained later.
        !           396:                 *
        !           397:                 * NB - if the directory is unlocked, then this
        !           398:                 * information cannot be used.
        !           399:                 */
        !           400:                cnp->cn_flags |= SAVENAME;
        !           401:                if (!lockparent) {
        !           402:                        VOP_UNLOCK(vdp, 0, p);
        !           403:                        cnp->cn_flags |= PDIRUNLOCK;
        !           404:                }
        !           405:                return (EJUSTRETURN);
        !           406:        }
        !           407:        /*
        !           408:         * Insert name into cache (as non-existent) if appropriate.
        !           409:         */
        !           410:        if ((cnp->cn_flags & MAKEENTRY) && nameiop != CREATE)
        !           411:                cache_enter(vdp, *vpp, cnp);
        !           412:        return (ENOENT);
        !           413:
        !           414: found:;
        !           415:        /*
        !           416:         * NOTE:  We still have the buffer with matched directory entry at
        !           417:         * this point.
        !           418:         */
        !           419:        isadir = dep->deAttributes & ATTR_DIRECTORY;
        !           420:        scn = getushort(dep->deStartCluster);
        !           421:        if (FAT32(pmp)) {
        !           422:                scn |= getushort(dep->deHighClust) << 16;
        !           423:                if (scn == pmp->pm_rootdirblk) {
        !           424:                        /*
        !           425:                         * There should actually be 0 here.
        !           426:                         * Just ignore the error.
        !           427:                         */
        !           428:                        scn = MSDOSFSROOT;
        !           429:                }
        !           430:        }
        !           431:
        !           432:        if (cluster == MSDOSFSROOT)
        !           433:                blkoff = diroff;
        !           434:
        !           435:        if (isadir) {
        !           436:                cluster = scn;
        !           437:                if (cluster == MSDOSFSROOT)
        !           438:                        blkoff = MSDOSFSROOT_OFS;
        !           439:                else
        !           440:                        blkoff = 0;
        !           441:        }
        !           442:
        !           443:        /*
        !           444:         * Now release buf to allow deget to read the entry again.
        !           445:         * Reserving it here and giving it to deget could result
        !           446:         * in a deadlock.
        !           447:         */
        !           448:        brelse(bp);
        !           449:
        !           450: foundroot:;
        !           451:        /*
        !           452:         * If we entered at foundroot, then we are looking for the . or ..
        !           453:         * entry of the filesystems root directory.  isadir and scn were
        !           454:         * setup before jumping here.  And, bp is already null.
        !           455:         */
        !           456:        if (FAT32(pmp) && scn == MSDOSFSROOT)
        !           457:                scn = pmp->pm_rootdirblk;
        !           458:
        !           459:        /*
        !           460:         * If deleting, and at end of pathname, return
        !           461:         * parameters which can be used to remove file.
        !           462:         * If the wantparent flag isn't set, we return only
        !           463:         * the directory (in ndp->ni_dvp), otherwise we go
        !           464:         * on and lock the inode, being careful with ".".
        !           465:         */
        !           466:        if (nameiop == DELETE && (flags & ISLASTCN)) {
        !           467:                /*
        !           468:                 * Don't allow deleting the root.
        !           469:                 */
        !           470:                if (blkoff == MSDOSFSROOT_OFS)
        !           471:                        return EROFS;                           /* really? XXX */
        !           472:
        !           473:                /*
        !           474:                 * Write access to directory required to delete files.
        !           475:                 */
        !           476:                error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred, cnp->cn_proc);
        !           477:                if (error)
        !           478:                        return (error);
        !           479:
        !           480:                /*
        !           481:                 * Return pointer to current entry in dp->i_offset.
        !           482:                 * Save directory inode pointer in ndp->ni_dvp for dirremove().
        !           483:                 */
        !           484:                if (dp->de_StartCluster == scn && isadir) {     /* "." */
        !           485:                        VREF(vdp);
        !           486:                        *vpp = vdp;
        !           487:                        return (0);
        !           488:                }
        !           489:                if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0)
        !           490:                        return (error);
        !           491:                *vpp = DETOV(tdp);
        !           492:                if (!lockparent) {
        !           493:                        VOP_UNLOCK(vdp, 0, p);
        !           494:                        cnp->cn_flags |= PDIRUNLOCK;
        !           495:                }
        !           496:                return (0);
        !           497:        }
        !           498:
        !           499:        /*
        !           500:         * If rewriting (RENAME), return the inode and the
        !           501:         * information required to rewrite the present directory
        !           502:         * Must get inode of directory entry to verify it's a
        !           503:         * regular file, or empty directory.
        !           504:         */
        !           505:        if (nameiop == RENAME && wantparent &&
        !           506:            (flags & ISLASTCN)) {
        !           507:                if (blkoff == MSDOSFSROOT_OFS)
        !           508:                        return EROFS;                           /* really? XXX */
        !           509:
        !           510:                error = VOP_ACCESS(vdp, VWRITE, cnp->cn_cred, cnp->cn_proc);
        !           511:                if (error)
        !           512:                        return (error);
        !           513:
        !           514:                /*
        !           515:                 * Careful about locking second inode.
        !           516:                 * This can only occur if the target is ".".
        !           517:                 */
        !           518:                if (dp->de_StartCluster == scn && isadir)
        !           519:                        return (EISDIR);
        !           520:
        !           521:                if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0)
        !           522:                        return (error);
        !           523:                *vpp = DETOV(tdp);
        !           524:                cnp->cn_flags |= SAVENAME;
        !           525:                if (!lockparent)
        !           526:                        VOP_UNLOCK(vdp, 0, p);
        !           527:                return (0);
        !           528:        }
        !           529:
        !           530:        /*
        !           531:         * Step through the translation in the name.  We do not `vput' the
        !           532:         * directory because we may need it again if a symbolic link
        !           533:         * is relative to the current directory.  Instead we save it
        !           534:         * unlocked as "pdp".  We must get the target inode before unlocking
        !           535:         * the directory to insure that the inode will not be removed
        !           536:         * before we get it.  We prevent deadlock by always fetching
        !           537:         * inodes from the root, moving down the directory tree. Thus
        !           538:         * when following backward pointers ".." we must unlock the
        !           539:         * parent directory before getting the requested directory.
        !           540:         * There is a potential race condition here if both the current
        !           541:         * and parent directories are removed before the VFS_VGET for the
        !           542:         * inode associated with ".." returns.  We hope that this occurs
        !           543:         * infrequently since we cannot avoid this race condition without
        !           544:         * implementing a sophisticated deadlock detection algorithm.
        !           545:         * Note also that this simple deadlock detection scheme will not
        !           546:         * work if the file system has any hard links other than ".."
        !           547:         * that point backwards in the directory structure.
        !           548:         */
        !           549:        pdp = vdp;
        !           550:        if (flags & ISDOTDOT) {
        !           551:                VOP_UNLOCK(pdp, 0, p);  /* race to get the inode */
        !           552:                cnp->cn_flags |= PDIRUNLOCK;
        !           553:                if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0) {
        !           554:                        if (vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY, p) == 0)
        !           555:                                cnp->cn_flags &= ~PDIRUNLOCK;
        !           556:                        return (error);
        !           557:                }
        !           558:                if (lockparent && (flags & ISLASTCN)) {
        !           559:                        if ((error = vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY,
        !           560:                            p))) {
        !           561:                                vput(DETOV(tdp));
        !           562:                                return (error);
        !           563:                        }
        !           564:                        cnp->cn_flags &= ~PDIRUNLOCK;
        !           565:                }
        !           566:                *vpp = DETOV(tdp);
        !           567:        } else if (dp->de_StartCluster == scn && isadir) {
        !           568:                VREF(vdp);      /* we want ourself, ie "." */
        !           569:                *vpp = vdp;
        !           570:        } else {
        !           571:                if ((error = deget(pmp, cluster, blkoff, &tdp)) != 0)
        !           572:                        return (error);
        !           573:                if (!lockparent || !(flags & ISLASTCN)) {
        !           574:                        VOP_UNLOCK(pdp, 0, p);
        !           575:                        cnp->cn_flags |= PDIRUNLOCK;
        !           576:                }
        !           577:                *vpp = DETOV(tdp);
        !           578:        }
        !           579:
        !           580:        /*
        !           581:         * Insert name into cache if appropriate.
        !           582:         */
        !           583:        if (cnp->cn_flags & MAKEENTRY)
        !           584:                cache_enter(vdp, *vpp, cnp);
        !           585:        return (0);
        !           586: }
        !           587:
        !           588: /*
        !           589:  * dep  - directory entry to copy into the directory
        !           590:  * ddep - directory to add to
        !           591:  * depp - return the address of the denode for the created directory entry
        !           592:  *       if depp != 0
        !           593:  * cnp  - componentname needed for Win95 long filenames
        !           594:  */
        !           595: int
        !           596: createde(dep, ddep, depp, cnp)
        !           597:        struct denode *dep;
        !           598:        struct denode *ddep;
        !           599:        struct denode **depp;
        !           600:        struct componentname *cnp;
        !           601: {
        !           602:        int error;
        !           603:        uint32_t dirclust, diroffset;
        !           604:        struct direntry *ndep;
        !           605:        struct msdosfsmount *pmp = ddep->de_pmp;
        !           606:        struct buf *bp;
        !           607:        daddr64_t bn;
        !           608:        int blsize;
        !           609:
        !           610: #ifdef MSDOSFS_DEBUG
        !           611:        printf("createde(dep %08x, ddep %08x, depp %08x, cnp %08x)\n",
        !           612:            dep, ddep, depp, cnp);
        !           613: #endif
        !           614:
        !           615:        /*
        !           616:         * If no space left in the directory then allocate another cluster
        !           617:         * and chain it onto the end of the file.  There is one exception
        !           618:         * to this.  That is, if the root directory has no more space it
        !           619:         * can NOT be expanded.  extendfile() checks for and fails attempts
        !           620:         * to extend the root directory.  We just return an error in that
        !           621:         * case.
        !           622:         */
        !           623:        if (ddep->de_fndoffset >= ddep->de_FileSize) {
        !           624:                diroffset = ddep->de_fndoffset + sizeof(struct direntry)
        !           625:                    - ddep->de_FileSize;
        !           626:                dirclust = de_clcount(pmp, diroffset);
        !           627:                if ((error = extendfile(ddep, dirclust, 0, 0, DE_CLEAR)) != 0) {
        !           628:                        (void)detrunc(ddep, ddep->de_FileSize, 0, NOCRED, NULL);
        !           629:                        return error;
        !           630:                }
        !           631:
        !           632:                /*
        !           633:                 * Update the size of the directory
        !           634:                 */
        !           635:                ddep->de_FileSize += de_cn2off(pmp, dirclust);
        !           636:        }
        !           637:
        !           638:        /*
        !           639:         * We just read in the cluster with space.  Copy the new directory
        !           640:         * entry in.  Then write it to disk. NOTE:  DOS directories
        !           641:         * do not get smaller as clusters are emptied.
        !           642:         */
        !           643:        error = pcbmap(ddep, de_cluster(pmp, ddep->de_fndoffset),
        !           644:                       &bn, &dirclust, &blsize);
        !           645:        if (error)
        !           646:                return error;
        !           647:        diroffset = ddep->de_fndoffset;
        !           648:        if (dirclust != MSDOSFSROOT)
        !           649:                diroffset &= pmp->pm_crbomask;
        !           650:        if ((error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp)) != 0) {
        !           651:                brelse(bp);
        !           652:                return error;
        !           653:        }
        !           654:        ndep = bptoep(pmp, bp, ddep->de_fndoffset);
        !           655:
        !           656:        DE_EXTERNALIZE(ndep, dep);
        !           657:
        !           658:        /*
        !           659:         * Now write the Win95 long name
        !           660:         */
        !           661:        if (ddep->de_fndcnt > 0) {
        !           662:                u_int8_t chksum = winChksum(ndep->deName);
        !           663:                u_char *un = (u_char *)cnp->cn_nameptr;
        !           664:                int unlen = cnp->cn_namelen;
        !           665:                int cnt = 1;
        !           666:
        !           667:                while (--ddep->de_fndcnt >= 0) {
        !           668:                        if (!(ddep->de_fndoffset & pmp->pm_crbomask)) {
        !           669:                                if ((error = bwrite(bp)) != 0)
        !           670:                                        return error;
        !           671:
        !           672:                                ddep->de_fndoffset -= sizeof(struct direntry);
        !           673:                                error = pcbmap(ddep,
        !           674:                                               de_cluster(pmp,
        !           675:                                                          ddep->de_fndoffset),
        !           676:                                               &bn, 0, &blsize);
        !           677:                                if (error)
        !           678:                                        return error;
        !           679:
        !           680:                                error = bread(pmp->pm_devvp, bn, blsize,
        !           681:                                              NOCRED, &bp);
        !           682:                                if (error) {
        !           683:                                        brelse(bp);
        !           684:                                        return error;
        !           685:                                }
        !           686:                                ndep = bptoep(pmp, bp, ddep->de_fndoffset);
        !           687:                        } else {
        !           688:                                ndep--;
        !           689:                                ddep->de_fndoffset -= sizeof(struct direntry);
        !           690:                        }
        !           691:                        if (!unix2winfn(un, unlen, (struct winentry *)ndep, cnt++, chksum))
        !           692:                                break;
        !           693:                }
        !           694:        }
        !           695:
        !           696:        if ((error = bwrite(bp)) != 0)
        !           697:                return error;
        !           698:
        !           699:        /*
        !           700:         * If they want us to return with the denode gotten.
        !           701:         */
        !           702:        if (depp) {
        !           703:                if (dep->de_Attributes & ATTR_DIRECTORY) {
        !           704:                        dirclust = dep->de_StartCluster;
        !           705:                        if (FAT32(pmp) && dirclust == pmp->pm_rootdirblk)
        !           706:                                dirclust = MSDOSFSROOT;
        !           707:                        if (dirclust == MSDOSFSROOT)
        !           708:                                diroffset = MSDOSFSROOT_OFS;
        !           709:                        else
        !           710:                                diroffset = 0;
        !           711:                }
        !           712:                return deget(pmp, dirclust, diroffset, depp);
        !           713:        }
        !           714:
        !           715:        return 0;
        !           716: }
        !           717:
        !           718: /*
        !           719:  * Be sure a directory is empty except for "." and "..". Return 1 if empty,
        !           720:  * return 0 if not empty or error.
        !           721:  */
        !           722: int
        !           723: dosdirempty(dep)
        !           724:        struct denode *dep;
        !           725: {
        !           726:        int blsize;
        !           727:        int error;
        !           728:        uint32_t cn;
        !           729:        daddr64_t bn;
        !           730:        struct buf *bp;
        !           731:        struct msdosfsmount *pmp = dep->de_pmp;
        !           732:        struct direntry *dentp;
        !           733:
        !           734:        /*
        !           735:         * Since the filesize field in directory entries for a directory is
        !           736:         * zero, we just have to feel our way through the directory until
        !           737:         * we hit end of file.
        !           738:         */
        !           739:        for (cn = 0;; cn++) {
        !           740:                if ((error = pcbmap(dep, cn, &bn, 0, &blsize)) != 0) {
        !           741:                        if (error == E2BIG)
        !           742:                                return (1);     /* it's empty */
        !           743:                        return (0);
        !           744:                }
        !           745:                error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp);
        !           746:                if (error) {
        !           747:                        brelse(bp);
        !           748:                        return (0);
        !           749:                }
        !           750:                for (dentp = (struct direntry *)bp->b_data;
        !           751:                     (char *)dentp < bp->b_data + blsize;
        !           752:                     dentp++) {
        !           753:                        if (dentp->deName[0] != SLOT_DELETED &&
        !           754:                            (dentp->deAttributes & ATTR_VOLUME) == 0) {
        !           755:                                /*
        !           756:                                 * In dos directories an entry whose name
        !           757:                                 * starts with SLOT_EMPTY (0) starts the
        !           758:                                 * beginning of the unused part of the
        !           759:                                 * directory, so we can just return that it
        !           760:                                 * is empty.
        !           761:                                 */
        !           762:                                if (dentp->deName[0] == SLOT_EMPTY) {
        !           763:                                        brelse(bp);
        !           764:                                        return (1);
        !           765:                                }
        !           766:                                /*
        !           767:                                 * Any names other than "." and ".." in a
        !           768:                                 * directory mean it is not empty.
        !           769:                                 */
        !           770:                                if (bcmp(dentp->deName, ".          ", 11) &&
        !           771:                                    bcmp(dentp->deName, "..         ", 11)) {
        !           772:                                        brelse(bp);
        !           773: #ifdef MSDOSFS_DEBUG
        !           774:                                        printf("dosdirempty(): entry found %02x, %02x\n",
        !           775:                                            dentp->deName[0], dentp->deName[1]);
        !           776: #endif
        !           777:                                        return (0);     /* not empty */
        !           778:                                }
        !           779:                        }
        !           780:                }
        !           781:                brelse(bp);
        !           782:        }
        !           783:        /* NOTREACHED */
        !           784: }
        !           785:
        !           786: /*
        !           787:  * Check to see if the directory described by target is in some
        !           788:  * subdirectory of source.  This prevents something like the following from
        !           789:  * succeeding and leaving a bunch or files and directories orphaned. mv
        !           790:  * /a/b/c /a/b/c/d/e/f Where c and f are directories.
        !           791:  *
        !           792:  * source - the inode for /a/b/c
        !           793:  * target - the inode for /a/b/c/d/e/f
        !           794:  *
        !           795:  * Returns 0 if target is NOT a subdirectory of source.
        !           796:  * Otherwise returns a non-zero error number.
        !           797:  * The target inode is always unlocked on return.
        !           798:  */
        !           799: int
        !           800: doscheckpath(source, target)
        !           801:        struct denode *source;
        !           802:        struct denode *target;
        !           803: {
        !           804:        uint32_t scn;
        !           805:        struct msdosfsmount *pmp;
        !           806:        struct direntry *ep;
        !           807:        struct denode *dep;
        !           808:        struct buf *bp = NULL;
        !           809:        int error = 0;
        !           810:
        !           811:        dep = target;
        !           812:        if ((target->de_Attributes & ATTR_DIRECTORY) == 0 ||
        !           813:            (source->de_Attributes & ATTR_DIRECTORY) == 0) {
        !           814:                error = ENOTDIR;
        !           815:                goto out;
        !           816:        }
        !           817:        if (dep->de_StartCluster == source->de_StartCluster) {
        !           818:                error = EEXIST;
        !           819:                goto out;
        !           820:        }
        !           821:        if (dep->de_StartCluster == MSDOSFSROOT)
        !           822:                goto out;
        !           823:        pmp = dep->de_pmp;
        !           824: #ifdef DIAGNOSTIC
        !           825:        if (pmp != source->de_pmp)
        !           826:                panic("doscheckpath: source and target on different filesystems");
        !           827: #endif
        !           828:        if (FAT32(pmp) && dep->de_StartCluster == pmp->pm_rootdirblk)
        !           829:                goto out;
        !           830:
        !           831:        for (;;) {
        !           832:                if ((dep->de_Attributes & ATTR_DIRECTORY) == 0) {
        !           833:                        error = ENOTDIR;
        !           834:                        break;
        !           835:                }
        !           836:                scn = dep->de_StartCluster;
        !           837:                error = bread(pmp->pm_devvp, cntobn(pmp, scn),
        !           838:                              pmp->pm_bpcluster, NOCRED, &bp);
        !           839:                if (error)
        !           840:                        break;
        !           841:
        !           842:                ep = (struct direntry *) bp->b_data + 1;
        !           843:                if ((ep->deAttributes & ATTR_DIRECTORY) == 0 ||
        !           844:                    bcmp(ep->deName, "..         ", 11) != 0) {
        !           845:                        error = ENOTDIR;
        !           846:                        break;
        !           847:                }
        !           848:                scn = getushort(ep->deStartCluster);
        !           849:                if (FAT32(pmp))
        !           850:                        scn |= getushort(ep->deHighClust) << 16;
        !           851:
        !           852:                if (scn == source->de_StartCluster) {
        !           853:                        error = EINVAL;
        !           854:                        break;
        !           855:                }
        !           856:                if (scn == MSDOSFSROOT)
        !           857:                        break;
        !           858:                if (FAT32(pmp) && scn == pmp->pm_rootdirblk) {
        !           859:                        /*
        !           860:                         * scn should be 0 in this case,
        !           861:                         * but we silently ignore the error.
        !           862:                         */
        !           863:                        break;
        !           864:                }
        !           865:
        !           866:                vput(DETOV(dep));
        !           867:                brelse(bp);
        !           868:                bp = NULL;
        !           869:                /* NOTE: deget() clears dep on error */
        !           870:                if ((error = deget(pmp, scn, 0, &dep)) != 0)
        !           871:                        break;
        !           872:        }
        !           873: out:;
        !           874:        if (bp)
        !           875:                brelse(bp);
        !           876:        if (error == ENOTDIR)
        !           877:                printf("doscheckpath(): .. not a directory?\n");
        !           878:        if (dep != NULL)
        !           879:                vput(DETOV(dep));
        !           880:        return (error);
        !           881: }
        !           882:
        !           883: /*
        !           884:  * Read in the disk block containing the directory entry (dirclu, dirofs)
        !           885:  * and return the address of the buf header, and the address of the
        !           886:  * directory entry within the block.
        !           887:  */
        !           888: int
        !           889: readep(pmp, dirclust, diroffset, bpp, epp)
        !           890:        struct msdosfsmount *pmp;
        !           891:        uint32_t dirclust, diroffset;
        !           892:        struct buf **bpp;
        !           893:        struct direntry **epp;
        !           894: {
        !           895:        int error;
        !           896:        daddr64_t bn;
        !           897:        int blsize;
        !           898:        uint32_t boff;
        !           899:
        !           900:        boff = diroffset & ~pmp->pm_crbomask;
        !           901:        blsize = pmp->pm_bpcluster;
        !           902:        if (dirclust == MSDOSFSROOT
        !           903:            && de_blk(pmp, diroffset + blsize) > pmp->pm_rootdirsize)
        !           904:                blsize = de_bn2off(pmp, pmp->pm_rootdirsize) & pmp->pm_crbomask;
        !           905:        bn = detobn(pmp, dirclust, diroffset);
        !           906:        if ((error = bread(pmp->pm_devvp, bn, blsize, NOCRED, bpp)) != 0) {
        !           907:                brelse(*bpp);
        !           908:                *bpp = NULL;
        !           909:                return (error);
        !           910:        }
        !           911:        if (epp)
        !           912:                *epp = bptoep(pmp, *bpp, diroffset);
        !           913:        return (0);
        !           914: }
        !           915:
        !           916: /*
        !           917:  * Read in the disk block containing the directory entry dep came from and
        !           918:  * return the address of the buf header, and the address of the directory
        !           919:  * entry within the block.
        !           920:  */
        !           921: int
        !           922: readde(dep, bpp, epp)
        !           923:        struct denode *dep;
        !           924:        struct buf **bpp;
        !           925:        struct direntry **epp;
        !           926: {
        !           927:
        !           928:        return (readep(dep->de_pmp, dep->de_dirclust, dep->de_diroffset,
        !           929:            bpp, epp));
        !           930: }
        !           931:
        !           932: /*
        !           933:  * Remove a directory entry. At this point the file represented by the
        !           934:  * directory entry to be removed is still full length until noone has it
        !           935:  * open.  When the file no longer being used msdosfs_inactive() is called
        !           936:  * and will truncate the file to 0 length.  When the vnode containing the
        !           937:  * denode is needed for some other purpose by VFS it will call
        !           938:  * msdosfs_reclaim() which will remove the denode from the denode cache.
        !           939:  */
        !           940: int
        !           941: removede(pdep, dep)
        !           942:        struct denode *pdep;    /* directory where the entry is removed */
        !           943:        struct denode *dep;     /* file to be removed */
        !           944: {
        !           945:        int error;
        !           946:        struct direntry *ep;
        !           947:        struct buf *bp;
        !           948:        daddr64_t bn;
        !           949:        int blsize;
        !           950:        struct msdosfsmount *pmp = pdep->de_pmp;
        !           951:        uint32_t offset = pdep->de_fndoffset;
        !           952:
        !           953: #ifdef MSDOSFS_DEBUG
        !           954:        printf("removede(): filename %s, dep %08x, offset %08x\n",
        !           955:            dep->de_Name, dep, offset);
        !           956: #endif
        !           957:
        !           958:        dep->de_refcnt--;
        !           959:        offset += sizeof(struct direntry);
        !           960:        do {
        !           961:                offset -= sizeof(struct direntry);
        !           962:                error = pcbmap(pdep, de_cluster(pmp, offset), &bn, 0, &blsize);
        !           963:                if (error)
        !           964:                        return error;
        !           965:                error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp);
        !           966:                if (error) {
        !           967:                        brelse(bp);
        !           968:                        return error;
        !           969:                }
        !           970:                ep = bptoep(pmp, bp, offset);
        !           971:                /*
        !           972:                 * Check whether, if we came here the second time, i.e.
        !           973:                 * when underflowing into the previous block, the last
        !           974:                 * entry in this block is a longfilename entry, too.
        !           975:                 */
        !           976:                if (ep->deAttributes != ATTR_WIN95
        !           977:                    && offset != pdep->de_fndoffset) {
        !           978:                        brelse(bp);
        !           979:                        break;
        !           980:                }
        !           981:                offset += sizeof(struct direntry);
        !           982:                while (1) {
        !           983:                        /*
        !           984:                         * We are a bit agressive here in that we delete any Win95
        !           985:                         * entries preceding this entry, not just the ones we "own".
        !           986:                         * Since these presumably aren't valid anyway,
        !           987:                         * there should be no harm.
        !           988:                         */
        !           989:                        offset -= sizeof(struct direntry);
        !           990:                        ep--->deName[0] = SLOT_DELETED;
        !           991:                        if ((pmp->pm_flags & MSDOSFSMNT_NOWIN95)
        !           992:                            || !(offset & pmp->pm_crbomask)
        !           993:                            || ep->deAttributes != ATTR_WIN95)
        !           994:                                break;
        !           995:                }
        !           996:                if ((error = bwrite(bp)) != 0)
        !           997:                        return error;
        !           998:        } while (!(pmp->pm_flags & MSDOSFSMNT_NOWIN95)
        !           999:            && !(offset & pmp->pm_crbomask)
        !          1000:            && offset);
        !          1001:        return 0;
        !          1002: }
        !          1003:
        !          1004: /*
        !          1005:  * Create a unique DOS name in dvp
        !          1006:  */
        !          1007: int
        !          1008: uniqdosname(dep, cnp, cp)
        !          1009:        struct denode *dep;
        !          1010:        struct componentname *cnp;
        !          1011:        u_char *cp;
        !          1012: {
        !          1013:        struct msdosfsmount *pmp = dep->de_pmp;
        !          1014:        struct direntry *dentp;
        !          1015:        int gen;
        !          1016:        int blsize;
        !          1017:        uint32_t cn;
        !          1018:        daddr64_t bn;
        !          1019:        struct buf *bp;
        !          1020:        int error;
        !          1021:
        !          1022:        for (gen = 1;; gen++) {
        !          1023:                /*
        !          1024:                 * Generate DOS name with generation number
        !          1025:                 */
        !          1026:                if (!unix2dosfn((u_char *)cnp->cn_nameptr, cp, cnp->cn_namelen, gen))
        !          1027:                        return gen == 1 ? EINVAL : EEXIST;
        !          1028:
        !          1029:                /*
        !          1030:                 * Now look for a dir entry with this exact name
        !          1031:                 */
        !          1032:                for (cn = error = 0; !error; cn++) {
        !          1033:                        if ((error = pcbmap(dep, cn, &bn, 0, &blsize)) != 0) {
        !          1034:                                if (error == E2BIG)     /* EOF reached and not found */
        !          1035:                                        return 0;
        !          1036:                                return error;
        !          1037:                        }
        !          1038:                        error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp);
        !          1039:                        if (error) {
        !          1040:                                brelse(bp);
        !          1041:                                return error;
        !          1042:                        }
        !          1043:                        for (dentp = (struct direntry *)bp->b_data;
        !          1044:                             (char *)dentp < bp->b_data + blsize;
        !          1045:                             dentp++) {
        !          1046:                                if (dentp->deName[0] == SLOT_EMPTY) {
        !          1047:                                        /*
        !          1048:                                         * Last used entry and not found
        !          1049:                                         */
        !          1050:                                        brelse(bp);
        !          1051:                                        return 0;
        !          1052:                                }
        !          1053:                                /*
        !          1054:                                 * Ignore volume labels and Win95 entries
        !          1055:                                 */
        !          1056:                                if (dentp->deAttributes & ATTR_VOLUME)
        !          1057:                                        continue;
        !          1058:                                if (!bcmp(dentp->deName, cp, 11)) {
        !          1059:                                        error = EEXIST;
        !          1060:                                        break;
        !          1061:                                }
        !          1062:                        }
        !          1063:                        brelse(bp);
        !          1064:                }
        !          1065:        }
        !          1066:
        !          1067:        return (EEXIST);
        !          1068: }
        !          1069:
        !          1070: /*
        !          1071:  * Find any Win'95 long filename entry in directory dep
        !          1072:  */
        !          1073: int
        !          1074: findwin95(dep)
        !          1075:        struct denode *dep;
        !          1076: {
        !          1077:        struct msdosfsmount *pmp = dep->de_pmp;
        !          1078:        struct direntry *dentp;
        !          1079:        int blsize;
        !          1080:        uint32_t cn;
        !          1081:        daddr64_t bn;
        !          1082:        struct buf *bp;
        !          1083:
        !          1084:        /*
        !          1085:         * Read through the directory looking for Win'95 entries
        !          1086:         * Note: Error currently handled just as EOF                    XXX
        !          1087:         */
        !          1088:        for (cn = 0;; cn++) {
        !          1089:                if (pcbmap(dep, cn, &bn, 0, &blsize))
        !          1090:                        return 0;
        !          1091:                if (bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp)) {
        !          1092:                        brelse(bp);
        !          1093:                        return 0;
        !          1094:                }
        !          1095:                for (dentp = (struct direntry *)bp->b_data;
        !          1096:                     (char *)dentp < bp->b_data + blsize;
        !          1097:                     dentp++) {
        !          1098:                        if (dentp->deName[0] == SLOT_EMPTY) {
        !          1099:                                /*
        !          1100:                                 * Last used entry and not found
        !          1101:                                 */
        !          1102:                                brelse(bp);
        !          1103:                                return 0;
        !          1104:                        }
        !          1105:                        if (dentp->deName[0] == SLOT_DELETED) {
        !          1106:                                /*
        !          1107:                                 * Ignore deleted files
        !          1108:                                 * Note: might be an indication of Win'95 anyway        XXX
        !          1109:                                 */
        !          1110:                                continue;
        !          1111:                        }
        !          1112:                        if (dentp->deAttributes == ATTR_WIN95) {
        !          1113:                                brelse(bp);
        !          1114:                                return 1;
        !          1115:                        }
        !          1116:                }
        !          1117:                brelse(bp);
        !          1118:        }
        !          1119: }

CVSweb