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

1.1     ! root        1: /*
        !             2:  *  Written by Paul Popelka ([email protected])
        !             3:  *
        !             4:  *  You can do anything you want with this software,
        !             5:  *    just don't say you wrote it,
        !             6:  *    and don't remove this notice.
        !             7:  *
        !             8:  *  This software is provided "as is".
        !             9:  *
        !            10:  *  The author supplies this software to be publicly
        !            11:  *  redistributed on the understanding that the author
        !            12:  *  is not responsible for the correct functioning of
        !            13:  *  this software in any circumstances and is not liable
        !            14:  *  for any damages caused by this software.
        !            15:  *
        !            16:  *  October 1992
        !            17:  *
        !            18:  *     pcfs_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.