Annotation of Net2/pcfs/pcfs_lookup.c, revision 1.1.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.