Annotation of Net2/pcfs/pcfs_vnops.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_vnops.c,v 1.3.2.1 1993/08/05 02:37:23 cgd Exp
                     19:  */
                     20: 
                     21: #include "param.h"
                     22: #include "systm.h"
                     23: #include "namei.h"
                     24: #include "resourcevar.h"       /* defines plimit structure in proc struct */
                     25: #include "kernel.h"
                     26: #include "file.h"              /* define FWRITE ... */
                     27: #include "stat.h"
                     28: #include "buf.h"
                     29: #include "proc.h"
                     30: #include "mount.h"
                     31: #include "vnode.h"
                     32: #include "specdev.h"           /* defines plimit structure in the proc struct */
                     33: #include "malloc.h"
                     34: 
                     35: #include "dir.h"               /* defines dirent structure             */
                     36: 
                     37: #include "bpb.h"
                     38: #include "direntry.h"
                     39: #include "denode.h"
                     40: #include "pcfsmount.h"
                     41: #include "fat.h"
                     42: /*
                     43:  *  Some general notes:
                     44:  *
                     45:  *  In the ufs filesystem the inodes, superblocks, and indirect
                     46:  *  blocks are read/written using the vnode for the filesystem.
                     47:  *  Blocks that represent the contents of a file are read/written
                     48:  *  using the vnode for the file (including directories when
                     49:  *  they are read/written as files).
                     50:  *  This presents problems for the dos filesystem because data
                     51:  *  that should be in an inode (if dos had them) resides in the
                     52:  *  directory itself.  Since we must update directory entries
                     53:  *  without the benefit of having the vnode for the directory
                     54:  *  we must use the vnode for the filesystem.  This means that
                     55:  *  when a directory is actually read/written (via read, write,
                     56:  *  or readdir, or seek) we must use the vnode for the filesystem
                     57:  *  instead of the vnode for the directory as would happen in ufs.
                     58:  *  This is to insure we retreive the correct block from the
                     59:  *  buffer cache since the hash value is based upon the vnode
                     60:  *  address and the desired block number.
                     61:  */
                     62: 
                     63: /*
                     64:  *  Create a regular file.
                     65:  *  On entry the directory to contain the file being
                     66:  *  created is locked.  We must release before we
                     67:  *  return.
                     68:  *  We must also free the pathname buffer pointed at
                     69:  *  by ndp->ni_pnbuf, always on error, or only if the
                     70:  *  SAVESTART bit in ni_nameiop is clear on success.
                     71:  */
                     72: int
                     73: pcfs_create(ndp, vap, p)
                     74:        struct nameidata *ndp;
                     75:        struct vattr *vap;
                     76:        struct proc *p;
                     77: {
                     78:        struct denode ndirent;
                     79:        struct direntry *ndirp = &ndirent.de_de;
                     80:        struct denode *dep;
                     81:        struct denode *pdep = VTODE(ndp->ni_dvp);
                     82:        int error;
                     83: #if defined(PCFSDEBUG)
                     84: printf("pcfs_create(ndp %08x, vap %08x, p %08x\n", ndp, vap, p);
                     85: #endif /* defined(PCFSDEBUG) */
                     86: 
                     87: /*
                     88:  *  Create a directory entry for the file, then call
                     89:  *  createde() to have it installed.
                     90:  *  NOTE: DOS files are always executable.  We use the
                     91:  *  absence of the owner write bit to make the file readonly.
                     92:  */
                     93:        bzero(&ndirent, sizeof(ndirent));
                     94:        unix2dostime(&time, (union dosdate *)&ndirp->deDate,
                     95:                (union dostime *)&ndirp->deTime);
                     96:        unix2dosfn((u_char *)ndp->ni_ptr, ndirp->deName, ndp->ni_namelen);
                     97:        ndirp->deAttributes = (vap->va_mode & VWRITE) ? 0 : ATTR_READONLY;
                     98:        ndirp->deStartCluster = 0;
                     99:        ndirp->deFileSize = 0;
                    100:        ndirent.de_pmp = pdep->de_pmp;
                    101:        ndirent.de_dev = pdep->de_dev;
                    102:        ndirent.de_devvp = pdep->de_devvp;
                    103:        if ((error = createde(&ndirent, ndp, &dep)) == 0) {
                    104:                ndp->ni_vp = DETOV(dep);
                    105:                if ((ndp->ni_nameiop & SAVESTART) == 0)
                    106:                        free(ndp->ni_pnbuf, M_NAMEI);
                    107:        } else {
                    108:                free(ndp->ni_pnbuf, M_NAMEI);
                    109:        }
                    110:        deput(pdep);            /* release parent dir   */
                    111:        return error;
                    112: }
                    113: 
                    114: int
                    115: pcfs_mknod(ndp, vap, cred, p)
                    116:        struct nameidata *ndp;
                    117:        struct vattr *vap;
                    118:        struct ucred *cred;
                    119:        struct proc *p;
                    120: {
                    121:        int error;
                    122: 
                    123:        switch (vap->va_type) {
                    124:        case VDIR:
                    125:                error = pcfs_mkdir(ndp, vap, p);
                    126:                break;
                    127: 
                    128: /*
                    129:  *  pcfs_create() sets ndp->ni_vp.
                    130:  */
                    131:        case VREG:
                    132:                error = pcfs_create(ndp, vap, p);
                    133:                break;
                    134: 
                    135:        default:
                    136:                error = EINVAL;
                    137:                break;
                    138:        }
                    139:        return error;
                    140: }
                    141: 
                    142: int
                    143: pcfs_open(vp, mode, cred, p)
                    144:        struct vnode *vp;
                    145:        int mode;
                    146:        struct ucred *cred;
                    147:        struct proc *p;
                    148: {
                    149:        return 0;
                    150: }
                    151: 
                    152: int
                    153: pcfs_close(vp, fflag, cred, p)
                    154:        struct vnode *vp;
                    155:        int fflag;
                    156:        struct ucred *cred;
                    157:        struct proc *p;
                    158: {
                    159:        struct denode *dep = VTODE(vp);
                    160: 
                    161:        if (vp->v_usecount > 1  &&  !(dep->de_flag & DELOCKED))
                    162:                DETIMES(dep, &time);
                    163:        return 0;
                    164: }
                    165: 
                    166: int
                    167: pcfs_access(vp, mode, cred, p)
                    168:        struct vnode *vp;
                    169:        int mode;
                    170:        struct ucred *cred;
                    171:        struct proc *p;
                    172: {
                    173:        int dosmode;
                    174:        struct denode *dep = VTODE(vp);
                    175: 
                    176: /*
                    177:  *  Root gets to do anything.  Even execute a file
                    178:  *  without the x-bit on?  But, for dos filesystems
                    179:  *  every file is executable.  I may regret this.
                    180:  */
                    181:        if (cred->cr_uid == 0)
                    182:                return 0;
                    183: 
                    184: /*
                    185:  *  mode is filled with a combination of VREAD, VWRITE,
                    186:  *  and/or VEXEC bits turned on.  In an octal number these
                    187:  *  are the Y in 0Y00.
                    188:  *
                    189:  *  Since the dos filesystem doesn't have the concept of
                    190:  *  file ownership we just give everybody read and execute
                    191:  *  access and write access if the readonly bit is off.
                    192:  */
                    193:        dosmode = VEXEC | VREAD |
                    194:                ((dep->de_Attributes & ATTR_READONLY) ? 0 : VWRITE);
                    195:        return ((dosmode & mode) != 0) ? 0 : EACCES;
                    196: }
                    197: 
                    198: int
                    199: pcfs_getattr(vp, vap, cred, p)
                    200:        struct vnode *vp;
                    201:        struct vattr *vap;
                    202:        struct ucred *cred;
                    203:        struct proc *p;
                    204: {
                    205:        u_int cn;
                    206:        struct denode *dep = VTODE(vp);
                    207: 
                    208:        DETIMES(dep, &time);
                    209:        vap->va_fsid = dep->de_dev;
                    210:        /* The following computation of the fileid must be the
                    211:         * same as that used in pcfs_readdir() to compute d_fileno.
                    212:         * If not, pwd doesn't work. */
                    213:        if (dep->de_Attributes & ATTR_DIRECTORY) {
                    214:                if ((cn = dep->de_StartCluster) == PCFSROOT)
                    215:                        cn = 1;
                    216:        } else {
                    217:                if ((cn = dep->de_dirclust) == PCFSROOT)
                    218:                        cn = 1;
                    219:                cn = (cn << 16) | (dep->de_diroffset & 0xffff);
                    220:        }
                    221:        vap->va_fileid = cn;
                    222:        vap->va_mode = (dep->de_Attributes & ATTR_READONLY) ? 0555 : 0777;
                    223:        if (dep->de_Attributes & ATTR_DIRECTORY)
                    224:                vap->va_mode |= S_IFDIR;
                    225:        vap->va_nlink = 1;
                    226:        vap->va_gid = 0;
                    227:        vap->va_uid = 0;
                    228:        vap->va_rdev = 0;
                    229:        vap->va_size = dep->de_FileSize;
                    230:        vap->va_size_rsv = 0;
                    231:        dos2unixtime((union dosdate *)&dep->de_Date,
                    232:                (union dostime *)&dep->de_Time, &vap->va_atime);
                    233:        vap->va_atime.tv_usec = 0;
                    234:        vap->va_mtime.tv_sec = vap->va_atime.tv_sec;
                    235:        vap->va_mtime.tv_usec = 0;
                    236:        vap->va_ctime.tv_sec = vap->va_atime.tv_sec;
                    237:        vap->va_ctime.tv_usec = 0;
                    238:        vap->va_flags = dep->de_flag;
                    239:        vap->va_gen = 0;
                    240:        vap->va_blocksize = dep->de_pmp->pm_bpcluster;
                    241:        vap->va_bytes = (dep->de_FileSize + dep->de_pmp->pm_crbomask) &
                    242:                ~(dep->de_pmp->pm_crbomask);
                    243:        vap->va_bytes_rsv = 0;
                    244:        vap->va_type = vp->v_type;
                    245:        return 0;
                    246: }
                    247: 
                    248: int
                    249: pcfs_setattr(vp, vap, cred, p)
                    250:        struct vnode *vp;
                    251:        struct vattr *vap;
                    252:        struct ucred *cred;
                    253:        struct proc *p;
                    254: {
                    255:        int error = 0;
                    256:        struct denode *dep = VTODE(vp);
                    257: 
                    258: #if defined(PCFSDEBUG)
                    259: printf("pcfs_setattr(): vp %08x, vap %08x, cred %08x, p %08x\n",
                    260:        vp, vap, cred, p);
                    261: #endif /* defined(PCFSDEBUG) */
                    262:        if ((vap->va_type != VNON)  ||
                    263:            (vap->va_nlink != VNOVAL)  ||
                    264:            (vap->va_fsid != VNOVAL)  ||
                    265:            (vap->va_fileid != VNOVAL)  ||
                    266:            (vap->va_blocksize != VNOVAL)  ||
                    267:            (vap->va_rdev != VNOVAL)  ||
                    268:            (vap->va_bytes != VNOVAL)  ||
                    269:            (vap->va_gen != VNOVAL)  ||
                    270: #if 0
                    271:            (vap->va_uid != (u_short)VNOVAL)  ||
                    272:            (vap->va_gid != (u_short)VNOVAL)  ||
                    273:            (vap->va_atime.tv_sec != VNOVAL)  ||
                    274: #endif
                    275:            0) {
                    276: #if defined(PCFSDEBUG)
                    277: printf("pcfs_setattr(): returning EINVAL\n");
                    278: printf("    va_type %d, va_nlink %x, va_fsid %x, va_fileid %x\n",
                    279:        vap->va_type, vap->va_nlink, vap->va_fsid, vap->va_fileid);
                    280: printf("    va_blocksize %x, va_rdev %x, va_bytes %x, va_gen %x\n",
                    281:        vap->va_blocksize, vap->va_rdev, vap->va_bytes, vap->va_gen);
                    282: printf("    va_uid %x, va_gid %x, va_atime.tv_sec %x\n",
                    283:        vap->va_uid, vap->va_gid, vap->va_atime.tv_sec);
                    284: #endif /* defined(PCFSDEBUG) */
                    285:                return EINVAL;
                    286:        }
                    287: 
                    288:        if (vap->va_size != VNOVAL) {
                    289:                if (vp->v_type == VDIR)
                    290:                        return EISDIR;
                    291:                if (error = detrunc(dep, vap->va_size, 0))
                    292:                        return error;
                    293:        }
                    294:        if (vap->va_mtime.tv_sec != VNOVAL) {
                    295:                dep->de_flag |= DEUPD;
                    296:                if (error = deupdat(dep, &vap->va_mtime, 1))
                    297:                        return error;
                    298:        }
                    299: 
                    300: /*
                    301:  *  DOS files only have the ability to have thier
                    302:  *  writability attribute set, so we use the owner
                    303:  *  write bit to set the readonly attribute.
                    304:  */
                    305:        if (vap->va_mode != (u_short)VNOVAL) {
                    306:                /* We ignore the read and execute bits */
                    307:                if (vap->va_mode & VWRITE)
                    308:                        dep->de_Attributes &= ~ATTR_READONLY;
                    309:                else
                    310:                        dep->de_Attributes |= ATTR_READONLY;
                    311:                dep->de_flag |= DEUPD;
                    312:        }
                    313: 
                    314:        if (vap->va_flags != VNOVAL) {
                    315:                if (error = suser(cred, &p->p_acflag))
                    316:                        return error;
                    317:                if (cred->cr_uid == 0)
                    318:                        dep->de_flag = vap->va_flags;
                    319:                else {
                    320:                        dep->de_flag &= 0xffff0000;
                    321:                        dep->de_flag |= (vap->va_flags & 0xffff);
                    322:                }
                    323:                dep->de_flag |= DEUPD;
                    324:        }
                    325:        return error;
                    326: }
                    327: 
                    328: 
                    329: int
                    330: pcfs_read(vp, uio, ioflag, cred)
                    331:        struct vnode *vp;
                    332:        struct uio *uio;
                    333:        int ioflag;
                    334:        struct ucred *cred;
                    335: {
                    336:        int error = 0;
                    337:        int diff;
                    338:        int isadir;
                    339:        long n;
                    340:        long on;
                    341:        daddr_t bn;
                    342:        daddr_t lbn;
                    343:        daddr_t rablock;
                    344:        struct buf *bp;
                    345:        struct denode *dep = VTODE(vp);
                    346:        struct pcfsmount *pmp = dep->de_pmp;
                    347: 
                    348: /*
                    349:  *  If they didn't ask for any data, then we
                    350:  *  are done.
                    351:  */
                    352:        if (uio->uio_resid == 0)
                    353:                return 0;
                    354:        if (uio->uio_offset < 0)
                    355:                return EINVAL;
                    356: 
                    357:        isadir = dep->de_Attributes & ATTR_DIRECTORY;
                    358:        do {
                    359:                lbn = uio->uio_offset >> pmp->pm_cnshift;
                    360:                on  = uio->uio_offset &  pmp->pm_crbomask;
                    361:                n = MIN((u_long)(pmp->pm_bpcluster - on), uio->uio_resid);
                    362:                diff = dep->de_FileSize - uio->uio_offset;
                    363:                if (diff <= 0)
                    364:                        return 0;
                    365:                /* convert cluster # to block # if a directory */
                    366:                if (isadir) {
                    367:                        error = pcbmap(dep, lbn, &lbn, 0);
                    368:                        if (error)
                    369:                                return error;
                    370:                }
                    371:                if (diff < n)
                    372:                        n = diff;
                    373: /*
                    374:  *  If we are operating on a directory file then be
                    375:  *  sure to do i/o with the vnode for the filesystem
                    376:  *  instead of the vnode for the directory.
                    377:  */
                    378:                if (isadir) {
                    379:                        error = bread(pmp->pm_devvp, lbn, pmp->pm_bpcluster,
                    380:                                NOCRED, &bp);
                    381:                } else {
                    382:                        rablock = lbn + 1;
                    383:                        if (vp->v_lastr + 1 == lbn  &&
                    384:                            rablock * pmp->pm_bpcluster < dep->de_FileSize) {
                    385:                                error = breada(vp, lbn, pmp->pm_bpcluster,
                    386:                                        rablock, pmp->pm_bpcluster, NOCRED, &bp);
                    387:                        } else {
                    388:                                error = bread(vp, lbn, pmp->pm_bpcluster, NOCRED,
                    389:                                        &bp);
                    390:                        }
                    391:                        vp->v_lastr = lbn;
                    392:                }
                    393:                if (error) {
                    394:                        brelse(bp);
                    395:                        return error;
                    396:                }
                    397:                n = MIN(n, pmp->pm_bpcluster - bp->b_resid);
                    398:                error = uiomove(bp->b_un.b_addr + on, (int)n, uio);
                    399: /*
                    400:  *  If we have read everything from this block or
                    401:  *  have read to end of file then we are done with
                    402:  *  this block.  Mark it to say the buffer can be reused if
                    403:  *  need be.
                    404:  */
                    405: #if 0
                    406:                if (n + on == pmp->pm_bpcluster  ||
                    407:                    uio->uio_offset == dep->de_FileSize)
                    408:                        bp->b_flags |= B_AGE;
                    409: #endif
                    410:                brelse(bp);
                    411:        } while (error == 0  &&  uio->uio_resid > 0  && n != 0);
                    412:        return error;
                    413: }
                    414: 
                    415: /*
                    416:  *  Write data to a file or directory.
                    417:  */
                    418: int
                    419: pcfs_write(vp, uio, ioflag, cred)
                    420:        struct vnode *vp;
                    421:        struct uio *uio;
                    422:        int ioflag;
                    423:        struct ucred *cred;
                    424: {
                    425:        int n;
                    426:        int croffset;
                    427:        int resid;
                    428:        int osize;
                    429:        int error;
                    430:        u_long cluster;
                    431:        u_long nextcluster;
                    432:        u_long lastcluster;
                    433:        daddr_t bn;
                    434:        struct buf *bp;
                    435:        struct proc *p = uio->uio_procp;
                    436:        struct denode *dep = VTODE(vp);
                    437:        struct pcfsmount *pmp = dep->de_pmp;
                    438: 
                    439: #if defined(PCFSDEBUG)
                    440: printf("pcfs_write(vp %08x, uio %08x, ioflag %08x, cred %08x\n",
                    441:        vp, uio, ioflag, cred);
                    442: printf("pcfs_write(): diroff %d, dirclust %d, startcluster %d\n",
                    443:        dep->de_diroffset, dep->de_dirclust, dep->de_StartCluster);
                    444: #endif /* defined(PCFSDEBUG) */
                    445: 
                    446:        switch (vp->v_type) {
                    447:        case VREG:
                    448:                if (ioflag & IO_APPEND)
                    449:                        uio->uio_offset = dep->de_FileSize;
                    450:                break;
                    451: 
                    452:        case VDIR:
                    453:                /* In pcfs, directory updates don't use pcfs_write */
                    454:                panic("pcfs_write(): directory update");
                    455:                break;
                    456: 
                    457:        default:
                    458:                panic("pcfs_write(): bad file type");
                    459:                break;
                    460:        }
                    461: 
                    462:        if (uio->uio_offset < 0)
                    463:                return EINVAL;
                    464:        if (uio->uio_resid == 0)
                    465:                return 0;
                    466: 
                    467: /*
                    468:  *  If they've exceeded their filesize limit, tell them about it.
                    469:  */
                    470:        if (vp->v_type == VREG  &&  p  &&
                    471:            ((uio->uio_offset + uio->uio_resid) >
                    472:             p->p_rlimit[RLIMIT_FSIZE].rlim_cur)) {
                    473:                psignal(p, SIGXFSZ);
                    474:                return EFBIG;
                    475:        }
                    476: 
                    477: /*
                    478:  *  If the offset we are starting the write at is beyond the
                    479:  *  end of the file, then they've done a seek.  Unix filesystems
                    480:  *  allow files with holes in them, DOS doesn't so we must
                    481:  *  fill the hole with zeroed blocks.
                    482:  */
                    483:        if (uio->uio_offset > dep->de_FileSize) {
                    484:                error = pcfsextend(vp, uio->uio_offset);
                    485:                if (error)
                    486:                        return error;
                    487:        }
                    488: 
                    489: /*
                    490:  *  Remember some values in case the write fails.
                    491:  */
                    492:        resid = uio->uio_resid;
                    493:        osize = dep->de_FileSize;
                    494: 
                    495:        do {
                    496:                bn = uio->uio_offset >> pmp->pm_cnshift;
                    497:                croffset = uio->uio_offset & pmp->pm_crbomask;
                    498:                n = MIN(uio->uio_resid, pmp->pm_bpcluster-croffset);
                    499: /*
                    500:  *  If we are appending to the file and we are on a
                    501:  *  cluster boundary, then allocate a new cluster
                    502:  *  and chain it onto the file.
                    503:  */
                    504:                if (uio->uio_offset == dep->de_FileSize  &&
                    505:                    (uio->uio_offset & pmp->pm_crbomask) == 0) {
                    506:                        if (error = extendfile(dep, &bp, 0))
                    507:                                break;
                    508:                } else {
                    509: /*
                    510:  *  The block we need to write into exists,
                    511:  *  so just read it in.
                    512:  */
                    513:                        if (n == pmp->pm_bpcluster)
                    514:                                /* We will overwrite the whole block, so 
                    515:                                 * dont read it*/
                    516:                                bp = getblk(vp, bn, pmp->pm_bpcluster);
                    517:                        else {
                    518:                                error = bread(vp, bn, pmp->pm_bpcluster, cred, &bp);
                    519:                                if (error) {
                    520:                                        brelse(bp);
                    521:                                        return error;
                    522:                                }
                    523:                        }
                    524:                }
                    525:                if (uio->uio_offset+n > dep->de_FileSize) {
                    526:                        dep->de_FileSize = uio->uio_offset + n;
                    527:                        vnode_pager_setsize(vp, dep->de_FileSize);
                    528:                }
                    529:                (void) vnode_pager_uncache(vp);
                    530: 
                    531: /*
                    532:  *  Copy the data from user space into the buf header.
                    533:  */
                    534:                error = uiomove(bp->b_un.b_addr+croffset, n, uio);
                    535: 
                    536: /*
                    537:  *  If they want this synchronous then write it and wait
                    538:  *  for it.  Otherwise, if on a cluster boundary write it
                    539:  *  asynchronously so we can move on to the next block
                    540:  *  without delay.  Otherwise do a delayed write because
                    541:  *  we may want to write somemore into the block later.
                    542:  */
                    543:                if (ioflag & IO_SYNC)
                    544:                        (void) bwrite(bp);
                    545:                else
                    546:                if (n + croffset == pmp->pm_bpcluster) {
                    547:                        bp->b_flags |= B_AGE;
                    548:                        bawrite(bp);
                    549:                } else
                    550:                        bdwrite(bp);
                    551:                dep->de_flag |= DEUPD;
                    552:        } while (error == 0  &&  uio->uio_resid > 0);
                    553: 
                    554: /*
                    555:  *  If the write failed and they want us to, truncate
                    556:  *  the file back to the size it was before the write
                    557:  *  was attempted.
                    558:  */
                    559:        if (error && (ioflag & IO_UNIT)) {
                    560:                detrunc(dep, osize, ioflag & IO_SYNC);
                    561:                uio->uio_offset -= resid - uio->uio_resid;
                    562:                uio->uio_resid   = resid;
                    563:        }
                    564:        if (!error && (ioflag & IO_UNIT))
                    565:                error = deupdat(dep, &time, 1);
                    566:        return error;
                    567: }
                    568: 
                    569: int
                    570: pcfs_ioctl(vp, com, data, fflag, cred, p)
                    571:        struct vnode *vp;
                    572:        int com;
                    573:        caddr_t data;
                    574:        struct ucred *cred;
                    575:        struct proc *p;
                    576: {
                    577:        return ENOTTY;
                    578: }
                    579: 
                    580: int
                    581: pcfs_select(vp, which, fflags, cred, p)
                    582:        struct vnode *vp;
                    583:        int which;
                    584:        int fflags;
                    585:        struct ucred *cred;
                    586:        struct proc *p;
                    587: {
                    588:        return 1;               /* DOS filesystems never block? */
                    589: }
                    590: 
                    591: int
                    592: pcfs_mmap(vp, fflags, cred, p)
                    593:        struct vnode *vp;
                    594:        int fflags;
                    595:        struct ucred *cred;
                    596:        struct proc *p;
                    597: {
                    598:        return EINVAL;
                    599: }
                    600: 
                    601: /*
                    602:  *  Flush the blocks of a file to disk.
                    603:  *
                    604:  *  This function is worthless for vnodes that represent
                    605:  *  directories.
                    606:  *  Maybe we could just do a sync if they try an fsync
                    607:  *  on a directory file.
                    608:  */
                    609: int
                    610: pcfs_fsync(vp, fflags, cred, waitfor, p)
                    611:        struct vnode *vp;
                    612:        int fflags;
                    613:        struct ucred *cred;
                    614:        int waitfor;
                    615:        struct proc *p;
                    616: {
                    617:        struct denode *dep = VTODE(vp);
                    618: 
                    619:        if (fflags & FWRITE)
                    620:                dep->de_flag |= DEUPD;
                    621: 
                    622:        vflushbuf(vp, waitfor == MNT_WAIT ? B_SYNC : 0);
                    623:        return deupdat(dep, &time, waitfor == MNT_WAIT);
                    624: }
                    625: 
                    626: /*
                    627:  *  Since the dos filesystem does not allow files with
                    628:  *  holes in them we must fill the file with zeroed
                    629:  *  blocks when a write past the end of file happens.
                    630:  */
                    631: int
                    632: pcfsextend(vp, newoff)
                    633:        struct vnode *vp;
                    634:        off_t newoff;
                    635: {
                    636:        int error = 0;
                    637:        off_t foff;
                    638:        struct buf *bp;
                    639:        struct denode *dep = VTODE(vp);
                    640:        struct pcfsmount *pmp = dep->de_pmp;
                    641: 
                    642: #ifdef DIAGNOSTIC
                    643:        if (dep->de_Attributes & ATTR_DIRECTORY)
                    644:                /* should not happen */
                    645:                return EISDIR;
                    646: #endif
                    647: 
                    648: /*
                    649:  *  Compute the offset of the first byte after the
                    650:  *  last block in the file.
                    651:  *  If writing beyond the end of file then fill the
                    652:  *  file with zeroed blocks up to the seek address.
                    653:  */
                    654:        foff = (dep->de_FileSize + (pmp->pm_bpcluster-1)) & ~pmp->pm_crbomask;
                    655:        if (newoff <= foff)
                    656:                return 0;
                    657: 
                    658: /*
                    659:  *  Allocate and chain together as many clusters as
                    660:  *  are needed to get to newoff.
                    661:  */
                    662:        while (foff < newoff) {
                    663:                if (error = extendfile(dep, &bp, 0))
                    664:                        return error;
                    665:                bdwrite(bp);
                    666:                foff += pmp->pm_bpcluster;
                    667:                dep->de_FileSize += pmp->pm_bpcluster;
                    668:        }
                    669:        dep->de_FileSize = newoff;
                    670:        dep->de_flag |= DEUPD;
                    671:        return deupdat(dep, &time);
                    672: }
                    673: 
                    674: /*
                    675:  * Seek on a file
                    676:  *
                    677:  * Nothing to do, so just return.
                    678:  */
                    679: int
                    680: pcfs_seek(vp, oldoff, newoff, cred)
                    681:        struct vnode *vp;
                    682:        off_t oldoff;
                    683:        off_t newoff;
                    684:        struct ucred *cred;
                    685: {
                    686:        return 0;
                    687: }
                    688: 
                    689: int
                    690: pcfs_remove(ndp, p)
                    691:        struct nameidata *ndp;
                    692:        struct proc *p;
                    693: {
                    694:        int error;
                    695:        struct denode *dep = VTODE(ndp->ni_vp);
                    696:        struct denode *ddep = VTODE(ndp->ni_dvp);
                    697: 
                    698:        error = removede(ndp);
                    699: #if defined(PCFSDEBUG)
                    700: printf("pcfs_remove(), dep %08x, v_usecount %d\n", dep, ndp->ni_vp->v_usecount);
                    701: #endif /* defined(PCFSDEBUG) */
                    702:        if (ddep == dep)
                    703:                vrele(DETOV(dep));
                    704:        else
                    705:                deput(dep);     /* causes pcfs_inactive() to be called via vrele() */
                    706:        deput(ddep);
                    707:        return error;
                    708: }
                    709: 
                    710: /*
                    711:  *  DOS filesystems don't know what links are.
                    712:  */
                    713: int
                    714: pcfs_link(vp, ndp, p)
                    715:        struct vnode *vp;
                    716:        struct nameidata *ndp;
                    717:        struct proc *p;
                    718: {
                    719:        return EINVAL;
                    720: }
                    721: 
                    722: /*
                    723:  *  Renames on files require moving the denode to
                    724:  *  a new hash queue since the denode's location is
                    725:  *  used to compute which hash queue to put the file in.
                    726:  *  Unless it is a rename in place.  For example "mv a b".
                    727:  *
                    728:  *  What follows is the basic algorithm:
                    729:  *
                    730:  *     if (file move) {
                    731:  *             if (dest file exists) {
                    732:  *                     remove dest file
                    733:  *             }
                    734:  *             if (dest and src in same directory) {
                    735:  *                     rewrite name in existing directory slot
                    736:  *             } else {
                    737:  *                     write new entry in dest directory
                    738:  *                     update offset and dirclust in denode
                    739:  *                     move denode to new hash chain
                    740:  *                     clear old directory entry
                    741:  *             }
                    742:  *     } else {  directory move
                    743:  *             if (dest directory exists) {
                    744:  *                     if (dest is not empty) {
                    745:  *                             return ENOTEMPTY
                    746:  *                     }
                    747:  *                     remove dest directory
                    748:  *             }
                    749:  *             if (dest and src in same directory) {
                    750:  *                     rewrite name in existing entry
                    751:  *             } else {
                    752:  *                     be sure dest is not a child of src directory
                    753:  *                     write entry in dest directory
                    754:  *                     update "." and ".." in moved directory
                    755:  *                     update offset and dirclust in denode
                    756:  *                     move denode to new hash chain
                    757:  *                     clear old directory entry for moved directory
                    758:  *             }
                    759:  *     }
                    760:  *
                    761:  *  On entry:
                    762:  *    source's parent directory is unlocked
                    763:  *    source file or directory is unlocked
                    764:  *    destination's parent directory is locked
                    765:  *    destination file or directory is locked if it exists
                    766:  *
                    767:  *  On exit:
                    768:  *    all denodes should be released
                    769:  *  Notes:
                    770:  *    I'm not sure how the memory containing the pathnames
                    771:  *    pointed at by the nameidata structures is freed, there
                    772:  *    may be some memory bleeding for each rename done.
                    773:  */
                    774: int
                    775: pcfs_rename(fndp, tndp, p)
                    776:        struct nameidata *fndp;
                    777:        struct nameidata *tndp;
                    778:        struct proc *p;
                    779: {
                    780:        u_char toname[11];
                    781:        int error;
                    782:        int newparent = 0;
                    783:        int sourceisadirectory = 0;
                    784:        u_long to_dirclust;
                    785:        u_long to_diroffset;
                    786:        u_long cn;
                    787:        daddr_t bn;
                    788:        struct denode *fddep;   /* from file's parent directory */
                    789:        struct denode *fdep;    /* from file or directory       */
                    790:        struct denode *tddep;   /* to file's parent directory   */
                    791:        struct denode *tdep;    /* to file or directory         */
                    792:        struct pcfsmount *pmp;
                    793:        struct direntry *dotdotp;
                    794:        struct direntry *ep;
                    795:        struct buf *bp;
                    796: 
                    797: #if defined(PCFSDEBUG)
                    798: printf("pcfs_rename(fndp %08x, tndp %08x, p %08x\n", fndp, tndp, p);
                    799: #endif /* defined(PCFSDEBUG) */
                    800:        fddep = VTODE(fndp->ni_dvp);
                    801:        fdep  = VTODE(fndp->ni_vp);
                    802:        tddep = VTODE(tndp->ni_dvp);
                    803:        tdep  = tndp->ni_vp ? VTODE(tndp->ni_vp) : NULL;
                    804:        pmp = fddep->de_pmp;
                    805: 
                    806: /*
                    807:  *  Convert the filename in tdnp into a dos filename.
                    808:  *  We copy this into the denode and directory entry
                    809:  *  for the destination file/directory.
                    810:  */
                    811:        unix2dosfn((u_char *)tndp->ni_ptr, toname, tndp->ni_namelen);
                    812: 
                    813: /*
                    814:  *  At this point this is the lock state of the denodes:
                    815:  *   fddep referenced
                    816:  *   fdep  referenced
                    817:  *   tddep locked
                    818:  *   tdep  locked if it exists
                    819:  */
                    820: 
                    821: /*
                    822:  *  Be sure we are not renaming ".", "..", or an alias of ".".
                    823:  *  This leads to a crippled directory tree.  It's pretty tough
                    824:  *  to do a "ls" or "pwd" with the "." directory entry missing,
                    825:  *  and "cd .." doesn't work if the ".." entry is missing.
                    826:  */
                    827:        if (fdep->de_Attributes & ATTR_DIRECTORY) {
                    828:                if ((fndp->ni_namelen == 1  &&  fndp->ni_ptr[0] == '.')  ||
                    829:                    fddep == fdep  || /* won't happen ? */
                    830:                    fndp->ni_isdotdot) {
                    831:                        VOP_ABORTOP(tndp);
                    832:                        vput(tndp->ni_dvp);
                    833:                        if (tndp->ni_vp)
                    834:                                vput(tndp->ni_vp);
                    835:                        VOP_ABORTOP(fndp);
                    836:                        vrele(fndp->ni_dvp);
                    837:                        vrele(fndp->ni_vp);
                    838:                        return EINVAL;
                    839:                }
                    840:                sourceisadirectory = 1;
                    841:        }
                    842: 
                    843: /*
                    844:  *  If we are renaming a directory, and the directory
                    845:  *  is being moved to another directory, then we must
                    846:  *  be sure the destination directory is not in the
                    847:  *  subtree of the source directory.  This could orphan
                    848:  *  everything under the source directory.
                    849:  *  doscheckpath() unlocks the destination's parent
                    850:  *  directory so we must look it up again to relock it.
                    851:  */
                    852:        if (fddep->de_StartCluster != tddep->de_StartCluster)
                    853:                newparent = 1;
                    854:        if (sourceisadirectory && newparent) {
                    855:                if (tdep) {
                    856:                        deput(tdep);
                    857:                        tdep = NULL;
                    858:                }
                    859:                /* doscheckpath() deput()'s tddep */
                    860:                error = doscheckpath(fdep, tddep, tndp->ni_cred);
                    861:                tddep = NULL;
                    862:                if (error)
                    863:                        goto bad;
                    864:                if ((tndp->ni_nameiop & SAVESTART) == 0)
                    865:                        panic("pcfs_rename(): lost to startdir");
                    866:                if (error = lookup(tndp, p))
                    867:                        goto bad;
                    868:                tddep = VTODE(tndp->ni_dvp);
                    869:                tdep  = tndp->ni_vp ? VTODE(tndp->ni_vp) : NULL;
                    870:        }
                    871: 
                    872: /*
                    873:  *  If the destination exists, then be sure its type (file or dir)
                    874:  *  matches that of the source.  And, if it is a directory make
                    875:  *  sure it is empty.  Then delete the destination.
                    876:  */
                    877:        if (tdep) {
                    878:                if (tdep->de_Attributes & ATTR_DIRECTORY) {
                    879:                        if (!sourceisadirectory) {
                    880:                                error = ENOTDIR;
                    881:                                goto bad;
                    882:                        }
                    883:                        if (!dosdirempty(tdep)) {
                    884:                                error = ENOTEMPTY;
                    885:                                goto bad;
                    886:                        }
                    887:                } else {        /* destination is file */
                    888:                        if (sourceisadirectory) {
                    889:                                error = EISDIR;
                    890:                                goto bad;
                    891:                        }
                    892:                }
                    893:                to_dirclust = tdep->de_dirclust;
                    894:                to_diroffset = tdep->de_diroffset;
                    895:                if (error = removede(tndp))
                    896:                        goto bad;
                    897:                deput(tdep);
                    898:                tdep = NULL;
                    899: 
                    900: /*
                    901:  *  Remember where the slot was for createde().
                    902:  */
                    903:                tndp->ni_pcfs.pcfs_count = 1;
                    904:                tndp->ni_pcfs.pcfs_cluster = to_dirclust;
                    905:                tndp->ni_pcfs.pcfs_offset  = to_diroffset;
                    906:        }
                    907: 
                    908: /*
                    909:  *  If the source and destination are in the same
                    910:  *  directory then just read in the directory entry,
                    911:  *  change the name in the directory entry and
                    912:  *  write it back to disk.
                    913:  */
                    914:        if (newparent == 0) {
                    915:                /* tddep and fddep point to the same denode here */
                    916:                DELOCK(fdep);           /* tddep is already locked */
                    917:                if (error = readde(fdep, &bp, &ep)) {
                    918:                        DEUNLOCK(fdep);
                    919:                        goto bad;
                    920:                }
                    921:                bcopy(toname, ep->deName, 11);
                    922:                if (error = bwrite(bp)) {
                    923:                        DEUNLOCK(fdep);
                    924:                        goto bad;
                    925:                }
                    926:                bcopy(toname, fdep->de_Name, 11);       /* update denode */
                    927: /*
                    928:  *  fdep locked
                    929:  *  fddep and tddep point to the same denode which is locked
                    930:  *  tdep is unlocked and unreferenced
                    931:  */
                    932:        } else {
                    933:                u_long dirsize;
                    934: /*
                    935:  *  If the source and destination are in different
                    936:  *  directories, then mark the entry in the source
                    937:  *  directory as deleted and write a new entry in the
                    938:  *  destination directory.  Then move the denode to
                    939:  *  the correct hash chain for its new location in
                    940:  *  the filesystem.  And, if we moved a directory,
                    941:  *  then update its .. entry to point to the new
                    942:  *  parent directory.
                    943:  *  If we moved a directory will also insure that
                    944:  *  the directory entry on disk has a filesize of
                    945:  *  zero.
                    946:  */
                    947:                DELOCK(fdep);
                    948:                bcopy(toname, fdep->de_Name, 11);       /* update denode */
                    949:                if (fdep->de_Attributes & ATTR_DIRECTORY) {
                    950:                        dirsize = fdep->de_FileSize;
                    951:                        fdep->de_FileSize = 0;
                    952:                }
                    953:                error = createde(fdep, tndp, (struct denode **)0);
                    954:                if (fdep->de_Attributes & ATTR_DIRECTORY) {
                    955:                        fdep->de_FileSize = dirsize;
                    956:                }
                    957:                if (error) {
                    958:                        /* should put back filename */
                    959:                        DEUNLOCK(fdep);
                    960:                        goto bad;
                    961:                }
                    962:                DELOCK(fddep);
                    963:                error = markdeleted (pmp,
                    964:                                     fndp->ni_pcfs.pcfs_cluster,
                    965:                                     fndp->ni_pcfs.pcfs_offset);
                    966:                if (error) {
                    967:                        DEUNLOCK(fdep);
                    968:                        DEUNLOCK(fddep);
                    969:                        goto bad;
                    970:                }
                    971:                if (!(fdep->de_Attributes & ATTR_DIRECTORY)) {
                    972:                        fdep->de_dirclust = tndp->ni_pcfs.pcfs_cluster;
                    973:                        fdep->de_diroffset = tndp->ni_pcfs.pcfs_offset;
                    974:                        reinsert(fdep);
                    975:                }
                    976:                DEUNLOCK(fddep);
                    977:        }
                    978:        /* fdep is still locked here */
                    979: 
                    980: /*
                    981:  *  If we moved a directory to a new parent directory,
                    982:  *  then we must fixup the ".." entry in the moved
                    983:  *  directory.
                    984:  */
                    985:        if (sourceisadirectory  &&  newparent) {
                    986:                cn = fdep->de_StartCluster;
                    987:                if (cn == PCFSROOT)
                    988:                        /* this should never happen */
                    989:                        panic("pcfs_rename(): updating .. in root directory?\n");
                    990:                error = readep(pmp, cn, 1, &bp, &dotdotp);
                    991:                if (error) {
                    992:                        /* should really panic here, fs is corrupt */
                    993:                        DEUNLOCK(fdep);
                    994:                        goto bad;
                    995:                }
                    996:                dotdotp->deStartCluster = tddep->de_StartCluster;
                    997:                error = bwrite(bp);
                    998:                DEUNLOCK(fdep);
                    999:                if (error)
                   1000:                        /* should really panic here, fs is corrupt */
                   1001:                        goto bad;
                   1002:        }
                   1003:        else
                   1004:                DEUNLOCK(fdep);
                   1005: bad:;
                   1006:        vrele(DETOV(fdep));
                   1007:        vrele(DETOV(fddep));
                   1008:        if (tdep)
                   1009:                vput(DETOV(tdep));
                   1010:        if (tddep)
                   1011:                vput(DETOV(tddep));
                   1012:        return error;
                   1013: }
                   1014: 
                   1015: struct {
                   1016:        struct direntry dot;
                   1017:        struct direntry dotdot;
                   1018: } dosdirtemplate = {
                   1019:        ".       ", "   ",              /* the . entry */
                   1020:        ATTR_DIRECTORY,                 /* file attribute */
                   1021:        0,0,0,0,0,0,0,0,0,0,            /* resevered */
                   1022:        1234, 1234,                     /* time and date */
                   1023:        0,                              /* startcluster */
                   1024:        0,                              /* filesize */
                   1025:        "..      ", "   ",              /* the .. entry */
                   1026:        ATTR_DIRECTORY,                 /* file attribute */
                   1027:        0,0,0,0,0,0,0,0,0,0,            /* resevered */
                   1028:        1234, 1234,                     /* time and date */
                   1029:        0,                              /* startcluster */
                   1030:        0,                              /* filesize */
                   1031: };
                   1032: 
                   1033: int
                   1034: pcfs_mkdir(ndp, vap, p)
                   1035:        struct nameidata *ndp;
                   1036:        struct vattr *vap;
                   1037:        struct proc *p;
                   1038: {
                   1039:        int bn;
                   1040:        int error;
                   1041:        u_long newcluster;
                   1042:        struct denode *pdep;
                   1043:        struct denode *ndep;
                   1044:        struct vnode *pvp;
                   1045:        struct direntry *denp;
                   1046:        struct denode ndirent;
                   1047:        struct pcfsmount *pmp;
                   1048:        struct buf *bp;
                   1049: 
                   1050:        pvp = ndp->ni_dvp;
                   1051:        pdep = VTODE(pvp);
                   1052: 
                   1053: /*
                   1054:  *  If this is the root directory and there is no space left
                   1055:  *  we can't do anything.  This is because the root directory
                   1056:  *  can not change size.
                   1057:  */
                   1058:        if (pdep->de_StartCluster == PCFSROOT  &&  ndp->ni_pcfs.pcfs_count == 0) {
                   1059:                free(ndp->ni_pnbuf, M_NAMEI);
                   1060:                deput(pdep);
                   1061:                return ENOSPC;
                   1062:        }
                   1063: 
                   1064:        pmp = pdep->de_pmp;
                   1065: 
                   1066: /*
                   1067:  *  Allocate a cluster to hold the about to be created directory.
                   1068:  */
                   1069:        if (error = clusteralloc(pmp, &newcluster, CLUST_EOFE)) {
                   1070:                free(ndp->ni_pnbuf, M_NAMEI);
                   1071:                deput(pdep);
                   1072:                return error;
                   1073:        }
                   1074: 
                   1075: /*
                   1076:  *  Now fill the cluster with the "." and ".." entries.
                   1077:  *  And write the cluster to disk.  This way it is there
                   1078:  *  for the parent directory to be pointing at if there
                   1079:  *  were a crash.
                   1080:  */
                   1081:        bn = cntobn(pmp, newcluster);
                   1082:        bp = getblk(pmp->pm_devvp, bn, pmp->pm_bpcluster); /* always succeeds */
                   1083:        clrbuf(bp);
                   1084:        bcopy(&dosdirtemplate, bp->b_un.b_addr, sizeof dosdirtemplate);
                   1085:        denp = (struct direntry *)bp->b_un.b_addr;
                   1086:        denp->deStartCluster = newcluster;
                   1087:        unix2dostime(&time, (union dosdate *)&denp->deDate,
                   1088:                (union dostime *)&denp->deTime);
                   1089:        denp++;
                   1090:        denp->deStartCluster = pdep->de_StartCluster;
                   1091:        unix2dostime(&time, (union dosdate *)&denp->deDate,
                   1092:                (union dostime *)&denp->deTime);
                   1093:        if (error = bwrite(bp)) {
                   1094:                clusterfree(pmp, newcluster, NULL);
                   1095:                free(ndp->ni_pnbuf, M_NAMEI);
                   1096:                deput(pdep);
                   1097:                return error;
                   1098:        }
                   1099: 
                   1100: /*
                   1101:  *  Now build up a directory entry pointing to the newly
                   1102:  *  allocated cluster.  This will be written to an empty
                   1103:  *  slot in the parent directory.
                   1104:  */
                   1105:        ndep = &ndirent;
                   1106:        bzero(ndep, sizeof(*ndep));
                   1107:        unix2dosfn((u_char *)ndp->ni_ptr, ndep->de_Name, ndp->ni_namelen);
                   1108:        unix2dostime(&time, (union dosdate *)&ndep->de_Date,
                   1109:                (union dostime *)&ndep->de_Time);
                   1110:        ndep->de_StartCluster = newcluster;
                   1111:        ndep->de_Attributes = ATTR_DIRECTORY;
                   1112:        ndep->de_pmp = pmp;     /* createde() needs this        */
                   1113: 
                   1114:        error = createde(ndep, ndp, &ndep);
                   1115:        if (error) {
                   1116:                clusterfree(pmp, newcluster, NULL);
                   1117:        } else {
                   1118:                ndp->ni_vp = DETOV(ndep);
                   1119:        }
                   1120:        free(ndp->ni_pnbuf, M_NAMEI);
                   1121: #if defined(PCFSDEBUG)
                   1122: printf("pcfs_mkdir(): deput(%08x), vnode %08x\n", pdep, DETOV(pdep));
                   1123: #endif /* defined(PCFSDEBUG) */
                   1124:        deput(pdep);
                   1125:        return error;
                   1126: }
                   1127: 
                   1128: int
                   1129: pcfs_rmdir(ndp, p)
                   1130:        struct nameidata *ndp;
                   1131:        struct proc *p;
                   1132: {
                   1133:        struct denode *ddep;
                   1134:        struct denode *dep;
                   1135:        int error = 0;
                   1136: 
                   1137:        ddep = VTODE(ndp->ni_dvp);      /* parent dir of dir to delete  */
                   1138:        dep  = VTODE(ndp->ni_vp);       /* directory to delete  */
                   1139: 
                   1140: /*
                   1141:  *  Don't let "rmdir ." go thru.
                   1142:  */
                   1143:        if (ddep == dep) {
                   1144:                vrele(DETOV(dep));
                   1145:                deput(dep);
                   1146:                return EINVAL;
                   1147:        }
                   1148: 
                   1149: /*
                   1150:  *  Be sure the directory being deleted is empty.
                   1151:  */
                   1152:        if (dosdirempty(dep) == 0) {
                   1153:                error = ENOTEMPTY;
                   1154:                goto out;
                   1155:        }
                   1156: 
                   1157: /*
                   1158:  *  Delete the entry from the directory.  For dos filesystems
                   1159:  *  this gets rid of the directory entry on disk, the in memory
                   1160:  *  copy still exists but the de_refcnt is <= 0.  This prevents
                   1161:  *  it from being found by deget().  When the deput() on dep is
                   1162:  *  done we give up access and eventually pcfs_reclaim() will
                   1163:  *  be called which will remove it from the denode cache.
                   1164:  */
                   1165:        if (error = removede(ndp))
                   1166:                goto out;
                   1167: 
                   1168: /*
                   1169:  *  This is where we decrement the link count in the parent
                   1170:  *  directory.  Since dos filesystems don't do this we just
                   1171:  *  purge the name cache and let go of the parent directory
                   1172:  *  denode.
                   1173:  */
                   1174:        cache_purge(DETOV(ddep));
                   1175:        deput(ddep);
                   1176:        ndp->ni_dvp = NULL;     /* getting rid of parent dir pointer? */
                   1177: 
                   1178: /*
                   1179:  *  Truncate the directory that is being deleted.
                   1180:  */
                   1181:        error = detrunc(dep, (u_long)0, IO_SYNC);
                   1182:        cache_purge(DETOV(dep));
                   1183: 
                   1184: out:;
                   1185:        if (ndp->ni_dvp)
                   1186:                deput(ddep);
                   1187:        deput(dep);
                   1188:        return error;
                   1189: }
                   1190: 
                   1191: /*
                   1192:  *  DOS filesystems don't know what symlinks are.
                   1193:  */
                   1194: int
                   1195: pcfs_symlink(ndp, vap, target, p)
                   1196:        struct nameidata *ndp;
                   1197:        struct vattr *vap;
                   1198:        char *target;
                   1199:        struct proc *p;
                   1200: {
                   1201:        return EINVAL;
                   1202: }
                   1203: 
                   1204: /*
                   1205:  *  Dummy dirents to simulate the "." and ".." entries
                   1206:  *  of the root directory in a dos filesystem.  Dos doesn't
                   1207:  *  provide these.
                   1208:  *  Note that each entry must be the same size as a dos
                   1209:  *  directory entry (32 bytes).
                   1210:  */
                   1211: struct dos_dirent {
                   1212:        u_long d_fileno;
                   1213:        u_short d_reclen;
                   1214:        u_short d_namlen;
                   1215:        u_char d_name[24];
                   1216: } rootdots[2] = {
                   1217:     {
                   1218:        1,                              /* d_fileno                     */
                   1219:        sizeof(struct direntry),        /* d_reclen                     */
                   1220:        1,                              /* d_namlen                     */
                   1221:        "."                             /* d_name                       */
                   1222:     },
                   1223:     {
                   1224:        1,                              /* d_fileno                     */
                   1225:        sizeof(struct direntry),        /* d_reclen                     */
                   1226:        2,                              /* d_namlen                     */
                   1227:        ".."                            /* d_name                       */
                   1228:     }
                   1229: };
                   1230: 
                   1231: int
                   1232: pcfs_readdir(vp, uio, cred, eofflagp)
                   1233:        struct vnode *vp;
                   1234:        struct uio *uio;
                   1235:        struct ucred *cred;
                   1236:        int *eofflagp;
                   1237: {
                   1238:        int error = 0;
                   1239:        int diff;
                   1240:        char pushout;
                   1241:        long n;
                   1242:        long on;
                   1243:        long lost;
                   1244:        long count;
                   1245:        u_long cn;
                   1246:        u_long fileno;
                   1247:        long bias = 0;
                   1248:        daddr_t bn;
                   1249:        daddr_t lbn;
                   1250:        struct buf *bp;
                   1251:        struct denode *dep = VTODE(vp);
                   1252:        struct pcfsmount *pmp = dep->de_pmp;
                   1253:        struct direntry *dentp;
                   1254:        struct dirent *prev;
                   1255:        struct dirent *crnt;
                   1256:        u_char dirbuf[512];     /* holds converted dos directories */
                   1257: int i=0;
                   1258: 
                   1259: #if defined(PCFSDEBUG)
                   1260: printf("pcfs_readdir(): vp %08x, uio %08x, cred %08x, eofflagp %08x\n",
                   1261:        vp, uio, cred, eofflagp);
                   1262: #endif /* defined(PCFSDEBUG) */
                   1263: 
                   1264: /*
                   1265:  *  pcfs_readdir() won't operate properly on regular files
                   1266:  *  since it does i/o only with the the filesystem vnode,
                   1267:  *  and hence can retrieve the wrong block from the buffer
                   1268:  *  cache for a plain file.  So, fail attempts to readdir()
                   1269:  *  on a plain file.
                   1270:  */
                   1271:        if ((dep->de_Attributes & ATTR_DIRECTORY) == 0)
                   1272:                return ENOTDIR;
                   1273: 
                   1274: /*
                   1275:  *  If the user buffer is smaller than the size of one dos
                   1276:  *  directory entry or the file offset is not a multiple of
                   1277:  *  the size of a directory entry, then we fail the read.
                   1278:  */
                   1279:        count = uio->uio_resid & ~(sizeof(struct direntry)-1);
                   1280:        lost  = uio->uio_resid - count;
                   1281:        if (count < sizeof(struct direntry)  ||
                   1282:            (uio->uio_offset & (sizeof(struct direntry)-1)))
                   1283:                return EINVAL;
                   1284:        uio->uio_resid = count;
                   1285:        uio->uio_iov->iov_len = count;
                   1286: 
                   1287: /*
                   1288:  *  If they are reading from the root directory then,
                   1289:  *  we simulate the . and .. entries since these don't
                   1290:  *  exist in the root directory.  We also set the offset
                   1291:  *  bias to make up for having to simulate these entries.
                   1292:  *  By this I mean that at file offset 64 we read the first entry
                   1293:  *  in the root directory that lives on disk.
                   1294:  */
                   1295:        if (dep->de_StartCluster == PCFSROOT) {
                   1296: /*printf("pcfs_readdir(): going after . or .. in root dir, offset %d\n",
                   1297:        uio->uio_offset);*/
                   1298:                bias = 2*sizeof(struct direntry);
                   1299:                if (uio->uio_offset < 2*sizeof(struct direntry)) {
                   1300:                        error = uiomove((char *)rootdots + uio->uio_offset,
                   1301:                                sizeof rootdots - uio->uio_offset, uio);
                   1302:                        if (error)
                   1303:                                goto out;
                   1304:                }
                   1305:        }
                   1306:        do {
                   1307:                lbn = (uio->uio_offset-bias) >> pmp->pm_cnshift;
                   1308:                on  = (uio->uio_offset-bias) &  pmp->pm_crbomask;
                   1309:                n = MIN((u_long)(pmp->pm_bpcluster - on), uio->uio_resid);
                   1310:                diff = dep->de_FileSize - (uio->uio_offset - bias);
                   1311:                if (diff <= 0)
                   1312:                        return 0;
                   1313:                if (diff < n)
                   1314:                        n = diff;
                   1315:                error = pcbmap(dep, lbn, &bn, &cn);
                   1316:                if (error)
                   1317:                        break;
                   1318:                error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, NOCRED, &bp);
                   1319:                if (error) {
                   1320:                        brelse(bp);
                   1321:                        return error;
                   1322:                }
                   1323:                n = MIN(n, pmp->pm_bpcluster - bp->b_resid);
                   1324: 
                   1325: /*
                   1326:  *  code to convert from dos directory entries to ufs directory entries
                   1327:  */
                   1328:                pushout = 0;
                   1329:                dentp = (struct direntry *)(bp->b_un.b_addr + on);
                   1330:                prev = 0;
                   1331:                crnt = (struct dirent *)dirbuf;
                   1332:                while ((char *)dentp < bp->b_un.b_addr + on + n) {
                   1333: /*printf("rd: dentp %08x prev %08x crnt %08x deName %02x attr %02x\n",
                   1334:        dentp, prev, crnt, dentp->deName[0], dentp->deAttributes);*/
                   1335: /*
                   1336:  *  If we have an empty entry or a slot from a deleted
                   1337:  *  file, or a volume label entry just concatenate its
                   1338:  *  space onto the end of the previous entry or,
                   1339:  *  manufacture an empty entry if there is no previous
                   1340:  *  entry.
                   1341:  */
                   1342:                        if (dentp->deName[0] == SLOT_EMPTY  ||
                   1343:                            dentp->deName[0] == SLOT_DELETED  ||
                   1344:                            (dentp->deAttributes & ATTR_VOLUME)) {
                   1345:                                if (prev) {
                   1346:                                        prev->d_reclen += sizeof(struct direntry);
                   1347:                                } else {
                   1348:                                        prev = crnt;
                   1349:                                        prev->d_fileno = 0;
                   1350:                                        prev->d_reclen = sizeof(struct direntry);
                   1351:                                        prev->d_namlen = 0;
                   1352:                                        prev->d_name[0] = 0;
                   1353:                                }
                   1354:                        } else {
                   1355:                                /* this computation of d_fileno must match
                   1356:                                 * the computation of va_fileid in pcfs_getattr */
                   1357:                                if (dentp->deAttributes & ATTR_DIRECTORY) {
                   1358:                                        /* if this is the root directory */
                   1359:                                        if ((fileno = dentp->deStartCluster) == PCFSROOT)
                   1360:                                                fileno = 1;
                   1361:                                } else {
                   1362:                                        /* if the file's dirent lives in root dir */
                   1363:                                        if ((fileno = cn) == PCFSROOT)
                   1364:                                                fileno = 1;
                   1365:                                        fileno = (fileno << 16) |
                   1366:                                                ((dentp - (struct direntry *)bp->b_un.b_addr) & 0xffff);
                   1367:                                }
                   1368:                                crnt->d_fileno = fileno;
                   1369:                                crnt->d_reclen = sizeof(struct direntry);
                   1370:                                crnt->d_namlen = dos2unixfn(dentp->deName,
                   1371:                                        (u_char *)crnt->d_name);
                   1372: /*printf("readdir: file %s, fileno %08x, attr %02x, start %08x\n",
                   1373:        crnt->d_name, crnt->d_fileno, dentp->deAttributes, dentp->deStartCluster);*/
                   1374:                                prev = crnt;
                   1375:                        }
                   1376:                        crnt = (struct dirent *)((char *)crnt + sizeof(struct direntry));
                   1377:                        pushout = 1;
                   1378: 
                   1379: /*
                   1380:  *  If our intermediate buffer is full then copy
                   1381:  *  its contents to user space.
                   1382:  */
                   1383:                        if ((u_char *)crnt >= &dirbuf[sizeof dirbuf]) {
                   1384:                                pushout = 0;
                   1385:                                error = uiomove(dirbuf, sizeof(dirbuf), uio);
                   1386:                                if (error)
                   1387:                                        break;
                   1388:                                prev = 0;
                   1389:                                crnt = (struct dirent *)dirbuf;
                   1390:                        }
                   1391:                        dentp++;
                   1392:                }
                   1393:                if (pushout) {
                   1394:                        pushout = 0;
                   1395:                        error = uiomove(dirbuf, (char *)crnt - (char *)dirbuf,
                   1396:                                uio);
                   1397:                }
                   1398: 
                   1399: /*
                   1400:  *  If we have read everything from this block or
                   1401:  *  have read to end of file then we are done with
                   1402:  *  this block.  Mark it to say the buffer can be reused if
                   1403:  *  need be.
                   1404:  */
                   1405: #if 0
                   1406:                if (n + on == pmp->pm_bpcluster  ||
                   1407:                    (uio->uio_offset-bias) == dep->de_FileSize)
                   1408:                        bp->b_flags |= B_AGE;
                   1409: #endif
                   1410:                brelse(bp);
                   1411:        } while (error == 0  &&  uio->uio_resid > 0  && n != 0);
                   1412: out:;
                   1413:        uio->uio_resid += lost;
                   1414: 
                   1415: /*
                   1416:  *  I don't know why we bother setting this eofflag, getdirentries()
                   1417:  *  in vfs_syscalls.c doesn't bother to look at it when we return.
                   1418:  *     But nfsrv_readdir does. 
                   1419:  */
                   1420:        if (dep->de_FileSize - uio->uio_offset - bias <= 0)
                   1421:                *eofflagp = 1;
                   1422:        else
                   1423:                *eofflagp = 0;
                   1424:        return error;
                   1425: }
                   1426: 
                   1427: /*
                   1428:  *  DOS filesystems don't know what symlinks are.
                   1429:  */
                   1430: int
                   1431: pcfs_readlink(vp, uio, cred)
                   1432:        struct vnode *vp;
                   1433:        struct uio *uio;
                   1434:        struct ucred *cred;
                   1435: {
                   1436:        return EINVAL;
                   1437: }
                   1438: 
                   1439: int
                   1440: pcfs_abortop(ndp)
                   1441:        struct nameidata *ndp;
                   1442: {
                   1443:        if ((ndp->ni_nameiop & (HASBUF | SAVESTART)) == HASBUF)
                   1444:                FREE(ndp->ni_pnbuf, M_NAMEI);
                   1445:        return 0;
                   1446: }
                   1447: 
                   1448: int
                   1449: pcfs_lock(vp)
                   1450:        struct vnode *vp;
                   1451: {
                   1452:        struct denode *dep = VTODE(vp);
                   1453: 
                   1454:        DELOCK(dep);
                   1455:        return 0;
                   1456: }
                   1457: 
                   1458: int
                   1459: pcfs_unlock(vp)
                   1460:        struct vnode *vp;
                   1461: {
                   1462:        struct denode *dep = VTODE(vp);
                   1463: 
                   1464:        if (!(dep->de_flag & DELOCKED))
                   1465:                panic("pcfs_unlock: denode not locked");
                   1466:        DEUNLOCK(dep);
                   1467:        return 0;
                   1468: }
                   1469: 
                   1470: int
                   1471: pcfs_islocked(vp)
                   1472:        struct vnode *vp;
                   1473: {
                   1474:        return VTODE(vp)->de_flag & DELOCKED ? 1 : 0;
                   1475: }
                   1476: 
                   1477: /*
                   1478:  *  vp - address of vnode file the file
                   1479:  *  bn - which cluster we are interested in mapping to
                   1480:  *    a filesystem block number.
                   1481:  *  vpp - returns the vnode for the block special file
                   1482:  *    holding the filesystem containing the file of interest
                   1483:  *  bnp - address of where to return the filesystem
                   1484:  *    relative block number
                   1485:  */
                   1486: int
                   1487: pcfs_bmap(vp, bn, vpp, bnp)
                   1488:        struct vnode *vp;
                   1489:        daddr_t bn;
                   1490:        struct vnode **vpp;
                   1491:        daddr_t *bnp;
                   1492: {
                   1493:        struct denode *dep = VTODE(vp);
                   1494:        struct pcfsmount *pmp = dep->de_pmp;
                   1495: 
                   1496:        if (vpp != NULL)
                   1497:                *vpp = dep->de_devvp;
                   1498:        if (bnp == NULL)
                   1499:                return 0;
                   1500:        return pcbmap(dep, bn << (pmp->pm_cnshift - pmp->pm_bnshift), bnp, 0);
                   1501: }
                   1502: 
                   1503: int
                   1504: pcfs_strategy(bp)
                   1505:        struct buf *bp;
                   1506: {
                   1507:        struct denode *dep = VTODE(bp->b_vp);
                   1508:        struct pcfsmount *pmp = dep->de_pmp;
                   1509:        struct vnode *vp;
                   1510:        int error;
                   1511: 
                   1512:        if (bp->b_vp->v_type == VBLK  ||  bp->b_vp->v_type == VCHR)
                   1513:                panic("pcfs_strategy: spec");
                   1514: /*
                   1515:  *  If we don't already know the filesystem relative
                   1516:  *  block number then get it using pcbmap().  If pcbmap()
                   1517:  *  returns the block number as -1 then we've got a hole
                   1518:  *  in the file.  DOS filesystems don't allow files with
                   1519:  *  holes, so we shouldn't ever see this.
                   1520:  */
                   1521:        if (bp->b_blkno == bp->b_lblkno) {
                   1522:                if (error = pcbmap(dep, bp->b_lblkno, &bp->b_blkno, 0))
                   1523:                        return error;
                   1524:                if ((long)bp->b_blkno == -1)
                   1525:                        clrbuf(bp);
                   1526:        }
                   1527:        if ((long)bp->b_blkno == -1) {
                   1528:                biodone(bp);
                   1529:                return 0;
                   1530:        }
                   1531: #ifdef DIAGNOSTIC
                   1532: #endif /* defined(DIAGNOSTIC) */
                   1533: /*
                   1534:  *  Read/write the block from/to the disk that contains the desired
                   1535:  *  file block.
                   1536:  */
                   1537:        vp = dep->de_devvp;
                   1538:        bp->b_dev = vp->v_rdev;
                   1539:        (*(vp->v_op->vop_strategy))(bp);
                   1540:        return 0;
                   1541: }
                   1542: 
                   1543: int
                   1544: pcfs_print(vp)
                   1545:        struct vnode *vp;
                   1546: {
                   1547:        struct denode *dep = VTODE(vp);
                   1548: 
                   1549:        printf("tag VT_MSDOSFS, startcluster %d, dircluster %d, diroffset %d ",
                   1550:                dep->de_StartCluster, dep->de_dirclust, dep->de_diroffset);
                   1551:        printf(" dev %d, %d, %s\n",
                   1552:                major(dep->de_dev), minor(dep->de_dev),
                   1553:                dep->de_flag & DELOCKED ? "(LOCKED)" : "");
                   1554:        if (dep->de_spare0) {
                   1555:                printf("    owner pid %d", dep->de_spare0);
                   1556:                if (dep->de_spare1)
                   1557:                        printf(" waiting pid %d", dep->de_spare1);
                   1558:                printf("\n");
                   1559:        }
                   1560: }
                   1561: 
                   1562: int
                   1563: pcfs_advlock(vp, id, op, fl, flags)
                   1564:        struct vnode *vp;
                   1565:        caddr_t id;
                   1566:        int op;
                   1567:        struct flock *fl;
                   1568:        int flags;
                   1569: {
                   1570:        return EINVAL;          /* we don't do locking yet              */
                   1571: }
                   1572: 
                   1573: struct vnodeops pcfs_vnodeops = {
                   1574:        pcfs_lookup,
                   1575:        pcfs_create,
                   1576:        pcfs_mknod,
                   1577:        pcfs_open,
                   1578:        pcfs_close,
                   1579:        pcfs_access,
                   1580:        pcfs_getattr,
                   1581:        pcfs_setattr,
                   1582:        pcfs_read,
                   1583:        pcfs_write,
                   1584:        pcfs_ioctl,
                   1585:        pcfs_select,
                   1586:        pcfs_mmap,
                   1587:        pcfs_fsync,
                   1588:        pcfs_seek,
                   1589:        pcfs_remove,
                   1590:        pcfs_link,
                   1591:        pcfs_rename,
                   1592:        pcfs_mkdir,
                   1593:        pcfs_rmdir,
                   1594:        pcfs_symlink,
                   1595:        pcfs_readdir,
                   1596:        pcfs_readlink,
                   1597:        pcfs_abortop,
                   1598:        pcfs_inactive,
                   1599:        pcfs_reclaim,
                   1600:        pcfs_lock,
                   1601:        pcfs_unlock,
                   1602:        pcfs_bmap,
                   1603:        pcfs_strategy,
                   1604:        pcfs_print,
                   1605:        pcfs_islocked,
                   1606:        pcfs_advlock,
                   1607: };

unix.superglobalmegacorp.com

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