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

1.1     ! root        1: /*
        !             2:  *  Written by Paul Popelka ([email protected])
        !             3:  *
        !             4:  *  You can do anything you want with this software,
        !             5:  *    just don't say you wrote it,
        !             6:  *    and don't remove this notice.
        !             7:  *
        !             8:  *  This software is provided "as is".
        !             9:  *
        !            10:  *  The author supplies this software to be publicly
        !            11:  *  redistributed on the understanding that the author
        !            12:  *  is not responsible for the correct functioning of
        !            13:  *  this software in any circumstances and is not liable
        !            14:  *  for any damages caused by this software.
        !            15:  *
        !            16:  *  October 1992
        !            17:  *
        !            18:  *     pcfs_lookup.c,v 1.3 1993/05/20 03:34:16 cgd Exp
        !            19:  */
        !            20: 
        !            21: #include "param.h"
        !            22: #include "namei.h"
        !            23: #include "buf.h"
        !            24: #include "vnode.h"
        !            25: #include "mount.h"
        !            26: 
        !            27: #include "bpb.h"
        !            28: #include "direntry.h"
        !            29: #include "denode.h"
        !            30: #include "pcfsmount.h"
        !            31: #include "fat.h"
        !            32: 
        !            33: /*
        !            34:  *  When we search a directory the blocks containing directory
        !            35:  *  entries are read and examined.  The directory entries
        !            36:  *  contain information that would normally be in the inode
        !            37:  *  of a unix filesystem.  This means that some of a directory's
        !            38:  *  contents may also be in memory resident denodes (sort of
        !            39:  *  an inode).  This can cause problems if we are searching
        !            40:  *  while some other process is modifying a directory.  To
        !            41:  *  prevent one process from accessing incompletely modified
        !            42:  *  directory information we depend upon being the soul owner
        !            43:  *  of a directory block.  bread/brelse provide this service.
        !            44:  *  This being the case, when a process modifies a directory
        !            45:  *  it must first acquire the disk block that contains the
        !            46:  *  directory entry to be modified.  Then update the disk
        !            47:  *  block and the denode, and then write the disk block out
        !            48:  *  to disk.  This way disk blocks containing directory
        !            49:  *  entries and in memory denode's will be in synch.
        !            50:  */
        !            51: int
        !            52: pcfs_lookup(vdp, ndp, p)
        !            53:        struct vnode *vdp;      /* vnode of directory to search         */
        !            54:        struct nameidata *ndp;
        !            55:        struct proc *p;
        !            56: {
        !            57:        daddr_t bn;
        !            58:        int flag;
        !            59:        int error;
        !            60:        int lockparent;
        !            61:        int wantparent;
        !            62:        int slotstatus;
        !            63: #define        NONE    0
        !            64: #define        FOUND   1
        !            65:        int slotoffset;
        !            66:        int slotcluster;
        !            67:        int frcn;
        !            68:        u_long cluster;
        !            69:        int rootreloff;
        !            70:        int diroff;
        !            71:        int isadir;             /* ~0 if found direntry is a directory  */
        !            72:        u_long scn;             /* starting cluster number              */
        !            73:        struct denode *dp;
        !            74:        struct denode *pdp;
        !            75:        struct denode *tdp;
        !            76:        struct pcfsmount *pmp;
        !            77:        struct buf *bp = 0;
        !            78:        struct direntry *dep;
        !            79:        u_char dosfilename[12];
        !            80: 
        !            81: #if defined(PCFSDEBUG)
        !            82: printf("pcfs_lookup(): looking for %s\n", ndp->ni_ptr);
        !            83: #endif /* defined(PCFSDEBUG) */
        !            84:        ndp->ni_dvp = vdp;
        !            85:        ndp->ni_vp  = NULL;
        !            86:        dp = VTODE(vdp);
        !            87:        pmp = dp->de_pmp;
        !            88:        lockparent = ndp->ni_nameiop & LOCKPARENT;
        !            89:        flag = ndp->ni_nameiop & OPMASK;
        !            90:        wantparent = ndp->ni_nameiop & (LOCKPARENT | WANTPARENT);
        !            91: #if defined(PCFSDEBUG)
        !            92: printf("pcfs_lookup(): vdp %08x, dp %08x, Attr %02x\n",
        !            93:        vdp, dp, dp->de_Attributes);
        !            94: #endif /* defined(PCFSDEBUG) */
        !            95: 
        !            96: /*
        !            97:  *  Be sure vdp is a directory.  Since dos filesystems
        !            98:  *  don't have the concept of execute permission anybody
        !            99:  *  can search a directory.
        !           100:  */
        !           101:        if ((dp->de_Attributes & ATTR_DIRECTORY) == 0)
        !           102:                return ENOTDIR;
        !           103: 
        !           104: /*
        !           105:  *  See if the component of the pathname we are looking for
        !           106:  *  is in the directory cache.  If so then do a few things
        !           107:  *  and return.
        !           108:  */
        !           109:        if (error = cache_lookup(ndp)) {
        !           110:                int vpid;
        !           111: 
        !           112:                if (error == ENOENT)
        !           113:                        return error;
        !           114: #ifdef PARANOID
        !           115:                if (vdp == ndp->ni_rdir  &&  ndp->ni_isdotdot)
        !           116:                        panic("pcfs_lookup: .. thru root");
        !           117: #endif /* PARANOID */
        !           118:                pdp = dp;
        !           119:                vdp = ndp->ni_vp;
        !           120:                dp  = VTODE(vdp);
        !           121:                vpid = vdp->v_id;
        !           122:                if (pdp == dp) {
        !           123:                        VREF(vdp);
        !           124:                        error = 0;
        !           125:                } else if (ndp->ni_isdotdot) {
        !           126:                        DEUNLOCK(pdp);
        !           127:                        error = vget(vdp);
        !           128:                        if (!error && lockparent && *ndp->ni_next == '\0')
        !           129:                                DELOCK(pdp);
        !           130:                } else {
        !           131:                        error = vget(vdp);
        !           132:                        if (!lockparent || error || *ndp->ni_next != '\0')
        !           133:                                DEUNLOCK(pdp);
        !           134:                }
        !           135: 
        !           136:                if (!error) {
        !           137:                        if (vpid == vdp->v_id) {
        !           138: #if defined(PCFSDEBUG)
        !           139: printf("pcfs_lookup(): cache hit, vnode %08x, file %s\n", vdp, dp->de_Name);
        !           140: #endif /* defined(PCFSDEBUG) */
        !           141:                                return 0;
        !           142:                        }
        !           143:                        deput(dp);
        !           144:                        if (lockparent && pdp != dp && *ndp->ni_next == '\0')
        !           145:                                DEUNLOCK(pdp);
        !           146:                }
        !           147:                DELOCK(pdp);
        !           148:                dp = pdp;
        !           149:                vdp = DETOV(dp);
        !           150:                ndp->ni_vp = NULL;
        !           151:        }
        !           152: 
        !           153: /*
        !           154:  *  If they are going after the . or .. entry in the
        !           155:  *  root directory, they won't find it.  DOS filesystems
        !           156:  *  don't have them in the root directory.  So, we fake it.
        !           157:  *  deget() is in on this scam too.
        !           158:  */
        !           159:        if ((vdp->v_flag & VROOT)  &&  ndp->ni_ptr[0] == '.'  &&
        !           160:            (ndp->ni_namelen == 1  ||
        !           161:             (ndp->ni_namelen == 2  &&  ndp->ni_ptr[1] == '.'))) {
        !           162:                isadir = ATTR_DIRECTORY;
        !           163:                scn = PCFSROOT;
        !           164: #if defined(PCFSDEBUG)
        !           165: printf("pcfs_lookup(): looking for . or .. in root directory\n");
        !           166: #endif /* defined(PCFSDEBUG) */
        !           167:                cluster == PCFSROOT;
        !           168:                diroff = PCFSROOT_OFS;
        !           169:                goto foundroot;
        !           170:        }
        !           171: 
        !           172: /*
        !           173:  *  Don't search for free slots unless we are creating
        !           174:  *  a filename and we are at the end of the pathname.
        !           175:  */
        !           176:        slotstatus = FOUND;
        !           177:        if ((flag == CREATE || flag == RENAME) && *ndp->ni_next == '\0') {
        !           178:                slotstatus = NONE;
        !           179:                slotoffset = -1;
        !           180:        }
        !           181: 
        !           182:        unix2dosfn((u_char *)ndp->ni_ptr, dosfilename, ndp->ni_namelen);
        !           183:        dosfilename[11] = 0;
        !           184: #if defined(PCFSDEBUG)
        !           185: printf("pcfs_lookup(): dos version of filename %s, length %d\n",
        !           186:        dosfilename, ndp->ni_namelen);
        !           187: #endif /* defined(PCFSDEBUG) */
        !           188: /*
        !           189:  *  Search the directory pointed at by vdp for the
        !           190:  *  name pointed at by ndp->ni_ptr.
        !           191:  */
        !           192:        tdp = NULL;
        !           193: /*
        !           194:  *  The outer loop ranges over the clusters that make
        !           195:  *  up the directory.  Note that the root directory is
        !           196:  *  different from all other directories.  It has a
        !           197:  *  fixed number of blocks that are not part of the
        !           198:  *  pool of allocatable clusters.  So, we treat it a
        !           199:  *  little differently.
        !           200:  *  The root directory starts at "cluster" 0.
        !           201:  */
        !           202:        rootreloff = 0;
        !           203:        for (frcn = 0; ; frcn++) {
        !           204:                if (error = pcbmap(dp, frcn, &bn, &cluster)) {
        !           205:                        if (error == E2BIG)
        !           206:                                break;
        !           207:                        return error;
        !           208:                }
        !           209:                error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, NOCRED, &bp);
        !           210:                if (error) {
        !           211:                        brelse(bp);
        !           212:                        return error;
        !           213:                }
        !           214:                dep = (struct direntry *)bp->b_un.b_addr;
        !           215:                for (diroff = 0; diroff < pmp->pm_depclust; diroff++, dep++) {
        !           216: /*
        !           217:  *  If the slot is empty and we are still looking for
        !           218:  *  an empty then remember this one.  If the slot is
        !           219:  *  not empty then check to see if it matches what we
        !           220:  *  are looking for.  If the slot has never been filled
        !           221:  *  with anything, then the remainder of the directory
        !           222:  *  has never been used, so there is no point in searching
        !           223:  *  it.
        !           224:  */
        !           225:                        if (dep->deName[0] == SLOT_EMPTY   ||
        !           226:                            dep->deName[0] == SLOT_DELETED) {
        !           227:                                if (slotstatus != FOUND) {
        !           228:                                        slotstatus  = FOUND;
        !           229:                                        if (cluster == PCFSROOT)
        !           230:                                                slotoffset = rootreloff;
        !           231:                                        else
        !           232:                                                slotoffset = diroff;
        !           233:                                        slotcluster = cluster;
        !           234:                                }
        !           235:                                if (dep->deName[0] == SLOT_EMPTY) {
        !           236:                                        brelse(bp);
        !           237:                                        goto notfound;
        !           238:                                }
        !           239:                        } else {
        !           240:                                /* Ignore volume labels (anywhere, not just
        !           241:                                 * the root directory). */
        !           242:                                if ((dep->deAttributes & ATTR_VOLUME) == 0  &&
        !           243:                                    bcmp(dosfilename, dep->deName, 11) == 0) {
        !           244: #if defined(PCFSDEBUG)
        !           245: printf("pcfs_lookup(): match diroff %d, rootreloff %d\n", diroff, rootreloff);
        !           246: #endif /* defined(PCFSDEBUG) */
        !           247: /*
        !           248:  *  Remember where this directory entry came from
        !           249:  *  for whoever did this lookup.
        !           250:  *  If this is the root directory we are interested
        !           251:  *  in the offset relative to the beginning of the
        !           252:  *  directory (not the beginning of the cluster).
        !           253:  */
        !           254:                                        if (cluster == PCFSROOT)
        !           255:                                                diroff = rootreloff;
        !           256:                                        ndp->ni_pcfs.pcfs_offset = diroff;
        !           257:                                        ndp->ni_pcfs.pcfs_cluster = cluster;
        !           258:                                        goto found;
        !           259:                                }
        !           260:                        }
        !           261:                        rootreloff++;
        !           262:                }                       /* for (diroff = 0; .... */
        !           263: /*
        !           264:  *  Release the buffer holding the directory cluster
        !           265:  *  just searched.
        !           266:  */
        !           267:                brelse(bp);
        !           268:        }                       /* for (frcn = 0; ; frcn++) */
        !           269: notfound:;
        !           270: /*
        !           271:  *  We hold no disk buffers at this point.
        !           272:  */
        !           273: 
        !           274: /*
        !           275:  *  If we get here we didn't find the entry we were looking
        !           276:  *  for.  But that's ok if we are creating or renaming and
        !           277:  *  are at the end of the pathname and the directory hasn't
        !           278:  *  been removed.
        !           279:  */
        !           280: #if defined(PCFSDEBUG)
        !           281: printf("pcfs_lookup(): flag %d, refcnt %d, slotstatus %d\n",
        !           282:        flag, dp->de_refcnt, slotstatus);
        !           283: printf("               slotoffset %d, slotcluster %d\n",
        !           284:        slotoffset, slotcluster);
        !           285: #endif /* defined(PCFSDEBUG) */
        !           286:        if ((flag == CREATE || flag == RENAME)  &&
        !           287:            *ndp->ni_next == '\0' && dp->de_refcnt != 0) {
        !           288:                if (slotstatus == NONE) {
        !           289:                        ndp->ni_pcfs.pcfs_offset  = 0;
        !           290:                        ndp->ni_pcfs.pcfs_cluster = 0;
        !           291:                        ndp->ni_pcfs.pcfs_count   = 0;
        !           292:                } else {
        !           293: #if defined(PCFSDEBUG)
        !           294: printf("pcfs_lookup(): saving empty slot location\n");
        !           295: #endif /* defined(PCFSDEBUG) */
        !           296:                        ndp->ni_pcfs.pcfs_offset  = slotoffset;
        !           297:                        ndp->ni_pcfs.pcfs_cluster = slotcluster;
        !           298:                        ndp->ni_pcfs.pcfs_count   = 1;
        !           299:                }
        !           300: /*             dp->de_flag |= DEUPD; /* never update dos directories */
        !           301:                ndp->ni_nameiop |= SAVENAME;
        !           302:                if (!lockparent)        /* leave searched dir locked?   */
        !           303:                        DEUNLOCK(dp);
        !           304:        }
        !           305: /*
        !           306:  *  Insert name in cache as non-existant if not
        !           307:  *  trying to create it.
        !           308:  */
        !           309:        if (ndp->ni_makeentry && flag != CREATE)
        !           310:                cache_enter(ndp);
        !           311:        return ENOENT;
        !           312: 
        !           313: found:;
        !           314: /*
        !           315:  *  NOTE:  We still have the buffer with matched
        !           316:  *  directory entry at this point.
        !           317:  */
        !           318:        isadir = dep->deAttributes & ATTR_DIRECTORY;
        !           319:        scn = dep->deStartCluster;
        !           320: 
        !           321: foundroot:;
        !           322: /*
        !           323:  *  If we entered at foundroot, then we are looking
        !           324:  *  for the . or .. entry of the filesystems root
        !           325:  *  directory.  isadir and scn were setup before
        !           326:  *  jumping here.  And, bp is null.  There is no buf header.
        !           327:  */
        !           328: 
        !           329: /*
        !           330:  *  If deleting and at the end of the path, then
        !           331:  *  if we matched on "." then don't deget() we would
        !           332:  *  probably panic().  Otherwise deget() the directory
        !           333:  *  entry.
        !           334:  */
        !           335:        if (flag == DELETE && ndp->ni_next == '\0') {
        !           336:                if (dp->de_StartCluster == scn  &&
        !           337:                    isadir) { /* "." */
        !           338:                        VREF(vdp);
        !           339:                        ndp->ni_vp = vdp;
        !           340:                        if (bp) brelse(bp);
        !           341:                        return 0;
        !           342:                }
        !           343:                error = deget(pmp, cluster, diroff, dep, &tdp);
        !           344:                if (error) {
        !           345:                        if (bp) brelse(bp);
        !           346:                        return error;
        !           347:                }
        !           348:                ndp->ni_vp = DETOV(tdp);
        !           349:                if (!lockparent)
        !           350:                        DEUNLOCK(dp);
        !           351:                if (bp) brelse(bp);
        !           352:                return 0;
        !           353:        }
        !           354: 
        !           355: /*
        !           356:  *  If renaming.
        !           357:  */
        !           358:        if (flag == RENAME && wantparent && *ndp->ni_next == '\0') {
        !           359:                if (dp->de_StartCluster == scn  &&
        !           360:                    isadir) {
        !           361:                        if (bp) brelse(bp);
        !           362:                        return EISDIR;
        !           363:                }
        !           364:                error = deget(pmp, cluster, diroff, dep, &tdp);
        !           365:                if (error) {
        !           366:                        if (bp) brelse(bp);
        !           367:                        return error;
        !           368:                }
        !           369:                ndp->ni_vp = DETOV(tdp);
        !           370:                ndp->ni_nameiop |= SAVENAME;
        !           371:                if (!lockparent)
        !           372:                        DEUNLOCK(dp);
        !           373:                if (bp) brelse(bp);
        !           374:                return 0;
        !           375:        }
        !           376: 
        !           377: /*
        !           378:  *  ?
        !           379:  */
        !           380:        pdp = dp;
        !           381:        if (ndp->ni_isdotdot) {
        !           382:                DEUNLOCK(pdp);
        !           383:                error = deget(pmp, cluster, diroff, dep, &tdp);
        !           384:                if (error) {
        !           385:                        DELOCK(pdp);
        !           386:                        if (bp) brelse(bp);
        !           387:                        return error;
        !           388:                }
        !           389:                if (lockparent && *ndp->ni_next == '\0')
        !           390:                        DELOCK(pdp);
        !           391:                ndp->ni_vp = DETOV(tdp);
        !           392:        } else if (dp->de_StartCluster == scn  &&
        !           393:                   isadir) { /* "." */
        !           394:                VREF(vdp);
        !           395:                ndp->ni_vp = vdp;
        !           396:        } else {
        !           397:                error = deget(pmp, cluster, diroff, dep, &tdp);
        !           398:                if (error) {
        !           399:                        if (bp) brelse(bp);
        !           400:                        return error;
        !           401:                }
        !           402:                if (!lockparent || *ndp->ni_next != '\0')
        !           403:                        DEUNLOCK(pdp);
        !           404:                ndp->ni_vp = DETOV(tdp);
        !           405:        }
        !           406:        if (bp) brelse(bp);
        !           407: 
        !           408: /*
        !           409:  *  Insert name in cache if wanted.
        !           410:  */
        !           411:        if (ndp->ni_makeentry)
        !           412:                cache_enter(ndp);
        !           413:        return 0;
        !           414: }
        !           415: 
        !           416: /*
        !           417:  *  dep - directory to copy into the directory
        !           418:  *  ndp - nameidata structure containing info on
        !           419:  *    where to put the directory entry in the directory.
        !           420:  *  depp - return the address of the denode for the
        !           421:  *    created directory entry if depp != 0
        !           422:  */
        !           423: int
        !           424: createde(dep, ndp, depp)
        !           425:        struct denode *dep;
        !           426:        struct nameidata *ndp;
        !           427:        struct denode **depp;
        !           428: {
        !           429:        int bn;
        !           430:        int error;
        !           431:        u_long dirclust, diroffset;
        !           432:        struct direntry *ndep;
        !           433:        struct denode *ddep = VTODE(ndp->ni_dvp);       /* directory to add to */
        !           434:        struct pcfsmount *pmp = dep->de_pmp;
        !           435:        struct buf *bp;
        !           436: #if defined(PCFSDEBUG)
        !           437: printf("createde(dep %08x, ndp %08x, depp %08x)\n", dep, ndp, depp);
        !           438: #endif /* defined(PCFSDEBUG) */
        !           439: 
        !           440: /*
        !           441:  *  If no space left in the directory then allocate
        !           442:  *  another cluster and chain it onto the end of the
        !           443:  *  file.  There is one exception to this.  That is,
        !           444:  *  if the root directory has no more space it can NOT
        !           445:  *  be expanded.  extendfile() checks for and fails attempts to
        !           446:  *  extend the root directory.  We just return an error
        !           447:  *  in that case.
        !           448:  */
        !           449:        if (ndp->ni_pcfs.pcfs_count == 0) {
        !           450:                if (error = extendfile(ddep, &bp, &dirclust))
        !           451:                        return error;
        !           452:                ndep = (struct direntry *)bp->b_un.b_addr;
        !           453: /*
        !           454:  *  Let caller know where we put the directory entry.
        !           455:  */
        !           456:                ndp->ni_pcfs.pcfs_cluster = dirclust;
        !           457:                ndp->ni_pcfs.pcfs_offset  = diroffset = 0;
        !           458:        }
        !           459: 
        !           460:        else {
        !           461: /*
        !           462:  *  There is space in the existing directory.  So,
        !           463:  *  we just read in the cluster with space.  Copy
        !           464:  *  the new directory entry in.  Then write it to
        !           465:  *  disk.
        !           466:  *  NOTE:  DOS directories do not get smaller as
        !           467:  *  clusters are emptied.
        !           468:  */
        !           469:                dirclust = ndp->ni_pcfs.pcfs_cluster;
        !           470:                diroffset = ndp->ni_pcfs.pcfs_offset;
        !           471: 
        !           472:                error = readep(pmp, dirclust, diroffset, &bp, &ndep);
        !           473:                if (error)
        !           474:                        return error;
        !           475:        }
        !           476:        *ndep = dep->de_de;
        !           477: /*
        !           478:  *  If they want us to return with the denode gotten.
        !           479:  */
        !           480:        if (depp) {
        !           481:                error = deget(pmp, dirclust, diroffset, ndep, depp);
        !           482:                if (error)
        !           483:                        return error;
        !           484:        }
        !           485:        if (error = bwrite(bp))
        !           486: /*deput()?*/
        !           487:                return error;
        !           488:        return 0;
        !           489: }
        !           490: 
        !           491: /*
        !           492:  *  Read in a directory entry and mark it as being deleted.
        !           493:  */
        !           494: int
        !           495: markdeleted(pmp, dirclust, diroffset)
        !           496:        struct pcfsmount *pmp;
        !           497:        u_long dirclust;
        !           498:        u_long diroffset;
        !           499: {
        !           500:        int error;
        !           501:        struct direntry *ep;
        !           502:        struct buf *bp;
        !           503: 
        !           504:        error = readep(pmp, dirclust, diroffset, &bp, &ep);
        !           505:        if (error)
        !           506:                return error;
        !           507:        ep->deName[0] = SLOT_DELETED;
        !           508:        return bwrite(bp);
        !           509: }
        !           510: 
        !           511: /*
        !           512:  *  Remove a directory entry.
        !           513:  *  At this point the file represented by the directory
        !           514:  *  entry to be removed is still full length until no
        !           515:  *  one has it open.  When the file no longer being
        !           516:  *  used pcfs_inactive() is called and will truncate
        !           517:  *  the file to 0 length.  When the vnode containing
        !           518:  *  the denode is needed for some other purpose by 
        !           519:  *  VFS it will call pcfs_reclaim() which will remove
        !           520:  *  the denode from the denode cache.
        !           521:  */
        !           522: int
        !           523: removede(ndp)
        !           524:        struct nameidata *ndp;
        !           525: {
        !           526:        struct denode *dep = VTODE(ndp->ni_vp); /* the file being removed */
        !           527:        struct pcfsmount *pmp = dep->de_pmp;
        !           528:        int error;
        !           529: 
        !           530: #if defined(PCFSDEBUG)
        !           531: /*printf("removede(): filename %s\n", dep->de_Name);
        !           532: printf("rmde(): dep %08x, ndpcluster %d, ndpoffset %d\n",
        !           533:        dep, ndp->ni_pcfs.pcfs_cluster, ndp->ni_pcfs.pcfs_offset);*/
        !           534: #endif /* defined(PCFSDEBUG) */
        !           535: 
        !           536: /*
        !           537:  *  Read the directory block containing the directory
        !           538:  *  entry we are to make free.  The nameidata structure
        !           539:  *  holds the cluster number and directory entry index
        !           540:  *  number of the entry to free.
        !           541:  */
        !           542:        error = markdeleted(pmp, ndp->ni_pcfs.pcfs_cluster,
        !           543:                ndp->ni_pcfs.pcfs_offset);
        !           544: 
        !           545:        dep->de_refcnt--;
        !           546:        return error;
        !           547: }
        !           548: 
        !           549: /*
        !           550:  *  Be sure a directory is empty except for "." and "..".
        !           551:  *  Return 1 if empty, return 0 if not empty or error.
        !           552:  */
        !           553: int
        !           554: dosdirempty(dep)
        !           555:        struct denode *dep;
        !           556: {
        !           557:        int dei;
        !           558:        int error;
        !           559:        u_long cn;
        !           560:        daddr_t bn;
        !           561:        struct buf *bp;
        !           562:        struct pcfsmount *pmp = dep->de_pmp;
        !           563:        struct direntry *dentp;
        !           564: 
        !           565: /*
        !           566:  *  Since the filesize field in directory entries for a directory
        !           567:  *  is zero, we just have to feel our way through the directory
        !           568:  *  until we hit end of file.
        !           569:  */
        !           570:        for (cn = 0;; cn++) {
        !           571:                error = pcbmap(dep, cn, &bn, 0);
        !           572:                if (error == E2BIG)
        !           573:                        return 1;       /* it's empty */
        !           574:                error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, NOCRED,
        !           575:                        &bp);
        !           576:                if (error) {
        !           577:                        brelse(bp);
        !           578:                        return error;
        !           579:                }
        !           580:                dentp = (struct direntry *)bp->b_un.b_addr;
        !           581:                for (dei = 0; dei < pmp->pm_depclust; dei++) {
        !           582:                        if (dentp->deName[0] != SLOT_DELETED) {
        !           583: /*
        !           584:  *  In dos directories an entry whose name starts with SLOT_EMPTY (0)
        !           585:  *  starts the beginning of the unused part of the directory, so we
        !           586:  *  can just return that it is empty.
        !           587:  */
        !           588:                                if (dentp->deName[0] == SLOT_EMPTY) {
        !           589:                                        brelse(bp);
        !           590:                                        return 1;
        !           591:                                }
        !           592: /*
        !           593:  *  Any names other than "." and ".." in a directory mean
        !           594:  *  it is not empty.
        !           595:  */
        !           596:                                if (bcmp(dentp->deName, ".          ", 11)  &&
        !           597:                                    bcmp(dentp->deName, "..         ", 11)) {
        !           598:                                        brelse(bp);
        !           599: #if defined(PCFSDEBUG)
        !           600: printf("dosdirempty(): entry %d found %02x, %02x\n", dei, dentp->deName[0],
        !           601:        dentp->deName[1]);
        !           602: #endif /* defined(PCFSDEBUG) */
        !           603:                                        return 0;       /* not empty */
        !           604:                                }
        !           605:                        }
        !           606:                        dentp++;
        !           607:                }
        !           608:                brelse(bp);
        !           609:        }
        !           610:        /*NOTREACHED*/
        !           611: }
        !           612: 
        !           613: /*
        !           614:  *  Check to see if the directory described by target is
        !           615:  *  in some subdirectory of source.  This prevents something
        !           616:  *  like the following from succeeding and leaving a bunch
        !           617:  *  or files and directories orphaned.
        !           618:  *     mv /a/b/c /a/b/c/d/e/f
        !           619:  *  Where c and f are directories.
        !           620:  *  source - the inode for /a/b/c
        !           621:  *  target - the inode for /a/b/c/d/e/f
        !           622:  *  Returns 0 if target is NOT a subdirectory of source.
        !           623:  *  Otherwise returns a non-zero error number.
        !           624:  *  The target inode is always unlocked on return.
        !           625:  */
        !           626: int
        !           627: doscheckpath(source, target)
        !           628:        struct denode *source;
        !           629:        struct denode *target;
        !           630: {
        !           631:        daddr_t scn;
        !           632:        struct denode dummy;
        !           633:        struct pcfsmount *pmp;
        !           634:        struct direntry *ep;
        !           635:        struct denode *dep;
        !           636:        struct buf *bp = NULL;
        !           637:        int error = 0;
        !           638: 
        !           639:        dep = target;
        !           640:        if ((target->de_Attributes & ATTR_DIRECTORY) == 0  ||
        !           641:            (source->de_Attributes & ATTR_DIRECTORY) == 0) {
        !           642:                error = ENOTDIR;
        !           643:                goto out;
        !           644:        }
        !           645:        if (dep->de_StartCluster == source->de_StartCluster) {
        !           646:                error = EEXIST;
        !           647:                goto out;
        !           648:        }
        !           649:        if (dep->de_StartCluster == PCFSROOT)
        !           650:                goto out;
        !           651:        for (;;) {
        !           652:                if ((dep->de_Attributes & ATTR_DIRECTORY) == 0) {
        !           653:                        error = ENOTDIR;
        !           654:                        break;
        !           655:                }
        !           656:                pmp = dep->de_pmp;
        !           657:                scn = dep->de_StartCluster;
        !           658:                error = readep(pmp, scn, 1, &bp, &ep);
        !           659:                if (error)
        !           660:                        break;
        !           661:                if ((ep->deAttributes & ATTR_DIRECTORY) == 0  ||
        !           662:                    bcmp(ep->deName, "..         ", 11) != 0) {
        !           663:                        /* Bad Directory */
        !           664:                        error = ENOTDIR;
        !           665:                        break;
        !           666:                }
        !           667:                if (ep->deStartCluster == source->de_StartCluster) {
        !           668:                        error = EINVAL;
        !           669:                        break;
        !           670:                }
        !           671:                if (ep->deStartCluster == PCFSROOT)
        !           672:                        break;
        !           673:                deput(dep);
        !           674:                /* NOTE: deget() clears dep on error */
        !           675:                error = deget(pmp, ep->deStartCluster, 0, ep, &dep);
        !           676:                brelse(bp);
        !           677:                bp = NULL;
        !           678:                if (error)
        !           679:                        break;
        !           680:        }
        !           681: out:;
        !           682:        if (bp)
        !           683:                brelse(bp);
        !           684:        if (error == ENOTDIR)
        !           685:                printf("doscheckpath(): .. not a directory?\n");
        !           686:        if (dep != NULL)
        !           687:                deput(dep);
        !           688:        return error;
        !           689: }
        !           690: 
        !           691: /*
        !           692:  *  Read in the disk block containing the directory entry
        !           693:  *  (dirclu, dirofs) and return the address of the buf header,
        !           694:  *  and the address of the directory entry within the block.
        !           695:  */
        !           696: int
        !           697: readep(pmp, dirclu, dirofs, bpp, epp)
        !           698:        struct pcfsmount *pmp;
        !           699:        u_long dirclu, dirofs;
        !           700:        struct buf **bpp;
        !           701:        struct direntry **epp;
        !           702: {
        !           703:        int error;
        !           704:        daddr_t bn;
        !           705: 
        !           706:        bn = detobn(pmp, dirclu, dirofs);
        !           707:        if (error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, NOCRED, bpp)) {
        !           708:                brelse(*bpp);
        !           709:                *bpp = NULL;
        !           710:                return error;
        !           711:        }
        !           712:        if (epp)
        !           713:                *epp = bptoep(pmp, *bpp, dirofs);
        !           714:        return 0;
        !           715: }
        !           716: 
        !           717: 
        !           718: /*
        !           719:  *  Read in the disk block containing the directory entry
        !           720:  *  dep came from and return the address of the buf header,
        !           721:  *  and the address of the directory entry within the block.
        !           722:  */
        !           723: int
        !           724: readde(dep, bpp, epp)
        !           725:        struct denode *dep;
        !           726:        struct buf **bpp;
        !           727:        struct direntry **epp;
        !           728: {
        !           729:        return readep(dep->de_pmp, dep->de_dirclust, dep->de_diroffset,
        !           730:                      bpp, epp);
        !           731: }

unix.superglobalmegacorp.com

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