Deleted Added
full compact
1,2c1,2
< /* $Id: msdosfs_vnops.c,v 1.54 1998/02/04 22:33:01 eivind Exp $ */
< /* $NetBSD: msdosfs_vnops.c,v 1.20 1994/08/21 18:44:13 ws Exp $ */
---
> /* $Id: msdosfs_vnops.c,v 1.55 1998/02/06 12:13:46 eivind Exp $ */
> /* $NetBSD: msdosfs_vnops.c,v 1.68 1998/02/10 14:10:04 mrg Exp $ */
5,6c5,6
< * Copyright (C) 1994 Wolfgang Solfrank.
< * Copyright (C) 1994 TooLs GmbH.
---
> * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
> * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
143c143
< printf("msdosfs_create(cnp %08x, vap %08x\n", cnp, ap->a_vap);
---
> printf("msdosfs_create(cnp %p, vap %p\n", cnp, ap->a_vap);
146a147,157
> * If this is the root directory and there is no space left we
> * can't do anything. This is because the root directory can not
> * change size.
> */
> if (pdep->de_StartCluster == MSDOSFSROOT
> && pdep->de_fndoffset >= pdep->de_FileSize) {
> error = ENOSPC;
> goto bad;
> }
>
> /*
153c164
< if ((cnp->cn_flags & SAVENAME) == 0)
---
> if ((cnp->cn_flags & HASBUF) == 0)
157,161c168,173
< TIMEVAL_TO_TIMESPEC(&time, &ts);
< unix2dostime(&ts, &ndirent.de_Date, &ndirent.de_Time);
< unix2dosfn((u_char *)cnp->cn_nameptr, ndirent.de_Name, cnp->cn_namelen);
< ndirent.de_Attributes = (ap->a_vap->va_mode & VWRITE)
< ? ATTR_ARCHIVE : ATTR_ARCHIVE | ATTR_READONLY;
---
> error = uniqdosname(pdep, cnp, ndirent.de_Name);
> if (error)
> goto bad;
>
> ndirent.de_Attributes = (ap->a_vap->va_mode & VWRITE) ?
> ATTR_ARCHIVE : ATTR_ARCHIVE | ATTR_READONLY;
166,170c178,185
< if ((error = createde(&ndirent, pdep, &dep)) == 0) {
< *ap->a_vpp = DETOV(dep);
< if ((cnp->cn_flags & SAVESTART) == 0)
< zfree(namei_zone, cnp->cn_pnbuf);
< } else {
---
> ndirent.de_pmp = pdep->de_pmp;
> ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE;
> TIMEVAL_TO_TIMESPEC(&time, &ts);
> DETIMES(&ndirent, &ts, &ts, &ts);
> error = createde(&ndirent, pdep, &dep, cnp);
> if (error)
> goto bad;
> if ((cnp->cn_flags & SAVESTART) == 0)
172,174c187,194
< }
< vput(ap->a_dvp); /* release parent dir */
< return error;
---
> vput(ap->a_dvp);
> *ap->a_vpp = DETOV(dep);
> return (0);
>
> bad:
> zfree(namei_zone, cnp->cn_pnbuf);
> vput(ap->a_dvp);
> return (error);
186d205
< int error;
190c209
< error = msdosfs_mkdir((struct vop_mkdir_args *)ap);
---
> return (msdosfs_mkdir((struct vop_mkdir_args *)ap));
194c213
< error = msdosfs_create((struct vop_create_args *)ap);
---
> return (msdosfs_create((struct vop_create_args *)ap));
198d216
< error = EINVAL;
201c219
< break;
---
> return (EINVAL);
203c221
< return error;
---
> /* NOTREACHED */
216a235
> struct timespec ts;
219,220c238,241
< if (vp->v_usecount > 1)
< DE_TIMES(dep, &time);
---
> if (vp->v_usecount > 1) {
> TIMEVAL_TO_TIMESPEC(&time, &ts);
> DETIMES(dep, &ts, &ts, &ts);
> }
311a333
> struct msdosfsmount *pmp = dep->de_pmp;
312a335,338
> mode_t mode;
> struct timespec ts;
> u_long dirsperblk = pmp->pm_BytesPerSec / sizeof(struct direntry);
> u_long fileid;
314c340,341
< DE_TIMES(dep, &time);
---
> TIMEVAL_TO_TIMESPEC(&time, &ts);
> DETIMES(dep, &ts, &ts, &ts);
322,323c349,351
< if ((cn = dep->de_StartCluster) == MSDOSFSROOT)
< cn = 1;
---
> fileid = cntobn(pmp, dep->de_StartCluster) * dirsperblk;
> if (dep->de_StartCluster == MSDOSFSROOT)
> fileid = 1;
325,327c353,356
< if ((cn = dep->de_dirclust) == MSDOSFSROOT)
< cn = 1;
< cn = (cn << 16) | (dep->de_diroffset & 0xffff);
---
> fileid = cntobn(pmp, dep->de_dirclust) * dirsperblk;
> if (dep->de_dirclust == MSDOSFSROOT)
> fileid = roottobn(pmp, 0) * dirsperblk;
> fileid += dep->de_diroffset / sizeof(struct direntry);
329,334c358,365
< vap->va_fileid = cn;
< vap->va_mode = (S_IXUSR|S_IXGRP|S_IXOTH) | (S_IRUSR|S_IRGRP|S_IROTH) |
< ((dep->de_Attributes & ATTR_READONLY) ? 0 : (S_IWUSR|S_IWGRP|S_IWOTH));
< vap->va_mode &= dep->de_pmp->pm_mask;
< if (dep->de_Attributes & ATTR_DIRECTORY)
< vap->va_mode |= S_IFDIR;
---
> vap->va_fileid = fileid;
> if ((dep->de_Attributes & ATTR_READONLY) == 0)
> mode = S_IRWXU|S_IRWXG|S_IRWXO;
> else
> mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
> vap->va_mode = mode & pmp->pm_mask;
> vap->va_uid = pmp->pm_uid;
> vap->va_gid = pmp->pm_gid;
336,337d366
< vap->va_gid = dep->de_pmp->pm_gid;
< vap->va_uid = dep->de_pmp->pm_uid;
340,349c369,379
< dos2unixtime(dep->de_Date, dep->de_Time, &vap->va_atime);
< vap->va_mtime = vap->va_atime;
< #if 0
< #ifndef MSDOSFS_NODIRMOD
< if (vap->va_mode & S_IFDIR)
< TIMEVAL_TO_TIMESPEC(&time, &vap->va_mtime);
< #endif
< #endif
< vap->va_ctime = vap->va_atime;
< vap->va_flags = (dep->de_Attributes & ATTR_ARCHIVE) ? 0 : SF_ARCHIVED;
---
> dos2unixtime(dep->de_MDate, dep->de_MTime, 0, &vap->va_mtime);
> if (pmp->pm_flags & MSDOSFSMNT_LONGNAME) {
> dos2unixtime(dep->de_ADate, 0, 0, &vap->va_atime);
> dos2unixtime(dep->de_CDate, dep->de_CTime, dep->de_CHun, &vap->va_ctime);
> } else {
> vap->va_atime = vap->va_mtime;
> vap->va_ctime = vap->va_mtime;
> }
> vap->va_flags = 0;
> if ((dep->de_Attributes & ATTR_ARCHIVE) == 0)
> vap->va_flags |= SF_ARCHIVED;
351,353c381,383
< vap->va_blocksize = dep->de_pmp->pm_bpcluster;
< vap->va_bytes = (dep->de_FileSize + dep->de_pmp->pm_crbomask) &
< ~(dep->de_pmp->pm_crbomask);
---
> vap->va_blocksize = pmp->pm_bpcluster;
> vap->va_bytes =
> (dep->de_FileSize + pmp->pm_crbomask) & ~pmp->pm_crbomask;
356c386
< return 0;
---
> return (0);
369a400
> struct msdosfsmount *pmp = dep->de_pmp;
373a405,409
> #ifdef MSDOSFS_DEBUG
> printf("msdosfs_setattr(): vp %p, vap %p, cred %p, p %p\n",
> ap->a_vp, vap, cred, ap->a_p);
> #endif
>
380a417,425
> #ifdef MSDOSFS_DEBUG
> printf("msdosfs_setattr(): returning EINVAL\n");
> printf(" va_type %d, va_nlink %x, va_fsid %lx, va_fileid %lx\n",
> vap->va_type, vap->va_nlink, vap->va_fsid, vap->va_fileid);
> printf(" va_blocksize %lx, va_rdev %x, va_bytes %qx, va_gen %lx\n",
> vap->va_blocksize, vap->va_rdev, vap->va_bytes, vap->va_gen);
> printf(" va_uid %x, va_gid %x\n",
> vap->va_uid, vap->va_gid);
> #endif
386c431
< if (cred->cr_uid != dep->de_pmp->pm_uid &&
---
> if (cred->cr_uid != pmp->pm_uid &&
414c459,462
< if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (uid_t)VNOVAL) {
---
> if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
> uid_t uid;
> gid_t gid;
>
417,420c465,472
< if ((cred->cr_uid != dep->de_pmp->pm_uid ||
< vap->va_uid != dep->de_pmp->pm_uid ||
< (vap->va_gid != dep->de_pmp->pm_gid &&
< !groupmember(vap->va_gid, cred))) &&
---
> uid = vap->va_uid;
> if (uid == (uid_t)VNOVAL)
> uid = pmp->pm_uid;
> gid = vap->va_gid;
> if (gid == (gid_t)VNOVAL)
> gid = pmp->pm_gid;
> if ((cred->cr_uid != pmp->pm_uid || uid != pmp->pm_uid ||
> (gid != pmp->pm_gid && !groupmember(gid, cred))) &&
423,424c475
< if (vap->va_uid != dep->de_pmp->pm_uid ||
< vap->va_gid != dep->de_pmp->pm_gid)
---
> if (uid != pmp->pm_uid || gid != pmp->pm_gid)
426a478
>
446c498
< if (vap->va_mtime.tv_sec != VNOVAL) {
---
> if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
449c501
< if (cred->cr_uid != dep->de_pmp->pm_uid &&
---
> if (cred->cr_uid != pmp->pm_uid &&
452,457c504,514
< (error = VOP_ACCESS(vp, VWRITE, cred, ap->a_p))))
< return error;
< dep->de_flag |= DE_UPDATE;
< error = deupdat(dep, &vap->va_mtime, 1);
< if (error)
< return error;
---
> (error = VOP_ACCESS(ap->a_vp, VWRITE, cred, ap->a_p))))
> return (error);
> if (vp->v_type != VDIR) {
> if ((pmp->pm_flags & MSDOSFSMNT_NOWIN95) == 0 &&
> vap->va_atime.tv_sec != VNOVAL)
> unix2dostime(&vap->va_atime, &dep->de_ADate, NULL, NULL);
> if (vap->va_mtime.tv_sec != VNOVAL)
> unix2dostime(&vap->va_mtime, &dep->de_MDate, &dep->de_MTime, NULL);
> dep->de_Attributes |= ATTR_ARCHIVE;
> dep->de_flag |= DE_MODIFIED;
> }
459d515
<
465,466c521
< error = 0;
< if (vap->va_mode != (u_short) VNOVAL) {
---
> if (vap->va_mode != (mode_t)VNOVAL) {
469c524
< if (cred->cr_uid != dep->de_pmp->pm_uid &&
---
> if (cred->cr_uid != pmp->pm_uid &&
471,478c526,534
< return error;
<
< /* We ignore the read and execute bits */
< if (vap->va_mode & VWRITE)
< dep->de_Attributes &= ~ATTR_READONLY;
< else
< dep->de_Attributes |= ATTR_READONLY;
< dep->de_flag |= DE_MODIFIED;
---
> return (error);
> if (vp->v_type != VDIR) {
> /* We ignore the read and execute bits. */
> if (vap->va_mode & VWRITE)
> dep->de_Attributes &= ~ATTR_READONLY;
> else
> dep->de_Attributes |= ATTR_READONLY;
> dep->de_flag |= DE_MODIFIED;
> }
480c536
< return error;
---
> return (deupdat(dep, 1));
493a550
> int blsize;
498c555
< daddr_t rablock;
---
> daddr_t rablock, rablock1;
510c567
< return 0;
---
> return (0);
512c569
< return EINVAL;
---
> return (EINVAL);
516c573
< lbn = uio->uio_offset >> pmp->pm_cnshift;
---
> lbn = de_cluster(pmp, uio->uio_offset);
521c578,580
< return 0;
---
> return (0);
> if (diff < n)
> n = diff;
524c583
< error = pcbmap(dep, lbn, &lbn, 0);
---
> error = pcbmap(dep, lbn, &lbn, 0, &blsize);
526c585
< return error;
---
> return (error);
528,529d586
< if (diff < n)
< n = diff;
536,537c593
< error = bread(pmp->pm_devvp, lbn, pmp->pm_bpcluster,
< NOCRED, &bp);
---
> error = bread(pmp->pm_devvp, lbn, blsize, NOCRED, &bp);
548c604,605
< rablock * pmp->pm_bpcluster < dep->de_FileSize) {
---
> de_cn2off(pmp, rablock) < dep->de_FileSize) {
> rablock1 = de_cn2bn(pmp, rablock);
550,556c607,612
< error = breadn(vp, lbn, pmp->pm_bpcluster,
< &rablock, &rasize, 1,
< NOCRED, &bp);
< } else {
< error = bread(vp, lbn, pmp->pm_bpcluster, NOCRED,
< &bp);
< }
---
> error = breadn(vp, de_cn2bn(pmp, lbn),
> pmp->pm_bpcluster, &rablock1, &rasize, 1,
> NOCRED, &bp);
> } else
> error = bread(vp, de_cn2bn(pmp, lbn),
> pmp->pm_bpcluster, NOCRED, &bp);
562c618
< return error;
---
> return (error);
565,574c621,622
< /*
< * If we have read everything from this block or have read
< * to end of file then we are done with this block. Mark
< * it to say the buffer can be reused if need be.
< */
< #if 0
< if (n + on == pmp->pm_bpcluster ||
< uio->uio_offset == dep->de_FileSize)
< bp->b_flags |= B_AGE;
< #endif
---
> if (!isadir)
> dep->de_flag |= DE_ACCESS;
577c625
< return error;
---
> return (error);
593d640
< int isadir;
596c643
< int osize;
---
> u_long osize;
609d655
< struct timespec ts;
612,615c658,661
< printf("msdosfs_write(vp %08x, uio %08x, ioflag %08x, cred %08x\n",
< vp, uio, ioflag, cred);
< printf("msdosfs_write(): diroff %d, dirclust %d, startcluster %d\n",
< dep->de_diroffset, dep->de_dirclust, dep->de_StartCluster);
---
> printf("msdosfs_write(vp %p, uio %p, ioflag %x, cred %p\n",
> vp, uio, ioflag, cred);
> printf("msdosfs_write(): diroff %lu, dirclust %lu, startcluster %lu\n",
> dep->de_diroffset, dep->de_dirclust, dep->de_StartCluster);
622d667
< isadir = 0;
625d669
<
627,632c671
< if ((ioflag & IO_SYNC) == 0)
< panic("msdosfs_write(): non-sync directory update");
< isadir = 1;
< thisvp = pmp->pm_devvp;
< break;
<
---
> return EISDIR;
635d673
< break;
639c677
< return EINVAL;
---
> return (EINVAL);
642c680
< return 0;
---
> return (0);
647c685
< if (vp->v_type == VREG && p &&
---
> if (p &&
649c687
< p->p_rlimit[RLIMIT_FSIZE].rlim_cur)) {
---
> p->p_rlimit[RLIMIT_FSIZE].rlim_cur)) {
651c689
< return EFBIG;
---
> return (EFBIG);
655,663d692
< * If attempting to write beyond the end of the root directory we
< * stop that here because the root directory can not grow.
< */
< if ((dep->de_Attributes & ATTR_DIRECTORY) &&
< dep->de_StartCluster == MSDOSFSROOT &&
< (uio->uio_offset + uio->uio_resid) > dep->de_FileSize)
< return ENOSPC;
<
< /*
672c701
< return error;
---
> return (error);
681d709
<
694,696c722,725
< count = de_clcount(pmp, uio->uio_offset + resid) - de_clcount(pmp, osize);
< if ((error = extendfile(dep, count, NULL, NULL, 0))
< && (error != ENOSPC || (ioflag & IO_UNIT)))
---
> count = de_clcount(pmp, uio->uio_offset + resid) -
> de_clcount(pmp, osize);
> error = extendfile(dep, count, NULL, NULL, 0);
> if (error && (error != ENOSPC || (ioflag & IO_UNIT)))
703,708c732
< bn = de_blk(pmp, uio->uio_offset);
< if (isadir) {
< error = pcbmap(dep, bn, &bn, 0);
< if (error)
< break;
< } else if (bn > lastcn) {
---
> if (de_cluster(pmp, uio->uio_offset) > lastcn) {
720a745
> bn = de_blk(pmp, uio->uio_offset);
735,747c760,765
< if (!isadir) {
< if (bp->b_blkno == bp->b_lblkno) {
< error = pcbmap(dep, bp->b_lblkno,
< &bp->b_blkno, 0);
< if (error)
< bp->b_blkno = -1;
< }
< if (bp->b_blkno == -1) {
< brelse(bp);
< if (!error)
< error = EIO; /* XXX */
< break;
< }
---
> if (bp->b_blkno == bp->b_lblkno) {
> error = pcbmap(dep,
> de_bn2cn(pmp, bp->b_lblkno),
> &bp->b_blkno, 0, 0);
> if (error)
> bp->b_blkno = -1;
748a767,772
> if (bp->b_blkno == -1) {
> brelse(bp);
> if (!error)
> error = EIO; /* XXX */
> break;
> }
754c778,779
< if (error)
---
> if (error) {
> brelse(bp);
755a781
> }
777c803
< else if (n + croffset == pmp->pm_bpcluster) {
---
> else if (n + croffset == pmp->pm_bpcluster)
779c805
< } else
---
> else
799,803c825,827
< } else if (ioflag & IO_SYNC) {
< TIMEVAL_TO_TIMESPEC(&time, &ts);
< error = deupdat(dep, &ts, 1);
< }
< return error;
---
> } else if (ioflag & IO_SYNC)
> error = deupdat(dep, 1);
> return (error);
821,825c845
< register struct vnode *vp = ap->a_vp;
< register struct buf *bp;
< int wait = ap->a_waitfor == MNT_WAIT;
< struct timespec ts;
< struct buf *nbp;
---
> struct vnode *vp = ap->a_vp;
826a847
> struct buf *bp, *nbp;
856,857c877
< TIMEVAL_TO_TIMESPEC(&time, &ts);
< return deupdat(VTODE(vp), &ts, wait);
---
> return (deupdat(VTODE(vp), ap->a_waitfor == MNT_WAIT));
872c892,895
< error = removede(ddep,dep);
---
> if (ap->a_vp->v_type == VDIR)
> error = EPERM;
> else
> error = removede(ddep, dep);
874c897
< printf("msdosfs_remove(), dep %08x, v_usecount %d\n", dep, ap->a_vp->v_usecount);
---
> printf("msdosfs_remove(), dep %p, v_usecount %d\n", dep, ap->a_vp->v_usecount);
882c905
< return error;
---
> return (error);
965,970c988,990
< u_char toname[11];
< int error;
< int newparent = 0;
< int sourceisadirectory = 0;
< u_long cn;
< daddr_t bn;
---
> struct vnode *tdvp = ap->a_tdvp;
> struct vnode *fvp = ap->a_fvp;
> struct vnode *fdvp = ap->a_fdvp;
971a992
> struct componentname *tcnp = ap->a_tcnp;
973a995,1002
> struct denode *ip, *xp, *dp, *zp;
> u_char toname[11], oldname[11];
> u_long from_diroffset, to_diroffset;
> u_char to_count;
> int doingdirectory = 0, newparent = 0;
> int error;
> u_long cn;
> daddr_t bn;
980d1008
< struct direntry *ep;
989,994c1017
< /* Check for cross-device rename */
< if ((ap->a_fvp->v_mount != ap->a_tdvp->v_mount) ||
< (tvp && (ap->a_fvp->v_mount != tvp->v_mount))) {
< error = EXDEV;
< goto bad;
< }
---
> pmp = VFSTOMSDOSFS(fdvp->v_mount);
995a1019,1023
> #ifdef DIAGNOSTIC
> if ((tcnp->cn_flags & HASBUF) == 0 ||
> (fcnp->cn_flags & HASBUF) == 0)
> panic("msdosfs_rename: no name");
> #endif
997,999c1025
< * Convert the filename in tcnp into a dos filename. We copy this
< * into the denode and directory entry for the destination
< * file/directory.
---
> * Check for cross-device rename.
1001,1002c1027,1042
< unix2dosfn((u_char *) ap->a_tcnp->cn_nameptr,
< toname, ap->a_tcnp->cn_namelen);
---
> if ((fvp->v_mount != tdvp->v_mount) ||
> (tvp && (fvp->v_mount != tvp->v_mount))) {
> error = EXDEV;
> abortit:
> VOP_ABORTOP(tdvp, tcnp);
> if (tdvp == tvp)
> vrele(tdvp);
> else
> vput(tdvp);
> if (tvp)
> vput(tvp);
> VOP_ABORTOP(fdvp, fcnp);
> vrele(fdvp);
> vrele(fvp);
> return (error);
> }
1005,1009c1045
< * At this point this is the lock state of the denodes:
< * fddep referenced
< * fdep referenced
< * tddep locked
< * tdep locked if it exists
---
> * If source and dest are the same, do nothing.
1010a1047,1050
> if (tvp == fvp) {
> error = 0;
> goto abortit;
> }
1011a1052,1057
> error = vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, p);
> if (error)
> goto abortit;
> dp = VTODE(fdvp);
> ip = VTODE(fvp);
>
1018,1031c1064,1075
< if (fdep->de_Attributes & ATTR_DIRECTORY) {
< if ((ap->a_fcnp->cn_namelen == 1
< && ap->a_fcnp->cn_nameptr[0] == '.')
< || fddep == fdep
< || (ap->a_fcnp->cn_flags | ap->a_tcnp->cn_flags)
< & ISDOTDOT) {
< VOP_ABORTOP(ap->a_tdvp, ap->a_tcnp);
< vput(ap->a_tdvp);
< if (tvp)
< vput(tvp);
< VOP_ABORTOP(ap->a_fdvp, ap->a_fcnp);
< vrele(ap->a_fdvp);
< vrele(ap->a_fvp);
< return EINVAL;
---
> if (ip->de_Attributes & ATTR_DIRECTORY) {
> /*
> * Avoid ".", "..", and aliases of "." for obvious reasons.
> */
> if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
> dp == ip ||
> (fcnp->cn_flags & ISDOTDOT) ||
> (tcnp->cn_flags & ISDOTDOT) ||
> (ip->de_flag & DE_RENAME)) {
> VOP_UNLOCK(fvp, 0, p);
> error = EINVAL;
> goto abortit;
1033c1077,1078
< sourceisadirectory = 1;
---
> ip->de_flag |= DE_RENAME;
> doingdirectory++;
1037,1042c1082,1083
< * If we are renaming a directory, and the directory is being moved
< * to another directory, then we must be sure the destination
< * directory is not in the subtree of the source directory. This
< * could orphan everything under the source directory.
< * doscheckpath() unlocks the destination's parent directory so we
< * must look it up again to relock it.
---
> * When the target exists, both the directory
> * and target vnodes are returned locked.
1044c1085,1105
< if (fddep->de_StartCluster != tddep->de_StartCluster)
---
> dp = VTODE(tdvp);
> xp = tvp ? VTODE(tvp) : NULL;
> /*
> * Remember direntry place to use for destination
> */
> to_diroffset = dp->de_fndoffset;
> to_count = dp->de_fndcnt;
>
> /*
> * If ".." must be changed (ie the directory gets a new
> * parent) then the source directory must not be in the
> * directory heirarchy above the target, as this would
> * orphan everything below the source directory. Also
> * the user must have write permission in the source so
> * as to be able to change "..". We must repeat the call
> * to namei, as the parent directory is unlocked by the
> * call to doscheckpath().
> */
> error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
> VOP_UNLOCK(fvp, 0, p);
> if (VTODE(fdvp)->de_StartCluster != VTODE(tdvp)->de_StartCluster)
1046,1054c1107,1109
< if (sourceisadirectory && newparent) {
< if (tdep) {
< vput(ap->a_tvp);
< tdep = NULL;
< }
< /* doscheckpath() vput()'s tddep */
< error = doscheckpath(fdep, tddep);
< tddep = NULL;
< if (error)
---
> vrele(fdvp);
> if (doingdirectory && newparent) {
> if (error) /* write access check above */
1056,1058c1111,1117
< if ((ap->a_tcnp->cn_flags & SAVESTART) == 0)
< panic("msdosfs_rename(): lost to startdir");
< error = relookup(ap->a_tdvp, &tvp, ap->a_tcnp);
---
> if (xp != NULL)
> vput(tvp);
> /*
> * doscheckpath() vput()'s dp,
> * so we have to do a relookup afterwards
> */
> error = doscheckpath(ip, dp);
1060,1062c1119,1126
< goto bad;
< tddep = VTODE(ap->a_tdvp);
< tdep = tvp ? VTODE(tvp) : NULL;
---
> goto out;
> if ((tcnp->cn_flags & SAVESTART) == 0)
> panic("msdosfs_rename: lost to startdir");
> error = relookup(tdvp, &tvp, tcnp);
> if (error)
> goto out;
> dp = VTODE(tdvp);
> xp = tvp ? VTODE(tvp) : NULL;
1065,1076c1129,1136
< /*
< * If the destination exists, then be sure its type (file or dir)
< * matches that of the source. And, if it is a directory make sure
< * it is empty. Then delete the destination.
< */
< if (tdep) {
< if (tdep->de_Attributes & ATTR_DIRECTORY) {
< if (!sourceisadirectory) {
< error = ENOTDIR;
< goto bad;
< }
< if (!dosdirempty(tdep)) {
---
> if (xp != NULL) {
> /*
> * Target must be empty if a directory and have no links
> * to it. Also, ensure source and target are compatible
> * (both directories, or both not directories).
> */
> if (xp->de_Attributes & ATTR_DIRECTORY) {
> if (!dosdirempty(xp)) {
1080,1083c1140,1141
< cache_purge(DETOV(tddep));
< } else { /* destination is file */
< if (sourceisadirectory) {
< error = EISDIR;
---
> if (!doingdirectory) {
> error = ENOTDIR;
1085a1144,1147
> cache_purge(tdvp);
> } else if (doingdirectory) {
> error = EISDIR;
> goto bad;
1087c1149
< error = removede(tddep,tdep);
---
> error = removede(dp, xp);
1090,1091c1152,1153
< vput(ap->a_tvp);
< tdep = NULL;
---
> vput(tvp);
> xp = NULL;
1095,1097c1157,1159
< * If the source and destination are in the same directory then
< * just read in the directory entry, change the name in the
< * directory entry and write it back to disk.
---
> * Convert the filename in tcnp into a dos filename. We copy this
> * into the denode and directory entry for the destination
> * file/directory.
1099,1114c1161,1176
< if (newparent == 0) {
< /* tddep and fddep point to the same denode here */
< vn_lock(ap->a_fvp, LK_EXCLUSIVE, p); /* ap->a_fdvp is already locked */
< error = readep(fddep->de_pmp, fdep->de_dirclust,
< fdep->de_diroffset, &bp, &ep);
< if (error) {
< VOP_UNLOCK(ap->a_fvp, 0, p);
< goto bad;
< }
< bcopy(toname, ep->deName, 11);
< error = bwrite(bp);
< if (error) {
< VOP_UNLOCK(ap->a_fvp, 0, p);
< goto bad;
< }
< bcopy(toname, fdep->de_Name, 11); /* update denode */
---
> error = uniqdosname(VTODE(tdvp), tcnp, toname);
> if (error)
> goto abortit;
>
> /*
> * Since from wasn't locked at various places above,
> * have to do a relookup here.
> */
> fcnp->cn_flags &= ~MODMASK;
> fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
> if ((fcnp->cn_flags & SAVESTART) == 0)
> panic("msdosfs_rename: lost from startdir");
> if (!newparent)
> VOP_UNLOCK(tdvp, 0, p);
> (void) relookup(fdvp, &fvp, fcnp);
> if (fvp == NULL) {
1116,1117c1178
< * fdep locked fddep and tddep point to the same denode
< * which is locked tdep is NULL
---
> * From name has disappeared.
1118a1180,1207
> if (doingdirectory)
> panic("rename: lost dir entry");
> vrele(ap->a_fvp);
> if (newparent)
> VOP_UNLOCK(tdvp, 0, p);
> vrele(tdvp);
> return 0;
> }
> xp = VTODE(fvp);
> zp = VTODE(fdvp);
> from_diroffset = zp->de_fndoffset;
>
> /*
> * Ensure that the directory entry still exists and has not
> * changed till now. If the source is a file the entry may
> * have been unlinked or renamed. In either case there is
> * no further work to be done. If the source is a directory
> * then it cannot have been rmdir'ed or renamed; this is
> * prohibited by the DE_RENAME flag.
> */
> if (xp != ip) {
> if (doingdirectory)
> panic("rename: lost dir entry");
> vrele(ap->a_fvp);
> VOP_UNLOCK(fvp, 0, p);
> if (newparent)
> VOP_UNLOCK(fdvp, 0, p);
> xp = NULL;
1120c1209,1210
< u_long dirsize = 0L;
---
> vrele(fvp);
> xp = NULL;
1123,1126c1213,1215
< * If the source and destination are in different
< * directories, then mark the entry in the source directory
< * as deleted and write a new entry in the destination
< * directory. Then move the denode to the correct hash
---
> * First write a new entry in the destination
> * directory and mark the entry in the source directory
> * as deleted. Then move the denode to the correct hash
1129,1131c1218
< * to the new parent directory. If we moved a directory
< * will also insure that the directory entry on disk has a
< * filesize of zero.
---
> * to the new parent directory.
1133,1142c1220,1224
< vn_lock(ap->a_fvp, LK_EXCLUSIVE, p);
< bcopy(toname, fdep->de_Name, 11); /* update denode */
< if (fdep->de_Attributes & ATTR_DIRECTORY) {
< dirsize = fdep->de_FileSize;
< fdep->de_FileSize = 0;
< }
< error = createde(fdep, tddep, (struct denode **) 0);
< if (fdep->de_Attributes & ATTR_DIRECTORY) {
< fdep->de_FileSize = dirsize;
< }
---
> bcopy(ip->de_Name, oldname, 11);
> bcopy(toname, ip->de_Name, 11); /* update denode */
> dp->de_fndoffset = to_diroffset;
> dp->de_fndcnt = to_count;
> error = createde(ip, dp, (struct denode **)0, tcnp);
1144,1145c1226,1229
< /* should put back filename */
< VOP_UNLOCK(ap->a_fvp, 0, p);
---
> bcopy(oldname, ip->de_Name, 11);
> if (newparent)
> VOP_UNLOCK(fdvp, 0, p);
> VOP_UNLOCK(fvp, 0, p);
1148,1150c1232,1234
< vn_lock(ap->a_fdvp, LK_EXCLUSIVE, p);
< error = readep(fddep->de_pmp, fddep->de_fndclust,
< fddep->de_fndoffset, &bp, &ep);
---
> ip->de_refcnt++;
> zp->de_fndoffset = from_diroffset;
> error = removede(zp, ip);
1152,1153c1236,1239
< VOP_UNLOCK(ap->a_fvp, 0, p);
< VOP_UNLOCK(ap->a_fdvp, 0, p);
---
> /* XXX should really panic here, fs is corrupt */
> if (newparent)
> VOP_UNLOCK(fdvp, 0, p);
> VOP_UNLOCK(fvp, 0, p);
1156,1161c1242,1253
< ep->deName[0] = SLOT_DELETED;
< error = bwrite(bp);
< if (error) {
< VOP_UNLOCK(ap->a_fvp, 0, p);
< VOP_UNLOCK(ap->a_fdvp, 0, p);
< goto bad;
---
> if (!doingdirectory) {
> error = pcbmap(dp, de_cluster(pmp, to_diroffset), 0,
> &ip->de_dirclust, 0);
> if (error) {
> /* XXX should really panic here, fs is corrupt */
> if (newparent)
> VOP_UNLOCK(fdvp, 0, p);
> VOP_UNLOCK(fvp, 0, p);
> goto bad;
> }
> if (ip->de_dirclust != MSDOSFSROOT)
> ip->de_diroffset = to_diroffset & pmp->pm_crbomask;
1163,1168c1255,1257
< if (!sourceisadirectory) {
< fdep->de_dirclust = tddep->de_fndclust;
< fdep->de_diroffset = tddep->de_fndoffset;
< reinsert(fdep);
< }
< VOP_UNLOCK(ap->a_fdvp, 0, p);
---
> reinsert(ip);
> if (newparent)
> VOP_UNLOCK(fdvp, 0, p);
1170d1258
< /* fdep is still locked here */
1176,1177c1264,1265
< if (sourceisadirectory && newparent) {
< cn = fdep->de_StartCluster;
---
> if (doingdirectory && newparent) {
> cn = ip->de_StartCluster;
1181c1269
< } else {
---
> } else
1183d1270
< }
1187,1188c1274,1276
< /* should really panic here, fs is corrupt */
< VOP_UNLOCK(ap->a_fvp, 0, p);
---
> /* XXX should really panic here, fs is corrupt */
> brelse(bp);
> VOP_UNLOCK(fvp, 0, p);
1191,1192c1279,1282
< dotdotp = (struct direntry *) bp->b_data + 1;
< putushort(dotdotp->deStartCluster, tddep->de_StartCluster);
---
> dotdotp = (struct direntry *)bp->b_data + 1;
> putushort(dotdotp->deStartCluster, dp->de_StartCluster);
> if (FAT32(pmp))
> putushort(dotdotp->deHighClust, dp->de_StartCluster >> 16);
1194d1283
< VOP_UNLOCK(ap->a_fvp, 0, p);
1196c1285,1286
< /* should really panic here, fs is corrupt */
---
> /* XXX should really panic here, fs is corrupt */
> VOP_UNLOCK(fvp, 0, p);
1199,1208c1289,1301
< } else
< VOP_UNLOCK(ap->a_fvp, 0, p);
< bad: ;
< vrele(DETOV(fdep));
< vrele(DETOV(fddep));
< if (tdep)
< vput(DETOV(tdep));
< if (tddep)
< vput(DETOV(tddep));
< return error;
---
> }
>
> VOP_UNLOCK(fvp, 0, p);
> bad:
> if (xp)
> vput(tvp);
> vput(tdvp);
> out:
> ip->de_flag &= ~DE_RENAME;
> vrele(fdvp);
> vrele(fvp);
> return (error);
>
1214,1229c1307,1327
< } dosdirtemplate = {
< {
< ". ", " ", /* the . entry */
< ATTR_DIRECTORY, /* file attribute */
< {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* resevered */
< {210, 4}, {210, 4}, /* time and date */
< {0, 0}, /* startcluster */
< {0, 0, 0, 0}, /* filesize */
< },{
< ".. ", " ", /* the .. entry */
< ATTR_DIRECTORY, /* file attribute */
< {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, /* resevered */
< {210, 4}, {210, 4}, /* time and date */
< {0, 0}, /* startcluster */
< {0, 0, 0, 0}, /* filesize */
< }
---
> } dosdirtemplate = {
> { ". ", " ", /* the . entry */
> ATTR_DIRECTORY, /* file attribute */
> 0, /* reserved */
> 0, { 0, 0 }, { 0, 0 }, /* create time & date */
> { 0, 0 }, /* access date */
> { 0, 0 }, /* high bits of start cluster */
> { 210, 4 }, { 210, 4 }, /* modify time & date */
> { 0, 0 }, /* startcluster */
> { 0, 0, 0, 0 } /* filesize */
> },
> { ".. ", " ", /* the .. entry */
> ATTR_DIRECTORY, /* file attribute */
> 0, /* reserved */
> 0, { 0, 0 }, { 0, 0 }, /* create time & date */
> { 0, 0 }, /* access date */
> { 0, 0 }, /* high bits of start cluster */
> { 210, 4 }, { 210, 4 }, /* modify time & date */
> { 0, 0 }, /* startcluster */
> { 0, 0, 0, 0 } /* filesize */
> }
1241c1339,1342
< int bn;
---
> struct componentname *cnp = ap->a_cnp;
> struct denode ndirent;
> struct denode *dep;
> struct denode *pdep = VTODE(ap->a_dvp);
1243,1245c1344,1345
< u_long newcluster;
< struct denode *pdep;
< struct denode *ndep;
---
> int bn;
> u_long newcluster, pcl;
1247,1248c1347
< struct denode ndirent;
< struct msdosfsmount *pmp;
---
> struct msdosfsmount *pmp = pdep->de_pmp;
1251d1349
< u_short dDate, dTime;
1253,1254d1350
< pdep = VTODE(ap->a_dvp);
<
1260,1263c1356,1359
< if (pdep->de_StartCluster == MSDOSFSROOT && pdep->de_fndclust == (u_long)-1) {
< zfree(namei_zone, ap->a_cnp->cn_pnbuf);
< vput(ap->a_dvp);
< return ENOSPC;
---
> if (pdep->de_StartCluster == MSDOSFSROOT
> && pdep->de_fndoffset >= pdep->de_FileSize) {
> error = ENOSPC;
> goto bad2;
1266,1267d1361
< pmp = pdep->de_pmp;
<
1272,1276c1366,1367
< if (error) {
< zfree(namei_zone, ap->a_cnp->cn_pnbuf);
< vput(ap->a_dvp);
< return error;
< }
---
> if (error)
> goto bad2;
1277a1369,1374
> bzero(&ndirent, sizeof(ndirent));
> ndirent.de_pmp = pmp;
> ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE;
> TIMEVAL_TO_TIMESPEC(&time, &ts);
> DETIMES(&ndirent, &ts, &ts, &ts);
>
1288,1303c1385,1405
< denp = (struct direntry *) bp->b_data;
< putushort(denp->deStartCluster, newcluster);
< TIMEVAL_TO_TIMESPEC(&time, &ts);
< unix2dostime(&ts, &dDate, &dTime);
< putushort(denp->deDate, dDate);
< putushort(denp->deTime, dTime);
< denp++;
< putushort(denp->deStartCluster, pdep->de_StartCluster);
< putushort(denp->deDate, dDate);
< putushort(denp->deTime, dTime);
< error = bwrite(bp);
< if (error) {
< clusterfree(pmp, newcluster, NULL);
< zfree(namei_zone, ap->a_cnp->cn_pnbuf);
< vput(ap->a_dvp);
< return error;
---
> denp = (struct direntry *)bp->b_data;
> putushort(denp[0].deStartCluster, newcluster);
> putushort(denp[0].deCDate, ndirent.de_CDate);
> putushort(denp[0].deCTime, ndirent.de_CTime);
> denp[0].deCHundredth = ndirent.de_CHun;
> putushort(denp[0].deADate, ndirent.de_ADate);
> putushort(denp[0].deMDate, ndirent.de_MDate);
> putushort(denp[0].deMTime, ndirent.de_MTime);
> pcl = pdep->de_StartCluster;
> if (FAT32(pmp) && pcl == pmp->pm_rootdirblk)
> pcl = 0;
> putushort(denp[1].deStartCluster, pcl);
> putushort(denp[1].deCDate, ndirent.de_CDate);
> putushort(denp[1].deCTime, ndirent.de_CTime);
> denp[1].deCHundredth = ndirent.de_CHun;
> putushort(denp[1].deADate, ndirent.de_ADate);
> putushort(denp[1].deMDate, ndirent.de_MDate);
> putushort(denp[1].deMTime, ndirent.de_MTime);
> if (FAT32(pmp)) {
> putushort(denp[0].deHighClust, newcluster >> 16);
> putushort(denp[1].deHighClust, pdep->de_StartCluster >> 16);
1305a1408,1411
> error = bwrite(bp);
> if (error)
> goto bad;
>
1311,1328c1417,1419
< ndep = &ndirent;
< bzero(ndep, sizeof(*ndep));
< unix2dosfn((u_char *)ap->a_cnp->cn_nameptr,
< ndep->de_Name, ap->a_cnp->cn_namelen);
< TIMEVAL_TO_TIMESPEC(&time, &ts);
< unix2dostime(&ts, &ndep->de_Date, &ndep->de_Time);
< ndep->de_StartCluster = newcluster;
< ndep->de_Attributes = ATTR_DIRECTORY;
<
< error = createde(ndep, pdep, &ndep);
< if (error) {
< clusterfree(pmp, newcluster, NULL);
< } else {
< *ap->a_vpp = DETOV(ndep);
< }
< zfree(namei_zone, ap->a_cnp->cn_pnbuf);
< #ifdef MSDOSFS_DEBUG
< printf("msdosfs_mkdir(): vput(%08x)\n", ap->a_dvp);
---
> #ifdef DIAGNOSTIC
> if ((cnp->cn_flags & HASBUF) == 0)
> panic("msdosfs_mkdir: no name");
1329a1421,1434
> error = uniqdosname(pdep, cnp, ndirent.de_Name);
> if (error)
> goto bad;
>
> ndirent.de_Attributes = ATTR_DIRECTORY;
> ndirent.de_StartCluster = newcluster;
> ndirent.de_FileSize = 0;
> ndirent.de_dev = pdep->de_dev;
> ndirent.de_devvp = pdep->de_devvp;
> error = createde(&ndirent, pdep, &dep, cnp);
> if (error)
> goto bad;
> if ((cnp->cn_flags & SAVESTART) == 0)
> zfree(namei_zone, cnp->cn_pnbuf);
1331c1436,1444
< return error;
---
> *ap->a_vpp = DETOV(dep);
> return (0);
>
> bad:
> clusterfree(pmp, newcluster, NULL);
> bad2:
> zfree(namei_zone, cnp->cn_pnbuf);
> vput(ap->a_dvp);
> return (error);
1342,1344c1455,1462
< struct denode *ddep;
< struct denode *dep;
< int error = 0;
---
> register struct vnode *vp = ap->a_vp;
> register struct vnode *dvp = ap->a_dvp;
> register struct componentname *cnp = ap->a_cnp;
> register struct denode *ip, *dp;
> int error;
>
> ip = VTODE(vp);
> dp = VTODE(dvp);
1346,1348d1463
< ddep = VTODE(ap->a_dvp); /* parent dir of dir to delete */
< dep = VTODE(ap->a_vp);/* directory to delete */
<
1350c1465,1469
< * Be sure the directory being deleted is empty.
---
> * Verify the directory is empty (and valid).
> * (Rmdir ".." won't be valid since
> * ".." will contain a reference to
> * the current directory and thus be
> * non-empty.)
1352c1471,1472
< if (dosdirempty(dep) == 0) {
---
> error = 0;
> if (!dosdirempty(ip) || ip->de_flag & DE_RENAME) {
1356d1475
<
1365c1484
< error = removede(ddep,dep);
---
> error = removede(dp, ip);
1368d1486
<
1374,1377c1492,1494
< cache_purge(DETOV(ddep));
< vput(ap->a_dvp);
< ap->a_dvp = NULL;
<
---
> cache_purge(dvp);
> vput(dvp);
> dvp = NULL;
1381,1388c1498,1504
< error = detrunc(dep, (u_long) 0, IO_SYNC, NOCRED, NULL);
< cache_purge(DETOV(dep));
<
< out: ;
< if (ap->a_dvp)
< vput(ap->a_dvp);
< vput(ap->a_vp);
< return error;
---
> error = detrunc(ip, (u_long)0, IO_SYNC, cnp->cn_cred, cnp->cn_proc);
> cache_purge(vp);
> out:
> if (dvp)
> vput(dvp);
> vput(vp);
> return (error);
1404a1521
> /* VOP_ABORTOP(ap->a_dvp, ap->a_cnp); ??? */
1406c1523
< return EINVAL;
---
> return (EOPNOTSUPP);
1409,1437d1525
< /*
< * Dummy dirents to simulate the "." and ".." entries of the root directory
< * in a dos filesystem. Dos doesn't provide these. Note that each entry
< * must be the same size as a dos directory entry (32 bytes).
< */
< static struct dos_dirent {
< u_long d_fileno;
< u_short d_reclen;
< u_char d_type;
< u_char d_namlen;
< u_char d_name[24];
< } rootdots[2] = {
<
< {
< 1, /* d_fileno */
< sizeof(struct direntry), /* d_reclen */
< DT_DIR, /* d_type */
< 1, /* d_namlen */
< "." /* d_name */
< },
< {
< 1, /* d_fileno */
< sizeof(struct direntry), /* d_reclen */
< DT_DIR, /* d_type */
< 2, /* d_namlen */
< ".." /* d_name */
< }
< };
<
1451d1538
< char pushout;
1452a1540
> int blsize;
1457a1546
> u_long dirsperblk;
1459,1460c1548
< daddr_t bn;
< daddr_t lbn;
---
> daddr_t bn, lbn;
1465,1467c1553
< struct dirent *prev;
< struct dirent *crnt;
< u_char dirbuf[512]; /* holds converted dos directories */
---
> struct dirent dirbuf;
1469c1555
< off_t off;
---
> u_long *cookies = NULL;
1470a1557,1558
> off_t offset, off;
> int chksum = -1;
1473,1474c1561,1562
< printf("msdosfs_readdir(): vp %08x, uio %08x, cred %08x, eofflagp %08x\n",
< ap->a_vp, uio, ap->a_cred, ap->a_eofflag);
---
> printf("msdosfs_readdir(): vp %p, uio %p, cred %p, eofflagp %p\n",
> ap->a_vp, uio, ap->a_cred, ap->a_eofflag);
1484c1572
< return ENOTDIR;
---
> return (ENOTDIR);
1486a1575,1579
> * To be safe, initialize dirbuf
> */
> bzero(dirbuf.d_name, sizeof(dirbuf.d_name));
>
> /*
1492c1585
< lost = uio->uio_resid - count;
---
> offset = uio->uio_offset;
1494,1495c1587,1589
< (uio->uio_offset & (sizeof(struct direntry) - 1)))
< return EINVAL;
---
> (offset & (sizeof(struct direntry) - 1)))
> return (EINVAL);
> lost = uio->uio_resid - count;
1497,1498d1590
< uio->uio_iov->iov_len = count;
< off = uio->uio_offset;
1499a1592,1601
> if (ap->a_ncookies) {
> ncookies = uio->uio_resid / 16;
> MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP,
> M_WAITOK);
> *ap->a_cookies = cookies;
> *ap->a_ncookies = ncookies;
> }
>
> dirsperblk = pmp->pm_BytesPerSec / sizeof(struct direntry);
>
1507,1511c1609,1614
< if (dep->de_StartCluster == MSDOSFSROOT) {
< /*
< * printf("msdosfs_readdir(): going after . or .. in root dir, offset %d\n",
< * uio->uio_offset);
< */
---
> if (dep->de_StartCluster == MSDOSFSROOT
> || (FAT32(pmp) && dep->de_StartCluster == pmp->pm_rootdirblk)) {
> #if 0
> printf("msdosfs_readdir(): going after . or .. in root dir, offset %d\n",
> offset);
> #endif
1513,1517c1616,1648
< if (uio->uio_offset < 2 * sizeof(struct direntry)) {
< if (uio->uio_offset
< && uio->uio_offset != sizeof(struct direntry)) {
< error = EINVAL;
< goto out;
---
> if (offset < bias) {
> for (n = (int)offset / sizeof(struct direntry);
> n < 2; n++) {
> if (FAT32(pmp))
> dirbuf.d_fileno = cntobn(pmp,
> pmp->pm_rootdirblk)
> * dirsperblk;
> else
> dirbuf.d_fileno = 1;
> dirbuf.d_type = DT_DIR;
> switch (n) {
> case 0:
> dirbuf.d_namlen = 1;
> strcpy(dirbuf.d_name, ".");
> break;
> case 1:
> dirbuf.d_namlen = 2;
> strcpy(dirbuf.d_name, "..");
> break;
> }
> dirbuf.d_reclen = GENERIC_DIRSIZ(&dirbuf);
> if (uio->uio_resid < dirbuf.d_reclen)
> goto out;
> error = uiomove((caddr_t) &dirbuf,
> dirbuf.d_reclen, uio);
> if (error)
> goto out;
> if (cookies) {
> *cookies++ = offset;
> if (--ncookies <= 0)
> goto out;
> }
> offset += sizeof(struct direntry);
1519,1526d1649
< n = 1;
< if (!uio->uio_offset) {
< n = 2;
< ncookies++;
< }
< ncookies++;
< error = uiomove((char *) rootdots + uio->uio_offset,
< n * sizeof(struct direntry), uio);
1529,1533c1652,1658
< while (!error && uio->uio_resid > 0) {
< lbn = (uio->uio_offset - bias) >> pmp->pm_cnshift;
< on = (uio->uio_offset - bias) & pmp->pm_crbomask;
< n = min((u_long) (pmp->pm_bpcluster - on), uio->uio_resid);
< diff = dep->de_FileSize - (uio->uio_offset - bias);
---
>
> off = offset;
> while (uio->uio_resid > 0) {
> lbn = de_cluster(pmp, offset - bias);
> on = (offset - bias) & pmp->pm_crbomask;
> n = min(pmp->pm_bpcluster - on, uio->uio_resid);
> diff = dep->de_FileSize - (offset - bias);
1536,1538c1661,1662
< if (diff < n)
< n = diff;
< error = pcbmap(dep, lbn, &bn, &cn);
---
> n = min(n, diff);
> error = pcbmap(dep, lbn, &bn, &cn, &blsize);
1541,1542c1665
< error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster, NOCRED, &bp);
< n = min(n, pmp->pm_bpcluster - bp->b_resid);
---
> error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp);
1545c1668
< return error;
---
> return (error);
1546a1670
> n = min(n, blsize - bp->b_resid);
1549,1550c1673,1674
< * code to convert from dos directory entries to ufs
< * directory entries
---
> * Convert from dos directory entries to fs-independent
> * directory entries.
1552,1556c1676,1682
< pushout = 0;
< dentp = (struct direntry *)(bp->b_data + on);
< prev = 0;
< crnt = (struct dirent *) dirbuf;
< while ((char *) dentp < bp->b_data + on + n) {
---
> for (dentp = (struct direntry *)(bp->b_data + on);
> (char *)dentp < bp->b_data + on + n;
> dentp++, offset += sizeof(struct direntry)) {
> #if 0
> printf("rd: dentp %08x prev %08x crnt %08x deName %02x attr %02x\n",
> dentp, prev, crnt, dentp->deName[0], dentp->deAttributes);
> #endif
1558,1559c1684
< * printf("rd: dentp %08x prev %08x crnt %08x deName %02x attr %02x\n",
< * dentp, prev, crnt, dentp->deName[0], dentp->deAttributes);
---
> * If this is an unused entry, we can stop.
1560a1686,1689
> if (dentp->deName[0] == SLOT_EMPTY) {
> brelse(bp);
> goto out;
> }
1562,1566c1691
< * If we have an empty entry or a slot from a
< * deleted file, or a volume label entry just
< * concatenate its space onto the end of the
< * previous entry or, manufacture an empty entry if
< * there is no previous entry.
---
> * Skip deleted entries.
1568,1615c1693,1695
< if (dentp->deName[0] == SLOT_EMPTY ||
< dentp->deName[0] == SLOT_DELETED ||
< (dentp->deAttributes & ATTR_VOLUME)) {
< if (prev) {
< prev->d_reclen += sizeof(struct direntry);
< } else {
< prev = crnt;
< prev->d_fileno = 0;
< prev->d_reclen = sizeof(struct direntry);
< prev->d_type = DT_UNKNOWN;
< prev->d_namlen = 0;
< prev->d_name[0] = 0;
< ncookies++;
< }
< } else {
< /*
< * this computation of d_fileno must match
< * the computation of va_fileid in
< * msdosfs_getattr
< */
< if (dentp->deAttributes & ATTR_DIRECTORY) {
< /* if this is the root directory */
< fileno = getushort(dentp->deStartCluster);
< if (fileno == MSDOSFSROOT)
< fileno = 1;
< } else {
< /*
< * if the file's dirent lives in
< * root dir
< */
< if ((fileno = cn) == MSDOSFSROOT)
< fileno = 1;
< fileno = (fileno << 16) |
< ((dentp - (struct direntry *) bp->b_data) & 0xffff);
< }
< crnt->d_fileno = fileno;
< crnt->d_reclen = sizeof(struct direntry);
< crnt->d_type = (dentp->deAttributes & ATTR_DIRECTORY)
< ? DT_DIR : DT_REG;
< crnt->d_namlen = dos2unixfn(dentp->deName,
< (u_char *)crnt->d_name);
< /*
< * printf("readdir: file %s, fileno %08x, attr %02x, start %08x\n",
< * crnt->d_name, crnt->d_fileno, dentp->deAttributes,
< * dentp->deStartCluster);
< */
< prev = crnt;
< ncookies++;
---
> if (dentp->deName[0] == SLOT_DELETED) {
> chksum = -1;
> continue;
1617d1696
< dentp++;
1619,1620c1698,1706
< crnt = (struct dirent *) ((char *) crnt + sizeof(struct direntry));
< pushout = 1;
---
> /*
> * Handle Win95 long directory entries
> */
> if (dentp->deAttributes == ATTR_WIN95) {
> if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
> continue;
> chksum = win2unixfn((struct winentry *)dentp, &dirbuf, chksum);
> continue;
> }
1623,1629c1709
< * If our intermediate buffer is full then copy its
< * contents to user space. I would just use the
< * buffer the buf header points to but, I'm afraid
< * that when we brelse() it someone else might find
< * it in the cache and think its contents are
< * valid. Maybe there is a way to invalidate the
< * buffer before brelse()'ing it.
---
> * Skip volume labels
1631,1637c1711,1713
< if ((u_char *) crnt >= &dirbuf[sizeof dirbuf]) {
< pushout = 0;
< error = uiomove(dirbuf, sizeof(dirbuf), uio);
< if (error)
< break;
< prev = 0;
< crnt = (struct dirent *) dirbuf;
---
> if (dentp->deAttributes & ATTR_VOLUME) {
> chksum = -1;
> continue;
1638a1715,1765
> /*
> * This computation of d_fileno must match
> * the computation of va_fileid in
> * msdosfs_getattr.
> */
> if (dentp->deAttributes & ATTR_DIRECTORY) {
> fileno = getushort(dentp->deStartCluster);
> if (FAT32(pmp))
> fileno |= getushort(dentp->deHighClust) << 16;
> /* if this is the root directory */
> if (fileno == MSDOSFSROOT)
> if (FAT32(pmp))
> fileno = cntobn(pmp,
> pmp->pm_rootdirblk)
> * dirsperblk;
> else
> fileno = 1;
> else
> fileno = cntobn(pmp, fileno) * dirsperblk;
> dirbuf.d_fileno = fileno;
> dirbuf.d_type = DT_DIR;
> } else {
> dirbuf.d_fileno = offset / sizeof(struct direntry);
> dirbuf.d_type = DT_REG;
> }
> if (chksum != winChksum(dentp->deName))
> dirbuf.d_namlen = dos2unixfn(dentp->deName,
> (u_char *)dirbuf.d_name,
> pmp->pm_flags & MSDOSFSMNT_SHORTNAME);
> else
> dirbuf.d_name[dirbuf.d_namlen] = 0;
> chksum = -1;
> dirbuf.d_reclen = GENERIC_DIRSIZ(&dirbuf);
> if (uio->uio_resid < dirbuf.d_reclen) {
> brelse(bp);
> goto out;
> }
> error = uiomove((caddr_t) &dirbuf,
> dirbuf.d_reclen, uio);
> if (error) {
> brelse(bp);
> goto out;
> }
> if (cookies) {
> *cookies++ = off;
> off = offset + sizeof(struct direntry);
> if (--ncookies <= 0) {
> brelse(bp);
> goto out;
> }
> }
1640,1655d1766
< if (pushout) {
< pushout = 0;
< error = uiomove(dirbuf, (char *) crnt - (char *) dirbuf,
< uio);
< }
<
< #if 0
< /*
< * If we have read everything from this block or have read
< * to end of file then we are done with this block. Mark
< * it to say the buffer can be reused if need be.
< */
< if (n + on == pmp->pm_bpcluster ||
< (uio->uio_offset - bias) == dep->de_FileSize)
< bp->b_flags |= B_AGE;
< #endif /* if 0 */
1657,1658d1767
< if (n == 0)
< break;
1660c1769,1774
< out: ;
---
> out:
> /* Subtract unused cookies */
> if (ap->a_ncookies)
> *ap->a_ncookies -= ncookies;
>
> uio->uio_offset = offset;
1662,1667d1775
< if (!error && ap->a_ncookies != NULL) {
< struct dirent* dpStart;
< struct dirent* dpEnd;
< struct dirent* dp;
< u_long *cookies;
< u_long *cookiep;
1669,1684d1776
< if (uio->uio_segflg != UIO_SYSSPACE || uio->uio_iovcnt != 1)
< panic("msdosfs_readdir: unexpected uio from NFS server");
< dpStart = (struct dirent *)
< (uio->uio_iov->iov_base - (uio->uio_offset - off));
< dpEnd = (struct dirent *) uio->uio_iov->iov_base;
< cookies = malloc(ncookies * sizeof(*cookies), M_TEMP, M_WAITOK);
< for (dp = dpStart, cookiep = cookies;
< dp < dpEnd;
< dp = (struct dirent *)((caddr_t) dp + dp->d_reclen)) {
< off += dp->d_reclen;
< *cookiep++ = (u_long) off;
< }
< *ap->a_ncookies = ncookies;
< *ap->a_cookies = cookies;
< }
<
1689c1781
< if (dep->de_FileSize - (uio->uio_offset - bias) <= 0)
---
> if (dep->de_FileSize - (offset - bias) <= 0)
1694c1786
< return error;
---
> return (error);
1706c1798
< return 0;
---
> return (0);
1727a1820
> struct msdosfsmount *pmp = dep->de_pmp;
1732c1825
< return 0;
---
> return (0);
1742c1835
< return pcbmap(dep, ap->a_bn, ap->a_bnp, 0);
---
> return (pcbmap(dep, de_bn2cn(pmp, ap->a_bn), ap->a_bnp, 0, 0));
1765,1769c1858,1867
< error = pcbmap(dep, bp->b_lblkno, &bp->b_blkno, 0);
< if (error)
< bp->b_blkno = -1;
< if (bp->b_blkno == -1)
< clrbuf(bp);
---
> error = pcbmap(dep, de_bn2cn(dep->de_pmp, bp->b_lblkno),
> &bp->b_blkno, 0, 0);
> if (error) {
> bp->b_error = error;
> bp->b_flags |= B_ERROR;
> biodone(bp);
> return (error);
> }
> if ((long)bp->b_blkno == -1)
> vfs_bio_clrbuf(bp);
1773c1871
< return error;
---
> return (0);
1775,1776d1872
< #ifdef DIAGNOSTIC
< #endif
1784c1880
< return 0;
---
> return (0);
1801c1897
< return 0;
---
> return (0);
1811a1908,1909
> struct msdosfsmount *pmp = VTODE(ap->a_vp)->de_pmp;
>
1815c1913
< return 0;
---
> return (0);
1817,1818c1915,1916
< *ap->a_retval = 12;
< return 0;
---
> *ap->a_retval = pmp->pm_flags & MSDOSFSMNT_LONGNAME ? WIN_MAXLEN : 12;
> return (0);
1820,1821c1918,1919
< *ap->a_retval = PATH_MAX; /* 255? */
< return 0;
---
> *ap->a_retval = PATH_MAX;
> return (0);
1824c1922
< return 0;
---
> return (0);
1827c1925
< return 0;
---
> return (0);
1829c1927
< return EINVAL;
---
> return (EINVAL);
1830a1929
> /* NOTREACHED */