[BACK]Return to msdosfs_vnops.c CVS log [TXT][DIR] Up to [local] / sys / msdosfs

Annotation of sys/msdosfs/msdosfs_vnops.c, Revision 1.1.1.1

1.1       nbrk        1: /*     $OpenBSD: msdosfs_vnops.c,v 1.64 2007/06/02 02:04:21 deraadt Exp $      */
                      2: /*     $NetBSD: msdosfs_vnops.c,v 1.63 1997/10/17 11:24:19 ws Exp $    */
                      3:
                      4: /*-
                      5:  * Copyright (C) 2005 Thomas Wang.
                      6:  * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
                      7:  * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
                      8:  * All rights reserved.
                      9:  * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
                     10:  *
                     11:  * Redistribution and use in source and binary forms, with or without
                     12:  * modification, are permitted provided that the following conditions
                     13:  * are met:
                     14:  * 1. Redistributions of source code must retain the above copyright
                     15:  *    notice, this list of conditions and the following disclaimer.
                     16:  * 2. Redistributions in binary form must reproduce the above copyright
                     17:  *    notice, this list of conditions and the following disclaimer in the
                     18:  *    documentation and/or other materials provided with the distribution.
                     19:  * 3. All advertising materials mentioning features or use of this software
                     20:  *    must display the following acknowledgement:
                     21:  *     This product includes software developed by TooLs GmbH.
                     22:  * 4. The name of TooLs GmbH may not be used to endorse or promote products
                     23:  *    derived from this software without specific prior written permission.
                     24:  *
                     25:  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
                     26:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
                     27:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
                     28:  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
                     29:  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
                     30:  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
                     31:  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
                     32:  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
                     33:  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
                     34:  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
                     35:  */
                     36: /*
                     37:  * Written by Paul Popelka (paulp@uts.amdahl.com)
                     38:  *
                     39:  * You can do anything you want with this software, just don't say you wrote
                     40:  * it, and don't remove this notice.
                     41:  *
                     42:  * This software is provided "as is".
                     43:  *
                     44:  * The author supplies this software to be publicly redistributed on the
                     45:  * understanding that the author is not responsible for the correct
                     46:  * functioning of this software in any circumstances and is not liable for
                     47:  * any damages caused by this software.
                     48:  *
                     49:  * October 1992
                     50:  */
                     51:
                     52: #include <sys/param.h>
                     53: #include <sys/systm.h>
                     54: #include <sys/namei.h>
                     55: #include <sys/resourcevar.h>   /* defines plimit structure in proc struct */
                     56: #include <sys/kernel.h>
                     57: #include <sys/file.h>          /* define FWRITE ... */
                     58: #include <sys/stat.h>
                     59: #include <sys/buf.h>
                     60: #include <sys/proc.h>
                     61: #include <sys/mount.h>
                     62: #include <sys/vnode.h>
                     63: #include <sys/signalvar.h>
                     64: #include <miscfs/specfs/specdev.h> /* XXX */   /* defines v_rdev */
                     65: #include <sys/malloc.h>
                     66: #include <sys/pool.h>
                     67: #include <sys/dirent.h>                /* defines dirent structure */
                     68: #include <sys/lockf.h>
                     69: #include <sys/poll.h>
                     70:
                     71: #include <uvm/uvm_extern.h>
                     72:
                     73: #include <msdosfs/bpb.h>
                     74: #include <msdosfs/direntry.h>
                     75: #include <msdosfs/denode.h>
                     76: #include <msdosfs/msdosfsmount.h>
                     77: #include <msdosfs/fat.h>
                     78:
                     79: static uint32_t fileidhash(uint64_t);
                     80:
                     81: /*
                     82:  * Some general notes:
                     83:  *
                     84:  * In the ufs filesystem the inodes, superblocks, and indirect blocks are
                     85:  * read/written using the vnode for the filesystem. Blocks that represent
                     86:  * the contents of a file are read/written using the vnode for the file
                     87:  * (including directories when they are read/written as files). This
                     88:  * presents problems for the dos filesystem because data that should be in
                     89:  * an inode (if dos had them) resides in the directory itself.  Since we
                     90:  * must update directory entries without the benefit of having the vnode
                     91:  * for the directory we must use the vnode for the filesystem.  This means
                     92:  * that when a directory is actually read/written (via read, write, or
                     93:  * readdir, or seek) we must use the vnode for the filesystem instead of
                     94:  * the vnode for the directory as would happen in ufs. This is to insure we
                     95:  * retrieve the correct block from the buffer cache since the hash value is
                     96:  * based upon the vnode address and the desired block number.
                     97:  */
                     98:
                     99: /*
                    100:  * Create a regular file. On entry the directory to contain the file being
                    101:  * created is locked.  We must release before we return. We must also free
                    102:  * the pathname buffer pointed at by cnp->cn_pnbuf, always on error, or
                    103:  * only if the SAVESTART bit in cn_flags is clear on success.
                    104:  */
                    105: int
                    106: msdosfs_create(v)
                    107:        void *v;
                    108: {
                    109:        struct vop_create_args *ap = v;
                    110:        struct componentname *cnp = ap->a_cnp;
                    111:        struct denode ndirent;
                    112:        struct denode *dep;
                    113:        struct denode *pdep = VTODE(ap->a_dvp);
                    114:        int error;
                    115:        struct timespec ts;
                    116:
                    117: #ifdef MSDOSFS_DEBUG
                    118:        printf("msdosfs_create(cnp %08x, vap %08x\n", cnp, ap->a_vap);
                    119: #endif
                    120:
                    121:        /*
                    122:         * If this is the root directory and there is no space left we
                    123:         * can't do anything.  This is because the root directory can not
                    124:         * change size.
                    125:         */
                    126:        if (pdep->de_StartCluster == MSDOSFSROOT
                    127:            && pdep->de_fndoffset >= pdep->de_FileSize) {
                    128:                error = ENOSPC;
                    129:                goto bad;
                    130:        }
                    131:
                    132:        /*
                    133:         * Create a directory entry for the file, then call createde() to
                    134:         * have it installed. NOTE: DOS files are always executable.  We
                    135:         * use the absence of the owner write bit to make the file
                    136:         * readonly.
                    137:         */
                    138: #ifdef DIAGNOSTIC
                    139:        if ((cnp->cn_flags & HASBUF) == 0)
                    140:                panic("msdosfs_create: no name");
                    141: #endif
                    142:        bzero(&ndirent, sizeof(ndirent));
                    143:        if ((error = uniqdosname(pdep, cnp, ndirent.de_Name)) != 0)
                    144:                goto bad;
                    145:
                    146:        ndirent.de_Attributes = (ap->a_vap->va_mode & VWRITE) ?
                    147:                                ATTR_ARCHIVE : ATTR_ARCHIVE | ATTR_READONLY;
                    148:        ndirent.de_StartCluster = 0;
                    149:        ndirent.de_FileSize = 0;
                    150:        ndirent.de_dev = pdep->de_dev;
                    151:        ndirent.de_devvp = pdep->de_devvp;
                    152:        ndirent.de_pmp = pdep->de_pmp;
                    153:        ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE;
                    154:        getnanotime(&ts);
                    155:        DETIMES(&ndirent, &ts, &ts, &ts);
                    156:        if ((error = createde(&ndirent, pdep, &dep, cnp)) != 0)
                    157:                goto bad;
                    158:        if ((cnp->cn_flags & SAVESTART) == 0)
                    159:                pool_put(&namei_pool, cnp->cn_pnbuf);
                    160:        vput(ap->a_dvp);
                    161:        *ap->a_vpp = DETOV(dep);
                    162:        return (0);
                    163:
                    164: bad:
                    165:        pool_put(&namei_pool, cnp->cn_pnbuf);
                    166:        vput(ap->a_dvp);
                    167:        return (error);
                    168: }
                    169:
                    170: int
                    171: msdosfs_mknod(v)
                    172:        void *v;
                    173: {
                    174:        struct vop_mknod_args *ap = v;
                    175:
                    176:        pool_put(&namei_pool, ap->a_cnp->cn_pnbuf);
                    177:        vput(ap->a_dvp);
                    178:        return (EINVAL);
                    179: }
                    180:
                    181: int
                    182: msdosfs_open(v)
                    183:        void *v;
                    184: {
                    185: #if 0
                    186:        struct vop_open_args /* {
                    187:                struct vnode *a_vp;
                    188:                int a_mode;
                    189:                struct ucred *a_cred;
                    190:                struct proc *a_p;
                    191:        } */ *ap;
                    192: #endif
                    193:
                    194:        return (0);
                    195: }
                    196:
                    197: int
                    198: msdosfs_close(v)
                    199:        void *v;
                    200: {
                    201:        struct vop_close_args *ap = v;
                    202:        struct vnode *vp = ap->a_vp;
                    203:        struct denode *dep = VTODE(vp);
                    204:        struct timespec ts;
                    205:
                    206:        if (vp->v_usecount > 1 && !VOP_ISLOCKED(vp)) {
                    207:                getnanotime(&ts);
                    208:                DETIMES(dep, &ts, &ts, &ts);
                    209:        }
                    210:        return (0);
                    211: }
                    212:
                    213: int
                    214: msdosfs_access(v)
                    215:        void *v;
                    216: {
                    217:        struct vop_access_args *ap = v;
                    218:        struct denode *dep = VTODE(ap->a_vp);
                    219:        struct msdosfsmount *pmp = dep->de_pmp;
                    220:        mode_t dosmode;
                    221:
                    222:        dosmode = (S_IXUSR|S_IXGRP|S_IXOTH) | (S_IRUSR|S_IRGRP|S_IROTH);
                    223:        if ((dep->de_Attributes & ATTR_READONLY) == 0)
                    224:                dosmode |= (S_IWUSR|S_IWGRP|S_IWOTH);
                    225:        dosmode &= pmp->pm_mask;
                    226:        if (dep->de_Attributes & ATTR_DIRECTORY
                    227:            && pmp->pm_flags & MSDOSFSMNT_ALLOWDIRX) {
                    228:                dosmode |= (dosmode & S_IRUSR) ? S_IXUSR : 0;
                    229:                dosmode |= (dosmode & S_IRGRP) ? S_IXGRP : 0;
                    230:                dosmode |= (dosmode & S_IROTH) ? S_IXOTH : 0;
                    231:        }
                    232:
                    233:        return (vaccess(dosmode, pmp->pm_uid, pmp->pm_gid, ap->a_mode,
                    234:            ap->a_cred));
                    235: }
                    236:
                    237: int
                    238: msdosfs_getattr(v)
                    239:        void *v;
                    240: {
                    241:        struct vop_getattr_args *ap = v;
                    242:        struct denode *dep = VTODE(ap->a_vp);
                    243:        struct msdosfsmount *pmp = dep->de_pmp;
                    244:        struct vattr *vap = ap->a_vap;
                    245:        struct timespec ts;
                    246:        uint32_t fileid;
                    247:
                    248:        getnanotime(&ts);
                    249:        DETIMES(dep, &ts, &ts, &ts);
                    250:        vap->va_fsid = dep->de_dev;
                    251:
                    252:        /*
                    253:         * The following computation of the fileid must be the same as
                    254:         * that used in msdosfs_readdir() to compute d_fileno. If not,
                    255:         * pwd doesn't work.
                    256:         *
                    257:         * We now use the starting cluster number as the fileid/fileno.
                    258:         * This works for both files and directories (including the root
                    259:         * directory, on FAT32).  Even on FAT32, this will at most be a
                    260:         * 28-bit number, as the high 4 bits of FAT32 cluster numbers
                    261:         * are reserved.
                    262:         *
                    263:         * However, we do need to do something for 0-length files, which
                    264:         * will not have a starting cluster number.
                    265:         *
                    266:         * These files cannot be directories, since (except for /, which
                    267:         * is special-cased anyway) directories contain entries for . and
                    268:         * .., so must have non-zero length.
                    269:         *
                    270:         * In this case, we just create a non-cryptographic hash of the
                    271:         * original fileid calculation, and set the top bit.
                    272:         *
                    273:         * This algorithm has the benefit that all directories, and all
                    274:         * non-zero-length files, will have fileids that are persistent
                    275:         * across mounts and reboots, and that cannot collide (as long
                    276:         * as the filesystem is not corrupt).  Zero-length files will
                    277:         * have fileids that are persistent, but that may collide.  We
                    278:         * will just have to live with that.
                    279:         */
                    280:        fileid = dep->de_StartCluster;
                    281:
                    282:        if (dep->de_Attributes & ATTR_DIRECTORY) {
                    283:                /* Special-case root */
                    284:                if (dep->de_StartCluster == MSDOSFSROOT)
                    285:                        fileid = FAT32(pmp) ? pmp->pm_rootdirblk : 1;
                    286:        } else {
                    287:                if (dep->de_FileSize == 0) {
                    288:                        uint32_t dirsperblk;
                    289:                        uint64_t fileid64;
                    290:
                    291:                        dirsperblk = pmp->pm_BytesPerSec /
                    292:                            sizeof(struct direntry);
                    293:
                    294:                        fileid64 = (dep->de_dirclust == MSDOSFSROOT) ?
                    295:                            roottobn(pmp, 0) : cntobn(pmp, dep->de_dirclust);
                    296:                        fileid64 *= dirsperblk;
                    297:                        fileid64 += dep->de_diroffset / sizeof(struct direntry);
                    298:
                    299:                        fileid = fileidhash(fileid64);
                    300:                }
                    301:        }
                    302:
                    303:        vap->va_fileid = fileid;
                    304:        vap->va_mode = (S_IXUSR|S_IXGRP|S_IXOTH) | (S_IRUSR|S_IRGRP|S_IROTH) |
                    305:            ((dep->de_Attributes & ATTR_READONLY) ? 0 : (S_IWUSR|S_IWGRP|S_IWOTH));
                    306:        vap->va_mode &= dep->de_pmp->pm_mask;
                    307:        if (dep->de_Attributes & ATTR_DIRECTORY) {
                    308:                vap->va_mode |= S_IFDIR;
                    309:                if (pmp->pm_flags & MSDOSFSMNT_ALLOWDIRX) {
                    310:                        vap->va_mode |= (vap->va_mode & S_IRUSR) ? S_IXUSR : 0;
                    311:                        vap->va_mode |= (vap->va_mode & S_IRGRP) ? S_IXGRP : 0;
                    312:                        vap->va_mode |= (vap->va_mode & S_IROTH) ? S_IXOTH : 0;
                    313:                }
                    314:        }
                    315:        vap->va_nlink = 1;
                    316:        vap->va_gid = dep->de_pmp->pm_gid;
                    317:        vap->va_uid = dep->de_pmp->pm_uid;
                    318:        vap->va_rdev = 0;
                    319:        vap->va_size = dep->de_FileSize;
                    320:        dos2unixtime(dep->de_MDate, dep->de_MTime, 0, &vap->va_mtime);
                    321:        if (dep->de_pmp->pm_flags & MSDOSFSMNT_LONGNAME) {
                    322:                dos2unixtime(dep->de_ADate, 0, 0, &vap->va_atime);
                    323:                dos2unixtime(dep->de_CDate, dep->de_CTime, dep->de_CTimeHundredth, &vap->va_ctime);
                    324:        } else {
                    325:                vap->va_atime = vap->va_mtime;
                    326:                vap->va_ctime = vap->va_mtime;
                    327:        }
                    328:        vap->va_flags = 0;
                    329:        if ((dep->de_Attributes & ATTR_ARCHIVE) == 0)
                    330:                vap->va_flags |= SF_ARCHIVED;
                    331:        vap->va_gen = 0;
                    332:        vap->va_blocksize = dep->de_pmp->pm_bpcluster;
                    333:        vap->va_bytes = (dep->de_FileSize + dep->de_pmp->pm_crbomask) &
                    334:                                ~(dep->de_pmp->pm_crbomask);
                    335:        vap->va_type = ap->a_vp->v_type;
                    336:        return (0);
                    337: }
                    338:
                    339: int
                    340: msdosfs_setattr(v)
                    341:        void *v;
                    342: {
                    343:        struct vop_setattr_args *ap = v;
                    344:        int error = 0;
                    345:        struct denode *dep = VTODE(ap->a_vp);
                    346:        struct vattr *vap = ap->a_vap;
                    347:        struct ucred *cred = ap->a_cred;
                    348:
                    349: #ifdef MSDOSFS_DEBUG
                    350:        printf("msdosfs_setattr(): vp %08x, vap %08x, cred %08x, p %08x\n",
                    351:            ap->a_vp, vap, cred, ap->a_p);
                    352: #endif
                    353:        if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
                    354:            (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
                    355:            (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
                    356:            (vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL) ||
                    357:            (vap->va_uid != VNOVAL) || (vap->va_gid != VNOVAL)) {
                    358: #ifdef MSDOSFS_DEBUG
                    359:                printf("msdosfs_setattr(): returning EINVAL\n");
                    360:                printf("    va_type %d, va_nlink %x, va_fsid %x, va_fileid %x\n",
                    361:                    vap->va_type, vap->va_nlink, vap->va_fsid, vap->va_fileid);
                    362:                printf("    va_blocksize %x, va_rdev %x, va_bytes %x, va_gen %x\n",
                    363:                    vap->va_blocksize, vap->va_rdev, vap->va_bytes, vap->va_gen);
                    364:                printf("    va_uid %x, va_gid %x\n",
                    365:                    vap->va_uid, vap->va_gid);
                    366: #endif
                    367:                return (EINVAL);
                    368:        }
                    369:        /*
                    370:         * Directories must not ever get their attributes modified
                    371:         */
                    372:        if (ap->a_vp->v_type == VDIR)
                    373:                return EISDIR;
                    374:
                    375:        if (vap->va_size != VNOVAL) {
                    376:                error = detrunc(dep, (uint32_t)vap->va_size, 0, cred, ap->a_p);
                    377:                if (error)
                    378:                        return (error);
                    379:        }
                    380:        if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
                    381:                if (cred->cr_uid != dep->de_pmp->pm_uid &&
                    382:                    (error = suser_ucred(cred)) &&
                    383:                    ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
                    384:                    (error = VOP_ACCESS(ap->a_vp, VWRITE, cred, ap->a_p))))
                    385:                        return (error);
                    386:                if (!(dep->de_pmp->pm_flags & MSDOSFSMNT_NOWIN95)
                    387:                    && vap->va_atime.tv_sec != VNOVAL)
                    388:                        unix2dostime(&vap->va_atime, &dep->de_ADate, NULL, NULL);
                    389:                if (vap->va_mtime.tv_sec != VNOVAL)
                    390:                        unix2dostime(&vap->va_mtime, &dep->de_MDate, &dep->de_MTime, NULL);
                    391:                dep->de_Attributes |= ATTR_ARCHIVE;
                    392:                dep->de_flag |= DE_MODIFIED;
                    393:        }
                    394:        /*
                    395:         * DOS files only have the ability to have their writability
                    396:         * attribute set, so we use the owner write bit to set the readonly
                    397:         * attribute.
                    398:         */
                    399:        if (vap->va_mode != (mode_t)VNOVAL) {
                    400:                if (cred->cr_uid != dep->de_pmp->pm_uid &&
                    401:                    (error = suser_ucred(cred)))
                    402:                        return (error);
                    403:                /* We ignore the read and execute bits. */
                    404:                if (vap->va_mode & VWRITE)
                    405:                        dep->de_Attributes &= ~ATTR_READONLY;
                    406:                else
                    407:                        dep->de_Attributes |= ATTR_READONLY;
                    408:                dep->de_flag |= DE_MODIFIED;
                    409:        }
                    410:        /*
                    411:         * Allow the `archived' bit to be toggled.
                    412:         */
                    413:        if (vap->va_flags != VNOVAL) {
                    414:                if (cred->cr_uid != dep->de_pmp->pm_uid &&
                    415:                    (error = suser_ucred(cred)))
                    416:                        return (error);
                    417:                if (vap->va_flags & SF_ARCHIVED)
                    418:                        dep->de_Attributes &= ~ATTR_ARCHIVE;
                    419:                else
                    420:                        dep->de_Attributes |= ATTR_ARCHIVE;
                    421:                dep->de_flag |= DE_MODIFIED;
                    422:        }
                    423:        return (deupdat(dep, 1));
                    424: }
                    425:
                    426: int
                    427: msdosfs_read(v)
                    428:        void *v;
                    429: {
                    430:        struct vop_read_args *ap = v;
                    431:        int error = 0;
                    432:        uint32_t diff;
                    433:        int blsize;
                    434:        int isadir;
                    435:        uint32_t n;
                    436:        long on;
                    437:        daddr64_t lbn, rablock, rablkno;
                    438:        struct buf *bp;
                    439:        struct vnode *vp = ap->a_vp;
                    440:        struct denode *dep = VTODE(vp);
                    441:        struct msdosfsmount *pmp = dep->de_pmp;
                    442:        struct uio *uio = ap->a_uio;
                    443:
                    444:        /*
                    445:         * If they didn't ask for any data, then we are done.
                    446:         */
                    447:        if (uio->uio_resid == 0)
                    448:                return (0);
                    449:        if (uio->uio_offset < 0)
                    450:                return (EINVAL);
                    451:
                    452:        isadir = dep->de_Attributes & ATTR_DIRECTORY;
                    453:        do {
                    454:                if (uio->uio_offset >= dep->de_FileSize)
                    455:                        return (0);
                    456:
                    457:                lbn = de_cluster(pmp, uio->uio_offset);
                    458:                on = uio->uio_offset & pmp->pm_crbomask;
                    459:                n = min((uint32_t) (pmp->pm_bpcluster - on), uio->uio_resid);
                    460:
                    461:                /*
                    462:                 * de_FileSize is uint32_t, and we know that uio_offset <
                    463:                 * de_FileSize, so uio->uio_offset < 2^32.  Therefore
                    464:                 * the cast to uint32_t on the next line is safe.
                    465:                 */
                    466:                diff = dep->de_FileSize - (uint32_t)uio->uio_offset;
                    467:                if (diff < n)
                    468:                        n = diff;
                    469:
                    470:                /* convert cluster # to block # if a directory */
                    471:                if (isadir) {
                    472:                        error = pcbmap(dep, lbn, &lbn, 0, &blsize);
                    473:                        if (error)
                    474:                                return (error);
                    475:                }
                    476:                /*
                    477:                 * If we are operating on a directory file then be sure to
                    478:                 * do i/o with the vnode for the filesystem instead of the
                    479:                 * vnode for the directory.
                    480:                 */
                    481:                if (isadir) {
                    482:                        error = bread(pmp->pm_devvp, lbn, blsize, NOCRED, &bp);
                    483:                } else {
                    484:                        rablock = lbn + 1;
                    485:                        rablkno = de_cn2bn(pmp, rablock);
                    486:                        if (dep->de_lastr + 1 == lbn &&
                    487:                            de_cn2off(pmp, rablock) < dep->de_FileSize)
                    488:                                error = breadn(vp, de_cn2bn(pmp, lbn),
                    489:                                    pmp->pm_bpcluster, &rablkno,
                    490:                                    &pmp->pm_bpcluster, 1, NOCRED, &bp);
                    491:                        else
                    492:                                error = bread(vp, de_cn2bn(pmp, lbn),
                    493:                                    pmp->pm_bpcluster, NOCRED, &bp);
                    494:                        dep->de_lastr = lbn;
                    495:                }
                    496:                n = min(n, pmp->pm_bpcluster - bp->b_resid);
                    497:                if (error) {
                    498:                        brelse(bp);
                    499:                        return (error);
                    500:                }
                    501:                error = uiomove(bp->b_data + on, (int) n, uio);
                    502:                brelse(bp);
                    503:        } while (error == 0 && uio->uio_resid > 0 && n != 0);
                    504:        if (!isadir && !(vp->v_mount->mnt_flag & MNT_NOATIME))
                    505:                dep->de_flag |= DE_ACCESS;
                    506:        return (error);
                    507: }
                    508:
                    509: /*
                    510:  * Write data to a file or directory.
                    511:  */
                    512: int
                    513: msdosfs_write(v)
                    514:        void *v;
                    515: {
                    516:        struct vop_write_args *ap = v;
                    517:        int n;
                    518:        int croffset;
                    519:        int resid;
                    520:        uint32_t osize;
                    521:        int error = 0;
                    522:        uint32_t count, lastcn;
                    523:        daddr64_t bn;
                    524:        struct buf *bp;
                    525:        int ioflag = ap->a_ioflag;
                    526:        struct uio *uio = ap->a_uio;
                    527:        struct proc *p = uio->uio_procp;
                    528:        struct vnode *vp = ap->a_vp;
                    529:        struct vnode *thisvp;
                    530:        struct denode *dep = VTODE(vp);
                    531:        struct msdosfsmount *pmp = dep->de_pmp;
                    532:        struct ucred *cred = ap->a_cred;
                    533:
                    534: #ifdef MSDOSFS_DEBUG
                    535:        printf("msdosfs_write(vp %08x, uio %08x, ioflag %08x, cred %08x\n",
                    536:            vp, uio, ioflag, cred);
                    537:        printf("msdosfs_write(): diroff %d, dirclust %d, startcluster %d\n",
                    538:            dep->de_diroffset, dep->de_dirclust, dep->de_StartCluster);
                    539: #endif
                    540:
                    541:        switch (vp->v_type) {
                    542:        case VREG:
                    543:                if (ioflag & IO_APPEND)
                    544:                        uio->uio_offset = dep->de_FileSize;
                    545:                thisvp = vp;
                    546:                break;
                    547:        case VDIR:
                    548:                return EISDIR;
                    549:        default:
                    550:                panic("msdosfs_write(): bad file type");
                    551:        }
                    552:
                    553:        if (uio->uio_offset < 0)
                    554:                return (EINVAL);
                    555:
                    556:        if (uio->uio_resid == 0)
                    557:                return (0);
                    558:
                    559:        /* Don't bother to try to write files larger than the f/s limit */
                    560:        if (uio->uio_offset + uio->uio_resid > MSDOSFS_FILESIZE_MAX)
                    561:                return (EFBIG);
                    562:
                    563:        /*
                    564:         * If they've exceeded their filesize limit, tell them about it.
                    565:         */
                    566:        if (p &&
                    567:            ((uio->uio_offset + uio->uio_resid) >
                    568:            p->p_rlimit[RLIMIT_FSIZE].rlim_cur)) {
                    569:                psignal(p, SIGXFSZ);
                    570:                return (EFBIG);
                    571:        }
                    572:
                    573:        /*
                    574:         * If the offset we are starting the write at is beyond the end of
                    575:         * the file, then they've done a seek.  Unix filesystems allow
                    576:         * files with holes in them, DOS doesn't so we must fill the hole
                    577:         * with zeroed blocks.
                    578:         */
                    579:        if (uio->uio_offset > dep->de_FileSize) {
                    580:                if ((error = deextend(dep, uio->uio_offset, cred)) != 0)
                    581:                        return (error);
                    582:        }
                    583:
                    584:        /*
                    585:         * Remember some values in case the write fails.
                    586:         */
                    587:        resid = uio->uio_resid;
                    588:        osize = dep->de_FileSize;
                    589:
                    590:        /*
                    591:         * If we write beyond the end of the file, extend it to its ultimate
                    592:         * size ahead of the time to hopefully get a contiguous area.
                    593:         */
                    594:        if (uio->uio_offset + resid > osize) {
                    595:                count = de_clcount(pmp, uio->uio_offset + resid) -
                    596:                        de_clcount(pmp, osize);
                    597:                if ((error = extendfile(dep, count, NULL, NULL, 0)) &&
                    598:                    (error != ENOSPC || (ioflag & IO_UNIT)))
                    599:                        goto errexit;
                    600:                lastcn = dep->de_fc[FC_LASTFC].fc_frcn;
                    601:        } else
                    602:                lastcn = de_clcount(pmp, osize) - 1;
                    603:
                    604:        do {
                    605:                if (de_cluster(pmp, uio->uio_offset) > lastcn) {
                    606:                        error = ENOSPC;
                    607:                        break;
                    608:                }
                    609:
                    610:                bn = de_blk(pmp, uio->uio_offset);
                    611:                if ((uio->uio_offset & pmp->pm_crbomask) == 0
                    612:                    && (de_blk(pmp, uio->uio_offset + uio->uio_resid) > de_blk(pmp, uio->uio_offset)
                    613:                        || uio->uio_offset + uio->uio_resid >= dep->de_FileSize)) {
                    614:                        /*
                    615:                         * If either the whole cluster gets written,
                    616:                         * or we write the cluster from its start beyond EOF,
                    617:                         * then no need to read data from disk.
                    618:                         */
                    619:                        bp = getblk(thisvp, bn, pmp->pm_bpcluster, 0, 0);
                    620:                        clrbuf(bp);
                    621:                        /*
                    622:                         * Do the bmap now, since pcbmap needs buffers
                    623:                         * for the fat table. (see msdosfs_strategy)
                    624:                         */
                    625:                        if (bp->b_blkno == bp->b_lblkno) {
                    626:                                error = pcbmap(dep,
                    627:                                               de_bn2cn(pmp, bp->b_lblkno),
                    628:                                               &bp->b_blkno, 0, 0);
                    629:                                if (error)
                    630:                                        bp->b_blkno = -1;
                    631:                        }
                    632:                        if (bp->b_blkno == -1) {
                    633:                                brelse(bp);
                    634:                                if (!error)
                    635:                                        error = EIO;            /* XXX */
                    636:                                break;
                    637:                        }
                    638:                } else {
                    639:                        /*
                    640:                         * The block we need to write into exists, so read it in.
                    641:                         */
                    642:                        error = bread(thisvp, bn, pmp->pm_bpcluster,
                    643:                                      NOCRED, &bp);
                    644:                        if (error) {
                    645:                                brelse(bp);
                    646:                                break;
                    647:                        }
                    648:                }
                    649:
                    650:                croffset = uio->uio_offset & pmp->pm_crbomask;
                    651:                n = min(uio->uio_resid, pmp->pm_bpcluster - croffset);
                    652:                if (uio->uio_offset + n > dep->de_FileSize) {
                    653:                        dep->de_FileSize = uio->uio_offset + n;
                    654:                        uvm_vnp_setsize(vp, dep->de_FileSize);
                    655:                }
                    656:                uvm_vnp_uncache(vp);
                    657:                /*
                    658:                 * Should these vnode_pager_* functions be done on dir
                    659:                 * files?
                    660:                 */
                    661:
                    662:                /*
                    663:                 * Copy the data from user space into the buf header.
                    664:                 */
                    665:                error = uiomove(bp->b_data + croffset, n, uio);
                    666:
                    667:                /*
                    668:                 * If they want this synchronous then write it and wait for
                    669:                 * it.  Otherwise, if on a cluster boundary write it
                    670:                 * asynchronously so we can move on to the next block
                    671:                 * without delay.  Otherwise do a delayed write because we
                    672:                 * may want to write somemore into the block later.
                    673:                 */
                    674:                if (ioflag & IO_SYNC)
                    675:                        (void) bwrite(bp);
                    676:                else if (n + croffset == pmp->pm_bpcluster)
                    677:                        bawrite(bp);
                    678:                else
                    679:                        bdwrite(bp);
                    680:                dep->de_flag |= DE_UPDATE;
                    681:        } while (error == 0 && uio->uio_resid > 0);
                    682:
                    683:        /*
                    684:         * If the write failed and they want us to, truncate the file back
                    685:         * to the size it was before the write was attempted.
                    686:         */
                    687: errexit:
                    688:        if (error) {
                    689:                if (ioflag & IO_UNIT) {
                    690:                        detrunc(dep, osize, ioflag & IO_SYNC, NOCRED, NULL);
                    691:                        uio->uio_offset -= resid - uio->uio_resid;
                    692:                        uio->uio_resid = resid;
                    693:                } else {
                    694:                        detrunc(dep, dep->de_FileSize, ioflag & IO_SYNC, NOCRED, NULL);
                    695:                        if (uio->uio_resid != resid)
                    696:                                error = 0;
                    697:                }
                    698:        } else if (ioflag & IO_SYNC)
                    699:                error = deupdat(dep, 1);
                    700:        return (error);
                    701: }
                    702:
                    703: int
                    704: msdosfs_ioctl(v)
                    705:        void *v;
                    706: {
                    707: #if 0
                    708:        struct vop_ioctl_args /* {
                    709:                struct vnode *a_vp;
                    710:                uint32_t a_command;
                    711:                caddr_t a_data;
                    712:                int a_fflag;
                    713:                struct ucred *a_cred;
                    714:                struct proc *a_p;
                    715:        } */ *ap;
                    716: #endif
                    717:
                    718:        return (ENOTTY);
                    719: }
                    720:
                    721: int
                    722: msdosfs_poll(v)
                    723:        void *v;
                    724: {
                    725:        struct vop_poll_args *ap = v;
                    726:
                    727:        return (ap->a_events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM));
                    728: }
                    729:
                    730: /*
                    731:  * Flush the blocks of a file to disk.
                    732:  *
                    733:  * This function is worthless for vnodes that represent directories. Maybe we
                    734:  * could just do a sync if they try an fsync on a directory file.
                    735:  */
                    736: int
                    737: msdosfs_fsync(v)
                    738:        void *v;
                    739: {
                    740:        struct vop_fsync_args *ap = v;
                    741:        struct vnode *vp = ap->a_vp;
                    742:
                    743:        vflushbuf(vp, ap->a_waitfor == MNT_WAIT);
                    744:        return (deupdat(VTODE(vp), ap->a_waitfor == MNT_WAIT));
                    745: }
                    746:
                    747: /*
                    748:  * Flush the blocks of a file to disk.
                    749:  *
                    750:  * This function is worthless for vnodes that represent directories. Maybe we
                    751:  * could just do a sync if they try an fsync on a directory file.
                    752:  */
                    753: int
                    754: msdosfs_remove(v)
                    755:        void *v;
                    756: {
                    757:        struct vop_remove_args *ap = v;
                    758:        struct denode *dep = VTODE(ap->a_vp);
                    759:        struct denode *ddep = VTODE(ap->a_dvp);
                    760:        int error;
                    761:
                    762:        if (ap->a_vp->v_type == VDIR)
                    763:                error = EPERM;
                    764:        else
                    765:                error = removede(ddep, dep);
                    766: #ifdef MSDOSFS_DEBUG
                    767:        printf("msdosfs_remove(), dep %08x, v_usecount %d\n", dep, ap->a_vp->v_usecount);
                    768: #endif
                    769:        if (ddep == dep)
                    770:                vrele(ap->a_vp);
                    771:        else
                    772:                vput(ap->a_vp); /* causes msdosfs_inactive() to be called
                    773:                                 * via vrele() */
                    774:        vput(ap->a_dvp);
                    775:        return (error);
                    776: }
                    777:
                    778: /*
                    779:  * DOS filesystems don't know what links are. But since we already called
                    780:  * msdosfs_lookup() with create and lockparent, the parent is locked so we
                    781:  * have to free it before we return the error.
                    782:  */
                    783: int
                    784: msdosfs_link(v)
                    785:        void *v;
                    786: {
                    787:        struct vop_link_args *ap = v;
                    788:
                    789:        VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
                    790:        vput(ap->a_dvp);
                    791:        return (EOPNOTSUPP);
                    792: }
                    793:
                    794: /*
                    795:  * Renames on files require moving the denode to a new hash queue since the
                    796:  * denode's location is used to compute which hash queue to put the file
                    797:  * in. Unless it is a rename in place.  For example "mv a b".
                    798:  *
                    799:  * What follows is the basic algorithm:
                    800:  *
                    801:  * if (file move) {
                    802:  *     if (dest file exists) {
                    803:  *             remove dest file
                    804:  *     }
                    805:  *     if (dest and src in same directory) {
                    806:  *             rewrite name in existing directory slot
                    807:  *     } else {
                    808:  *             write new entry in dest directory
                    809:  *             update offset and dirclust in denode
                    810:  *             move denode to new hash chain
                    811:  *             clear old directory entry
                    812:  *     }
                    813:  * } else {
                    814:  *     directory move
                    815:  *     if (dest directory exists) {
                    816:  *             if (dest is not empty) {
                    817:  *                     return ENOTEMPTY
                    818:  *             }
                    819:  *             remove dest directory
                    820:  *     }
                    821:  *     if (dest and src in same directory) {
                    822:  *             rewrite name in existing entry
                    823:  *     } else {
                    824:  *             be sure dest is not a child of src directory
                    825:  *             write entry in dest directory
                    826:  *             update "." and ".." in moved directory
                    827:  *             update offset and dirclust in denode
                    828:  *             move denode to new hash chain
                    829:  *             clear old directory entry for moved directory
                    830:  *     }
                    831:  * }
                    832:  *
                    833:  * On entry:
                    834:  *     source's parent directory is unlocked
                    835:  *     source file or directory is unlocked
                    836:  *     destination's parent directory is locked
                    837:  *     destination file or directory is locked if it exists
                    838:  *
                    839:  * On exit:
                    840:  *     all denodes should be released
                    841:  *
                    842:  * Notes:
                    843:  * I'm not sure how the memory containing the pathnames pointed at by the
                    844:  * componentname structures is freed, there may be some memory bleeding
                    845:  * for each rename done.
                    846:  */
                    847: int
                    848: msdosfs_rename(v)
                    849:        void *v;
                    850: {
                    851:        struct vop_rename_args *ap = v;
                    852:        struct vnode *tvp = ap->a_tvp;
                    853:        register struct vnode *tdvp = ap->a_tdvp;
                    854:        struct vnode *fvp = ap->a_fvp;
                    855:        register struct vnode *fdvp = ap->a_fdvp;
                    856:        register struct componentname *tcnp = ap->a_tcnp;
                    857:        register struct componentname *fcnp = ap->a_fcnp;
                    858:        struct proc *p = curproc; /* XXX */
                    859:        register struct denode *ip, *xp, *dp, *zp;
                    860:        u_char toname[11], oldname[11];
                    861:        uint32_t from_diroffset, to_diroffset;
                    862:        u_char to_count;
                    863:        int doingdirectory = 0, newparent = 0;
                    864:        int error;
                    865:        uint32_t cn, pcl;
                    866:        daddr64_t bn;
                    867:        struct msdosfsmount *pmp;
                    868:        struct direntry *dotdotp;
                    869:        struct buf *bp;
                    870:
                    871:        pmp = VFSTOMSDOSFS(fdvp->v_mount);
                    872:
                    873: #ifdef DIAGNOSTIC
                    874:        if ((tcnp->cn_flags & HASBUF) == 0 ||
                    875:            (fcnp->cn_flags & HASBUF) == 0)
                    876:                panic("msdosfs_rename: no name");
                    877: #endif
                    878:        /*
                    879:         * Check for cross-device rename.
                    880:         */
                    881:        if ((fvp->v_mount != tdvp->v_mount) ||
                    882:            (tvp && (fvp->v_mount != tvp->v_mount))) {
                    883:                error = EXDEV;
                    884: abortit:
                    885:                VOP_ABORTOP(tdvp, tcnp);
                    886:                if (tdvp == tvp)
                    887:                        vrele(tdvp);
                    888:                else
                    889:                        vput(tdvp);
                    890:                if (tvp)
                    891:                        vput(tvp);
                    892:                VOP_ABORTOP(fdvp, fcnp);
                    893:                vrele(fdvp);
                    894:                vrele(fvp);
                    895:                return (error);
                    896:        }
                    897:
                    898:        /*
                    899:         * If source and dest are the same, do nothing.
                    900:         */
                    901:        if (tvp == fvp) {
                    902:                error = 0;
                    903:                goto abortit;
                    904:        }
                    905:
                    906:        /* */
                    907:        if ((error = vn_lock(fvp, LK_EXCLUSIVE | LK_RETRY, p)) != 0)
                    908:                goto abortit;
                    909:        dp = VTODE(fdvp);
                    910:        ip = VTODE(fvp);
                    911:
                    912:        /*
                    913:         * Be sure we are not renaming ".", "..", or an alias of ".". This
                    914:         * leads to a crippled directory tree.  It's pretty tough to do a
                    915:         * "ls" or "pwd" with the "." directory entry missing, and "cd .."
                    916:         * doesn't work if the ".." entry is missing.
                    917:         */
                    918:        if (ip->de_Attributes & ATTR_DIRECTORY) {
                    919:                /*
                    920:                 * Avoid ".", "..", and aliases of "." for obvious reasons.
                    921:                 */
                    922:                if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
                    923:                    dp == ip ||
                    924:                    (fcnp->cn_flags & ISDOTDOT) ||
                    925:                    (tcnp->cn_flags & ISDOTDOT) ||
                    926:                    (ip->de_flag & DE_RENAME)) {
                    927:                        VOP_UNLOCK(fvp, 0, p);
                    928:                        error = EINVAL;
                    929:                        goto abortit;
                    930:                }
                    931:                ip->de_flag |= DE_RENAME;
                    932:                doingdirectory++;
                    933:        }
                    934:
                    935:        /*
                    936:         * When the target exists, both the directory
                    937:         * and target vnodes are returned locked.
                    938:         */
                    939:        dp = VTODE(tdvp);
                    940:        xp = tvp ? VTODE(tvp) : NULL;
                    941:        /*
                    942:         * Remember direntry place to use for destination
                    943:         */
                    944:        to_diroffset = dp->de_fndoffset;
                    945:        to_count = dp->de_fndcnt;
                    946:
                    947:        /*
                    948:         * If ".." must be changed (ie the directory gets a new
                    949:         * parent) then the source directory must not be in the
                    950:         * directory hierarchy above the target, as this would
                    951:         * orphan everything below the source directory. Also
                    952:         * the user must have write permission in the source so
                    953:         * as to be able to change "..". We must repeat the call
                    954:         * to namei, as the parent directory is unlocked by the
                    955:         * call to doscheckpath().
                    956:         */
                    957:        error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
                    958:        VOP_UNLOCK(fvp, 0, p);
                    959:        if (VTODE(fdvp)->de_StartCluster != VTODE(tdvp)->de_StartCluster)
                    960:                newparent = 1;
                    961:        vrele(fdvp);
                    962:        if (doingdirectory && newparent) {
                    963:                if (error)      /* write access check above */
                    964:                        goto bad1;
                    965:                if (xp != NULL)
                    966:                        vput(tvp);
                    967:                /*
                    968:                 * doscheckpath() vput()'s dp,
                    969:                 * so we have to do a relookup afterwards
                    970:                 */
                    971:                if ((error = doscheckpath(ip, dp)) != 0)
                    972:                        goto out;
                    973:                if ((tcnp->cn_flags & SAVESTART) == 0)
                    974:                        panic("msdosfs_rename: lost to startdir");
                    975:                if ((error = relookup(tdvp, &tvp, tcnp)) != 0)
                    976:                        goto out;
                    977:                dp = VTODE(tdvp);
                    978:                xp = tvp ? VTODE(tvp) : NULL;
                    979:        }
                    980:
                    981:        if (xp != NULL) {
                    982:                /*
                    983:                 * Target must be empty if a directory and have no links
                    984:                 * to it. Also, ensure source and target are compatible
                    985:                 * (both directories, or both not directories).
                    986:                 */
                    987:                if (xp->de_Attributes & ATTR_DIRECTORY) {
                    988:                        if (!dosdirempty(xp)) {
                    989:                                error = ENOTEMPTY;
                    990:                                goto bad1;
                    991:                        }
                    992:                        if (!doingdirectory) {
                    993:                                error = ENOTDIR;
                    994:                                goto bad1;
                    995:                        }
                    996:                        cache_purge(tdvp);
                    997:                } else if (doingdirectory) {
                    998:                        error = EISDIR;
                    999:                        goto bad1;
                   1000:                }
                   1001:                if ((error = removede(dp, xp)) != 0)
                   1002:                        goto bad1;
                   1003:                vput(tvp);
                   1004:                xp = NULL;
                   1005:        }
                   1006:
                   1007:        /*
                   1008:         * Convert the filename in tcnp into a dos filename. We copy this
                   1009:         * into the denode and directory entry for the destination
                   1010:         * file/directory.
                   1011:         */
                   1012:        if ((error = uniqdosname(VTODE(tdvp), tcnp, toname)) != 0)
                   1013:                goto bad1;
                   1014:
                   1015:        /*
                   1016:         * Since from wasn't locked at various places above,
                   1017:         * have to do a relookup here.
                   1018:         */
                   1019:        fcnp->cn_flags &= ~MODMASK;
                   1020:        fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
                   1021:        if ((fcnp->cn_flags & SAVESTART) == 0)
                   1022:                panic("msdosfs_rename: lost from startdir");
                   1023:        if (!newparent)
                   1024:                VOP_UNLOCK(tdvp, 0, p);
                   1025:        (void) relookup(fdvp, &fvp, fcnp);
                   1026:        if (fvp == NULL) {
                   1027:                /*
                   1028:                 * From name has disappeared.
                   1029:                 */
                   1030:                if (doingdirectory)
                   1031:                        panic("rename: lost dir entry");
                   1032:                vrele(ap->a_fvp);
                   1033:                if (newparent)
                   1034:                        VOP_UNLOCK(tdvp, 0, p);
                   1035:                vrele(tdvp);
                   1036:                return 0;
                   1037:        }
                   1038:        xp = VTODE(fvp);
                   1039:        zp = VTODE(fdvp);
                   1040:        from_diroffset = zp->de_fndoffset;
                   1041:
                   1042:        /*
                   1043:         * Ensure that the directory entry still exists and has not
                   1044:         * changed till now. If the source is a file the entry may
                   1045:         * have been unlinked or renamed. In either case there is
                   1046:         * no further work to be done. If the source is a directory
                   1047:         * then it cannot have been rmdir'ed or renamed; this is
                   1048:         * prohibited by the DE_RENAME flag.
                   1049:         */
                   1050:        if (xp != ip) {
                   1051:                if (doingdirectory)
                   1052:                        panic("rename: lost dir entry");
                   1053:                vrele(ap->a_fvp);
                   1054:                if (newparent)
                   1055:                        VOP_UNLOCK(fdvp, 0, p);
                   1056:                xp = NULL;
                   1057:        } else {
                   1058:                vrele(fvp);
                   1059:                xp = NULL;
                   1060:
                   1061:                /*
                   1062:                 * First write a new entry in the destination
                   1063:                 * directory and mark the entry in the source directory
                   1064:                 * as deleted.  Then move the denode to the correct hash
                   1065:                 * chain for its new location in the filesystem.  And, if
                   1066:                 * we moved a directory, then update its .. entry to point
                   1067:                 * to the new parent directory.
                   1068:                 */
                   1069:                bcopy(ip->de_Name, oldname, 11);
                   1070:                bcopy(toname, ip->de_Name, 11); /* update denode */
                   1071:                dp->de_fndoffset = to_diroffset;
                   1072:                dp->de_fndcnt = to_count;
                   1073:                error = createde(ip, dp, (struct denode **)0, tcnp);
                   1074:                if (error) {
                   1075:                        bcopy(oldname, ip->de_Name, 11);
                   1076:                        if (newparent)
                   1077:                                VOP_UNLOCK(fdvp, 0, p);
                   1078:                        goto bad;
                   1079:                }
                   1080:                ip->de_refcnt++;
                   1081:                zp->de_fndoffset = from_diroffset;
                   1082:                if ((error = removede(zp, ip)) != 0) {
                   1083:                        /* XXX should really panic here, fs is corrupt */
                   1084:                        if (newparent)
                   1085:                                VOP_UNLOCK(fdvp, 0, p);
                   1086:                        goto bad;
                   1087:                }
                   1088:
                   1089:                cache_purge(fvp);
                   1090:
                   1091:                if (!doingdirectory) {
                   1092:                        error = pcbmap(dp, de_cluster(pmp, to_diroffset), 0,
                   1093:                                       &ip->de_dirclust, 0);
                   1094:                        if (error) {
                   1095:                                /* XXX should really panic here, fs is corrupt */
                   1096:                                if (newparent)
                   1097:                                        VOP_UNLOCK(fdvp, 0, p);
                   1098:                                goto bad;
                   1099:                        }
                   1100:                        if (ip->de_dirclust != MSDOSFSROOT)
                   1101:                                ip->de_diroffset = to_diroffset & pmp->pm_crbomask;
                   1102:                }
                   1103:                reinsert(ip);
                   1104:                if (newparent)
                   1105:                        VOP_UNLOCK(fdvp, 0, p);
                   1106:        }
                   1107:
                   1108:        /*
                   1109:         * If we moved a directory to a new parent directory, then we must
                   1110:         * fixup the ".." entry in the moved directory.
                   1111:         */
                   1112:        if (doingdirectory && newparent) {
                   1113:                cn = ip->de_StartCluster;
                   1114:                if (cn == MSDOSFSROOT) {
                   1115:                        /* this should never happen */
                   1116:                        panic("msdosfs_rename: updating .. in root directory?");
                   1117:                } else
                   1118:                        bn = cntobn(pmp, cn);
                   1119:                error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster,
                   1120:                              NOCRED, &bp);
                   1121:                if (error) {
                   1122:                        /* XXX should really panic here, fs is corrupt */
                   1123:                        brelse(bp);
                   1124:                        goto bad;
                   1125:                }
                   1126:                dotdotp = (struct direntry *)bp->b_data;
                   1127:                putushort(dotdotp[0].deStartCluster, cn);
                   1128:                pcl = dp->de_StartCluster;
                   1129:                if (FAT32(pmp) && pcl == pmp->pm_rootdirblk)
                   1130:                        pcl = 0;
                   1131:                putushort(dotdotp[1].deStartCluster, pcl);
                   1132:                if (FAT32(pmp)) {
                   1133:                        putushort(dotdotp[0].deHighClust, cn >> 16);
                   1134:                        putushort(dotdotp[1].deHighClust, pcl >> 16);
                   1135:                }
                   1136:                if ((error = bwrite(bp)) != 0) {
                   1137:                        /* XXX should really panic here, fs is corrupt */
                   1138:                        goto bad;
                   1139:                }
                   1140:        }
                   1141:
                   1142: bad:
                   1143:        VOP_UNLOCK(fvp, 0, p);
                   1144:        vrele(fdvp);
                   1145: bad1:
                   1146:        if (xp)
                   1147:                vput(tvp);
                   1148:        vput(tdvp);
                   1149: out:
                   1150:        ip->de_flag &= ~DE_RENAME;
                   1151:        vrele(fvp);
                   1152:        return (error);
                   1153:
                   1154: }
                   1155:
                   1156: struct {
                   1157:        struct direntry dot;
                   1158:        struct direntry dotdot;
                   1159: } dosdirtemplate = {
                   1160:        {       ".       ", "   ",                      /* the . entry */
                   1161:                ATTR_DIRECTORY,                         /* file attribute */
                   1162:                CASE_LOWER_BASE | CASE_LOWER_EXT,       /* lower case */
                   1163:                0,                                      /* create time 100ths */
                   1164:                { 0, 0 }, { 0, 0 },                     /* create time & date */
                   1165:                { 0, 0 },                               /* access date */
                   1166:                { 0, 0 },                               /* high bits of start cluster */
                   1167:                { 210, 4 }, { 210, 4 },                 /* modify time & date */
                   1168:                { 0, 0 },                               /* startcluster */
                   1169:                { 0, 0, 0, 0 }                          /* filesize */
                   1170:        },
                   1171:        {       "..      ", "   ",                      /* the .. entry */
                   1172:                ATTR_DIRECTORY,                         /* file attribute */
                   1173:                CASE_LOWER_BASE | CASE_LOWER_EXT,       /* lower case */
                   1174:                0,                                      /* create time 100ths */
                   1175:                { 0, 0 }, { 0, 0 },                     /* create time & date */
                   1176:                { 0, 0 },                               /* access date */
                   1177:                { 0, 0 },                               /* high bits of start cluster */
                   1178:                { 210, 4 }, { 210, 4 },                 /* modify time & date */
                   1179:                { 0, 0 },                               /* startcluster */
                   1180:                { 0, 0, 0, 0 }                          /* filesize */
                   1181:        }
                   1182: };
                   1183:
                   1184: int
                   1185: msdosfs_mkdir(v)
                   1186:        void *v;
                   1187: {
                   1188:        struct vop_mkdir_args *ap = v;
                   1189:        struct componentname *cnp = ap->a_cnp;
                   1190:        struct denode ndirent;
                   1191:        struct denode *dep;
                   1192:        struct denode *pdep = VTODE(ap->a_dvp);
                   1193:        int error;
                   1194:        daddr64_t bn;
                   1195:        uint32_t newcluster, pcl;
                   1196:        struct direntry *denp;
                   1197:        struct msdosfsmount *pmp = pdep->de_pmp;
                   1198:        struct buf *bp;
                   1199:        struct timespec ts;
                   1200:
                   1201:        /*
                   1202:         * If this is the root directory and there is no space left we
                   1203:         * can't do anything.  This is because the root directory can not
                   1204:         * change size.
                   1205:         */
                   1206:        if (pdep->de_StartCluster == MSDOSFSROOT
                   1207:            && pdep->de_fndoffset >= pdep->de_FileSize) {
                   1208:                error = ENOSPC;
                   1209:                goto bad2;
                   1210:        }
                   1211:
                   1212:        /*
                   1213:         * Allocate a cluster to hold the about to be created directory.
                   1214:         */
                   1215:        error = clusteralloc(pmp, 0, 1, CLUST_EOFE, &newcluster, NULL);
                   1216:        if (error)
                   1217:                goto bad2;
                   1218:
                   1219:        bzero(&ndirent, sizeof(ndirent));
                   1220:        ndirent.de_pmp = pmp;
                   1221:        ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE;
                   1222:        getnanotime(&ts);
                   1223:        DETIMES(&ndirent, &ts, &ts, &ts);
                   1224:
                   1225:        /*
                   1226:         * Now fill the cluster with the "." and ".." entries. And write
                   1227:         * the cluster to disk.  This way it is there for the parent
                   1228:         * directory to be pointing at if there were a crash.
                   1229:         */
                   1230:        bn = cntobn(pmp, newcluster);
                   1231:        /* always succeeds */
                   1232:        bp = getblk(pmp->pm_devvp, bn, pmp->pm_bpcluster, 0, 0);
                   1233:        bzero(bp->b_data, pmp->pm_bpcluster);
                   1234:        bcopy(&dosdirtemplate, bp->b_data, sizeof dosdirtemplate);
                   1235:        denp = (struct direntry *)bp->b_data;
                   1236:        putushort(denp[0].deStartCluster, newcluster);
                   1237:        putushort(denp[0].deCDate, ndirent.de_CDate);
                   1238:        putushort(denp[0].deCTime, ndirent.de_CTime);
                   1239:        denp[0].deCTimeHundredth = ndirent.de_CTimeHundredth;
                   1240:        putushort(denp[0].deADate, ndirent.de_ADate);
                   1241:        putushort(denp[0].deMDate, ndirent.de_MDate);
                   1242:        putushort(denp[0].deMTime, ndirent.de_MTime);
                   1243:        pcl = pdep->de_StartCluster;
                   1244:        if (FAT32(pmp) && pcl == pmp->pm_rootdirblk)
                   1245:                pcl = 0;
                   1246:        putushort(denp[1].deStartCluster, pcl);
                   1247:        putushort(denp[1].deCDate, ndirent.de_CDate);
                   1248:        putushort(denp[1].deCTime, ndirent.de_CTime);
                   1249:        denp[1].deCTimeHundredth = ndirent.de_CTimeHundredth;
                   1250:        putushort(denp[1].deADate, ndirent.de_ADate);
                   1251:        putushort(denp[1].deMDate, ndirent.de_MDate);
                   1252:        putushort(denp[1].deMTime, ndirent.de_MTime);
                   1253:        if (FAT32(pmp)) {
                   1254:                putushort(denp[0].deHighClust, newcluster >> 16);
                   1255:                putushort(denp[1].deHighClust, pdep->de_StartCluster >> 16);
                   1256:        }
                   1257:
                   1258:        if ((error = bwrite(bp)) != 0)
                   1259:                goto bad;
                   1260:
                   1261:        /*
                   1262:         * Now build up a directory entry pointing to the newly allocated
                   1263:         * cluster.  This will be written to an empty slot in the parent
                   1264:         * directory.
                   1265:         */
                   1266: #ifdef DIAGNOSTIC
                   1267:        if ((cnp->cn_flags & HASBUF) == 0)
                   1268:                panic("msdosfs_mkdir: no name");
                   1269: #endif
                   1270:        if ((error = uniqdosname(pdep, cnp, ndirent.de_Name)) != 0)
                   1271:                goto bad;
                   1272:
                   1273:        ndirent.de_Attributes = ATTR_DIRECTORY;
                   1274:        ndirent.de_StartCluster = newcluster;
                   1275:        ndirent.de_FileSize = 0;
                   1276:        ndirent.de_dev = pdep->de_dev;
                   1277:        ndirent.de_devvp = pdep->de_devvp;
                   1278:        if ((error = createde(&ndirent, pdep, &dep, cnp)) != 0)
                   1279:                goto bad;
                   1280:        if ((cnp->cn_flags & SAVESTART) == 0)
                   1281:                pool_put(&namei_pool, cnp->cn_pnbuf);
                   1282:        vput(ap->a_dvp);
                   1283:        *ap->a_vpp = DETOV(dep);
                   1284:        return (0);
                   1285:
                   1286: bad:
                   1287:        clusterfree(pmp, newcluster, NULL);
                   1288: bad2:
                   1289:        pool_put(&namei_pool, cnp->cn_pnbuf);
                   1290:        vput(ap->a_dvp);
                   1291:        return (error);
                   1292: }
                   1293:
                   1294: int
                   1295: msdosfs_rmdir(v)
                   1296:        void *v;
                   1297: {
                   1298:        struct vop_rmdir_args *ap = v;
                   1299:        register struct vnode *vp = ap->a_vp;
                   1300:        register struct vnode *dvp = ap->a_dvp;
                   1301:        register struct componentname *cnp = ap->a_cnp;
                   1302:        register struct denode *ip, *dp;
                   1303:        int error;
                   1304:
                   1305:        ip = VTODE(vp);
                   1306:        dp = VTODE(dvp);
                   1307:        /*
                   1308:         * No rmdir "." please.
                   1309:         */
                   1310:        if (dp == ip) {
                   1311:                vrele(dvp);
                   1312:                vput(vp);
                   1313:                return (EINVAL);
                   1314:        }
                   1315:        /*
                   1316:         * Verify the directory is empty (and valid).
                   1317:         * (Rmdir ".." won't be valid since
                   1318:         *  ".." will contain a reference to
                   1319:         *  the current directory and thus be
                   1320:         *  non-empty.)
                   1321:         */
                   1322:        error = 0;
                   1323:        if (!dosdirempty(ip) || ip->de_flag & DE_RENAME) {
                   1324:                error = ENOTEMPTY;
                   1325:                goto out;
                   1326:        }
                   1327:        /*
                   1328:         * Delete the entry from the directory.  For dos filesystems this
                   1329:         * gets rid of the directory entry on disk, the in memory copy
                   1330:         * still exists but the de_refcnt is <= 0.  This prevents it from
                   1331:         * being found by deget().  When the vput() on dep is done we give
                   1332:         * up access and eventually msdosfs_reclaim() will be called which
                   1333:         * will remove it from the denode cache.
                   1334:         */
                   1335:        if ((error = removede(dp, ip)) != 0)
                   1336:                goto out;
                   1337:        /*
                   1338:         * This is where we decrement the link count in the parent
                   1339:         * directory.  Since dos filesystems don't do this we just purge
                   1340:         * the name cache and let go of the parent directory denode.
                   1341:         */
                   1342:        cache_purge(dvp);
                   1343:        vput(dvp);
                   1344:        dvp = NULL;
                   1345:        /*
                   1346:         * Truncate the directory that is being deleted.
                   1347:         */
                   1348:        error = detrunc(ip, (uint32_t)0, IO_SYNC, cnp->cn_cred, cnp->cn_proc);
                   1349:        cache_purge(vp);
                   1350: out:
                   1351:        if (dvp)
                   1352:                vput(dvp);
                   1353:        vput(vp);
                   1354:        return (error);
                   1355: }
                   1356:
                   1357: /*
                   1358:  * DOS filesystems don't know what symlinks are.
                   1359:  */
                   1360: int
                   1361: msdosfs_symlink(v)
                   1362:        void *v;
                   1363: {
                   1364:        struct vop_symlink_args *ap = v;
                   1365:
                   1366:        VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
                   1367:        vput(ap->a_dvp);
                   1368:        return (EOPNOTSUPP);
                   1369: }
                   1370:
                   1371: int
                   1372: msdosfs_readdir(v)
                   1373:        void *v;
                   1374: {
                   1375:        struct vop_readdir_args *ap = v;
                   1376:        int error = 0;
                   1377:        int diff;
                   1378:        long n;
                   1379:        int blsize;
                   1380:        long on;
                   1381:        long lost;
                   1382:        long count;
                   1383:        uint32_t dirsperblk;
                   1384:        uint32_t cn, lbn;
                   1385:        uint32_t fileno;
                   1386:        long bias = 0;
                   1387:        daddr64_t bn;
                   1388:        struct buf *bp;
                   1389:        struct denode *dep = VTODE(ap->a_vp);
                   1390:        struct msdosfsmount *pmp = dep->de_pmp;
                   1391:        struct direntry *dentp;
                   1392:        struct dirent dirbuf;
                   1393:        struct uio *uio = ap->a_uio;
                   1394:        u_long *cookies = NULL;
                   1395:        int ncookies = 0;
                   1396:        off_t offset, wlast = -1;
                   1397:        int chksum = -1;
                   1398:
                   1399: #ifdef MSDOSFS_DEBUG
                   1400:        printf("msdosfs_readdir(): vp %08x, uio %08x, cred %08x, eofflagp %08x\n",
                   1401:            ap->a_vp, uio, ap->a_cred, ap->a_eofflag);
                   1402: #endif
                   1403:
                   1404:        /*
                   1405:         * msdosfs_readdir() won't operate properly on regular files since
                   1406:         * it does i/o only with the filesystem vnode, and hence can
                   1407:         * retrieve the wrong block from the buffer cache for a plain file.
                   1408:         * So, fail attempts to readdir() on a plain file.
                   1409:         */
                   1410:        if ((dep->de_Attributes & ATTR_DIRECTORY) == 0)
                   1411:                return (ENOTDIR);
                   1412:
                   1413:        /*
                   1414:         * To be safe, initialize dirbuf
                   1415:         */
                   1416:        bzero(dirbuf.d_name, sizeof(dirbuf.d_name));
                   1417:
                   1418:        /*
                   1419:         * If the user buffer is smaller than the size of one dos directory
                   1420:         * entry or the file offset is not a multiple of the size of a
                   1421:         * directory entry, then we fail the read.
                   1422:         */
                   1423:        count = uio->uio_resid & ~(sizeof(struct direntry) - 1);
                   1424:        offset = uio->uio_offset;
                   1425:        if (count < sizeof(struct direntry) ||
                   1426:            (offset & (sizeof(struct direntry) - 1)))
                   1427:                return (EINVAL);
                   1428:        lost = uio->uio_resid - count;
                   1429:        uio->uio_resid = count;
                   1430:
                   1431:        if (ap->a_ncookies) {
                   1432:                ncookies = uio->uio_resid / sizeof(struct direntry) + 3;
                   1433:                MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP,
                   1434:                       M_WAITOK);
                   1435:                *ap->a_cookies = cookies;
                   1436:                *ap->a_ncookies = ncookies;
                   1437:        }
                   1438:
                   1439:        dirsperblk = pmp->pm_BytesPerSec / sizeof(struct direntry);
                   1440:
                   1441:        /*
                   1442:         * If they are reading from the root directory then, we simulate
                   1443:         * the . and .. entries since these don't exist in the root
                   1444:         * directory.  We also set the offset bias to make up for having to
                   1445:         * simulate these entries. By this I mean that at file offset 64 we
                   1446:         * read the first entry in the root directory that lives on disk.
                   1447:         */
                   1448:        if (dep->de_StartCluster == MSDOSFSROOT
                   1449:            || (FAT32(pmp) && dep->de_StartCluster == pmp->pm_rootdirblk)) {
                   1450: #if 0
                   1451:                printf("msdosfs_readdir(): going after . or .. in root dir, offset %d\n",
                   1452:                    offset);
                   1453: #endif
                   1454:                bias = 2 * sizeof(struct direntry);
                   1455:                if (offset < bias) {
                   1456:                        for (n = (int)offset / sizeof(struct direntry);
                   1457:                             n < 2; n++) {
                   1458:                                if (FAT32(pmp))
                   1459:                                        dirbuf.d_fileno = pmp->pm_rootdirblk;
                   1460:                                else
                   1461:                                        dirbuf.d_fileno = 1;
                   1462:                                dirbuf.d_type = DT_DIR;
                   1463:                                switch (n) {
                   1464:                                case 0:
                   1465:                                        dirbuf.d_namlen = 1;
                   1466:                                        strlcpy(dirbuf.d_name, ".",
                   1467:                                            sizeof dirbuf.d_name);
                   1468:                                        break;
                   1469:                                case 1:
                   1470:                                        dirbuf.d_namlen = 2;
                   1471:                                        strlcpy(dirbuf.d_name, "..",
                   1472:                                            sizeof dirbuf.d_name);
                   1473:                                        break;
                   1474:                                }
                   1475:                                dirbuf.d_reclen = DIRENT_SIZE(&dirbuf);
                   1476:                                if (uio->uio_resid < dirbuf.d_reclen)
                   1477:                                        goto out;
                   1478:                                error = uiomove((caddr_t) &dirbuf,
                   1479:                                                dirbuf.d_reclen, uio);
                   1480:                                if (error)
                   1481:                                        goto out;
                   1482:                                offset += sizeof(struct direntry);
                   1483:                                if (cookies) {
                   1484:                                        *cookies++ = offset;
                   1485:                                        if (--ncookies <= 0)
                   1486:                                                goto out;
                   1487:                                }
                   1488:                        }
                   1489:                }
                   1490:        }
                   1491:
                   1492:        while (uio->uio_resid > 0) {
                   1493:                lbn = de_cluster(pmp, offset - bias);
                   1494:                on = (offset - bias) & pmp->pm_crbomask;
                   1495:                n = min(pmp->pm_bpcluster - on, uio->uio_resid);
                   1496:                diff = dep->de_FileSize - (offset - bias);
                   1497:                if (diff <= 0)
                   1498:                        break;
                   1499:                n = min(n, diff);
                   1500:                if ((error = pcbmap(dep, lbn, &bn, &cn, &blsize)) != 0)
                   1501:                        break;
                   1502:                error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp);
                   1503:                if (error) {
                   1504:                        brelse(bp);
                   1505:                        return (error);
                   1506:                }
                   1507:                n = min(n, blsize - bp->b_resid);
                   1508:
                   1509:                /*
                   1510:                 * Convert from dos directory entries to fs-independent
                   1511:                 * directory entries.
                   1512:                 */
                   1513:                for (dentp = (struct direntry *)(bp->b_data + on);
                   1514:                     (char *)dentp < bp->b_data + on + n;
                   1515:                     dentp++, offset += sizeof(struct direntry)) {
                   1516: #if 0
                   1517:                        printf("rd: dentp %08x prev %08x crnt %08x deName %02x attr %02x\n",
                   1518:                            dentp, prev, crnt, dentp->deName[0], dentp->deAttributes);
                   1519: #endif
                   1520:                        /*
                   1521:                         * If this is an unused entry, we can stop.
                   1522:                         */
                   1523:                        if (dentp->deName[0] == SLOT_EMPTY) {
                   1524:                                brelse(bp);
                   1525:                                goto out;
                   1526:                        }
                   1527:                        /*
                   1528:                         * Skip deleted entries.
                   1529:                         */
                   1530:                        if (dentp->deName[0] == SLOT_DELETED) {
                   1531:                                chksum = -1;
                   1532:                                wlast = -1;
                   1533:                                continue;
                   1534:                        }
                   1535:
                   1536:                        /*
                   1537:                         * Handle Win95 long directory entries
                   1538:                         */
                   1539:                        if (dentp->deAttributes == ATTR_WIN95) {
                   1540:                                struct winentry *wep;
                   1541:                                if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
                   1542:                                        continue;
                   1543:                                wep = (struct winentry *)dentp;
                   1544:                                chksum = win2unixfn(wep, &dirbuf, chksum);
                   1545:                                if (wep->weCnt & WIN_LAST)
                   1546:                                        wlast = offset;
                   1547:                                continue;
                   1548:                        }
                   1549:
                   1550:                        /*
                   1551:                         * Skip volume labels
                   1552:                         */
                   1553:                        if (dentp->deAttributes & ATTR_VOLUME) {
                   1554:                                chksum = -1;
                   1555:                                wlast = -1;
                   1556:                                continue;
                   1557:                        }
                   1558:
                   1559:                        /*
                   1560:                         * This computation of d_fileno must match
                   1561:                         * the computation of va_fileid in
                   1562:                         * msdosfs_getattr.
                   1563:                         */
                   1564:                        fileno = getushort(dentp->deStartCluster);
                   1565:                        if (FAT32(pmp))
                   1566:                            fileno |= getushort(dentp->deHighClust) << 16;
                   1567:
                   1568:                        if (dentp->deAttributes & ATTR_DIRECTORY) {
                   1569:                                /* Special-case root */
                   1570:                                if (fileno == MSDOSFSROOT)  {
                   1571:                                        fileno = FAT32(pmp) ?
                   1572:                                            pmp->pm_rootdirblk : 1;
                   1573:                                }
                   1574:
                   1575:                                dirbuf.d_fileno = fileno;
                   1576:                                dirbuf.d_type = DT_DIR;
                   1577:                        } else {
                   1578:                                if (getulong(dentp->deFileSize) == 0) {
                   1579:                                        uint64_t fileno64;
                   1580:
                   1581:                                        fileno64 = (cn == MSDOSFSROOT) ?
                   1582:                                            roottobn(pmp, 0) : cntobn(pmp, cn);
                   1583:
                   1584:                                        fileno64 *= dirsperblk;
                   1585:                                        fileno64 += dentp -
                   1586:                                            (struct direntry *)bp->b_data;
                   1587:
                   1588:                                        fileno = fileidhash(fileno64);
                   1589:                                }
                   1590:
                   1591:                                dirbuf.d_fileno = fileno;
                   1592:                                dirbuf.d_type = DT_REG;
                   1593:                        }
                   1594:
                   1595:                        if (chksum != winChksum(dentp->deName))
                   1596:                                dirbuf.d_namlen = dos2unixfn(dentp->deName,
                   1597:                                    (u_char *)dirbuf.d_name,
                   1598:                                    pmp->pm_flags & MSDOSFSMNT_SHORTNAME);
                   1599:                        else
                   1600:                                dirbuf.d_name[dirbuf.d_namlen] = 0;
                   1601:                        chksum = -1;
                   1602:                        dirbuf.d_reclen = DIRENT_SIZE(&dirbuf);
                   1603:                        if (uio->uio_resid < dirbuf.d_reclen) {
                   1604:                                brelse(bp);
                   1605:                                /* Remember long-name offset. */
                   1606:                                if (wlast != -1)
                   1607:                                        offset = wlast;
                   1608:                                goto out;
                   1609:                        }
                   1610:                        wlast = -1;
                   1611:                        error = uiomove((caddr_t) &dirbuf,
                   1612:                                        dirbuf.d_reclen, uio);
                   1613:                        if (error) {
                   1614:                                brelse(bp);
                   1615:                                goto out;
                   1616:                        }
                   1617:                        if (cookies) {
                   1618:                                *cookies++ = offset + sizeof(struct direntry);
                   1619:                                if (--ncookies <= 0) {
                   1620:                                        brelse(bp);
                   1621:                                        goto out;
                   1622:                                }
                   1623:                        }
                   1624:                }
                   1625:                brelse(bp);
                   1626:        }
                   1627:
                   1628: out:
                   1629:        /* Subtract unused cookies */
                   1630:        if (ap->a_ncookies)
                   1631:                *ap->a_ncookies -= ncookies;
                   1632:
                   1633:        uio->uio_offset = offset;
                   1634:        uio->uio_resid += lost;
                   1635:        if (dep->de_FileSize - (offset - bias) <= 0)
                   1636:                *ap->a_eofflag = 1;
                   1637:        else
                   1638:                *ap->a_eofflag = 0;
                   1639:        return (error);
                   1640: }
                   1641:
                   1642: /*
                   1643:  * DOS filesystems don't know what symlinks are.
                   1644:  */
                   1645: int
                   1646: msdosfs_readlink(v)
                   1647:        void *v;
                   1648: {
                   1649: #if 0
                   1650:        struct vop_readlink_args /* {
                   1651:                struct vnode *a_vp;
                   1652:                struct uio *a_uio;
                   1653:                struct ucred *a_cred;
                   1654:        } */ *ap;
                   1655: #endif
                   1656:
                   1657:        return (EINVAL);
                   1658: }
                   1659:
                   1660: int
                   1661: msdosfs_lock(v)
                   1662:        void *v;
                   1663: {
                   1664:        struct vop_lock_args *ap = v;
                   1665:        struct vnode *vp = ap->a_vp;
                   1666:
                   1667:        return (lockmgr(&VTODE(vp)->de_lock, ap->a_flags, NULL));
                   1668: }
                   1669:
                   1670: int
                   1671: msdosfs_unlock(v)
                   1672:        void *v;
                   1673: {
                   1674:        struct vop_unlock_args *ap = v;
                   1675:        struct vnode *vp = ap->a_vp;
                   1676:
                   1677:        return (lockmgr(&VTODE(vp)->de_lock, ap->a_flags | LK_RELEASE, NULL));
                   1678: }
                   1679:
                   1680: int
                   1681: msdosfs_islocked(v)
                   1682:        void *v;
                   1683: {
                   1684:        struct vop_islocked_args *ap = v;
                   1685:
                   1686:        return (lockstatus(&VTODE(ap->a_vp)->de_lock));
                   1687: }
                   1688:
                   1689: /*
                   1690:  * vp  - address of vnode file the file
                   1691:  * bn  - which cluster we are interested in mapping to a filesystem block number.
                   1692:  * vpp - returns the vnode for the block special file holding the filesystem
                   1693:  *      containing the file of interest
                   1694:  * bnp - address of where to return the filesystem relative block number
                   1695:  */
                   1696: int
                   1697: msdosfs_bmap(v)
                   1698:        void *v;
                   1699: {
                   1700:        struct vop_bmap_args *ap = v;
                   1701:        struct denode *dep = VTODE(ap->a_vp);
                   1702:        struct msdosfsmount *pmp = dep->de_pmp;
                   1703:
                   1704:        if (ap->a_vpp != NULL)
                   1705:                *ap->a_vpp = dep->de_devvp;
                   1706:        if (ap->a_bnp == NULL)
                   1707:                return (0);
                   1708:        if (ap->a_runp) {
                   1709:                /*
                   1710:                 * Sequential clusters should be counted here.
                   1711:                 */
                   1712:                *ap->a_runp = 0;
                   1713:        }
                   1714:        return (pcbmap(dep, de_bn2cn(pmp, ap->a_bn), ap->a_bnp, 0, 0));
                   1715: }
                   1716:
                   1717: int
                   1718: msdosfs_strategy(v)
                   1719:        void *v;
                   1720: {
                   1721:        struct vop_strategy_args *ap = v;
                   1722:        struct buf *bp = ap->a_bp;
                   1723:        struct denode *dep = VTODE(bp->b_vp);
                   1724:        struct vnode *vp;
                   1725:        int error = 0;
                   1726:        int s;
                   1727:
                   1728:        if (bp->b_vp->v_type == VBLK || bp->b_vp->v_type == VCHR)
                   1729:                panic("msdosfs_strategy: spec");
                   1730:        /*
                   1731:         * If we don't already know the filesystem relative block number
                   1732:         * then get it using pcbmap().  If pcbmap() returns the block
                   1733:         * number as -1 then we've got a hole in the file.  DOS filesystems
                   1734:         * don't allow files with holes, so we shouldn't ever see this.
                   1735:         */
                   1736:        if (bp->b_blkno == bp->b_lblkno) {
                   1737:                error = pcbmap(dep, de_bn2cn(dep->de_pmp, bp->b_lblkno),
                   1738:                               &bp->b_blkno, 0, 0);
                   1739:                if (error)
                   1740:                        bp->b_blkno = -1;
                   1741:                if (bp->b_blkno == -1)
                   1742:                        clrbuf(bp);
                   1743:        }
                   1744:        if (bp->b_blkno == -1) {
                   1745:                s = splbio();
                   1746:                biodone(bp);
                   1747:                splx(s);
                   1748:                return (error);
                   1749:        }
                   1750:
                   1751:        /*
                   1752:         * Read/write the block from/to the disk that contains the desired
                   1753:         * file block.
                   1754:         */
                   1755:
                   1756:        vp = dep->de_devvp;
                   1757:        bp->b_dev = vp->v_rdev;
                   1758:        VOCALL(vp->v_op, VOFFSET(vop_strategy), ap);
                   1759:        return (0);
                   1760: }
                   1761:
                   1762: int
                   1763: msdosfs_print(v)
                   1764:        void *v;
                   1765: {
                   1766:        struct vop_print_args *ap = v;
                   1767:        struct denode *dep = VTODE(ap->a_vp);
                   1768:
                   1769:        printf(
                   1770:            "tag VT_MSDOSFS, startcluster %ld, dircluster %ld, diroffset %ld ",
                   1771:            dep->de_StartCluster, dep->de_dirclust, dep->de_diroffset);
                   1772:        printf(" dev %d, %d, %s\n",
                   1773:            major(dep->de_dev), minor(dep->de_dev),
                   1774:            VOP_ISLOCKED(ap->a_vp) ? "(LOCKED)" : "");
                   1775: #ifdef DIAGNOSTIC
                   1776:        lockmgr_printinfo(&dep->de_lock);
                   1777: #endif
                   1778:
                   1779:        return (0);
                   1780: }
                   1781:
                   1782: int
                   1783: msdosfs_advlock(v)
                   1784:        void *v;
                   1785: {
                   1786:        struct vop_advlock_args *ap = v;
                   1787:        register struct denode *dep = VTODE(ap->a_vp);
                   1788:
                   1789:        return (lf_advlock(&dep->de_lockf, dep->de_FileSize, ap->a_id, ap->a_op,
                   1790:            ap->a_fl, ap->a_flags));
                   1791: }
                   1792:
                   1793: int
                   1794: msdosfs_pathconf(v)
                   1795:        void *v;
                   1796: {
                   1797:        struct vop_pathconf_args *ap = v;
                   1798:        struct msdosfsmount *pmp = VTODE(ap->a_vp)->de_pmp;
                   1799:
                   1800:        switch (ap->a_name) {
                   1801:        case _PC_LINK_MAX:
                   1802:                *ap->a_retval = 1;
                   1803:                return (0);
                   1804:        case _PC_NAME_MAX:
                   1805:                *ap->a_retval = pmp->pm_flags & MSDOSFSMNT_LONGNAME ? WIN_MAXLEN : 12;
                   1806:                return (0);
                   1807:        case _PC_PATH_MAX:
                   1808:                *ap->a_retval = PATH_MAX;
                   1809:                return (0);
                   1810:        case _PC_CHOWN_RESTRICTED:
                   1811:                *ap->a_retval = 1;
                   1812:                return (0);
                   1813:        case _PC_NO_TRUNC:
                   1814:                *ap->a_retval = 0;
                   1815:                return (0);
                   1816:        default:
                   1817:                return (EINVAL);
                   1818:        }
                   1819:        /* NOTREACHED */
                   1820: }
                   1821:
                   1822: /*
                   1823:  * Thomas Wang's hash function, severely hacked to always set the high
                   1824:  * bit on the number it returns (so no longer a proper hash function).
                   1825:  */
                   1826: static uint32_t
                   1827: fileidhash(uint64_t fileid)
                   1828: {
                   1829:        uint64_t c1 = 0x6e5ea73858134343LL;
                   1830:        uint64_t c2 = 0xb34e8f99a2ec9ef5LL;
                   1831:
                   1832:        /*
                   1833:         * We now have the original fileid value, as 64-bit value.
                   1834:         * We need to reduce it to 32-bits, with the top bit set.
                   1835:         */
                   1836:        fileid ^= ((c1 ^ fileid) >> 32);
                   1837:        fileid *= c1;
                   1838:        fileid ^= ((c2 ^ fileid) >> 31);
                   1839:        fileid *= c2;
                   1840:        fileid ^= ((c1 ^ fileid) >> 32);
                   1841:
                   1842:        return (uint32_t)(fileid | 0x80000000);
                   1843: }
                   1844:
                   1845: /* Global vfs data structures for msdosfs */
                   1846: int (**msdosfs_vnodeop_p)(void *);
                   1847: struct vnodeopv_entry_desc msdosfs_vnodeop_entries[] = {
                   1848:        { &vop_default_desc, vn_default_error },
                   1849:        { &vop_lookup_desc, msdosfs_lookup },           /* lookup */
                   1850:        { &vop_create_desc, msdosfs_create },           /* create */
                   1851:        { &vop_mknod_desc, msdosfs_mknod },             /* mknod */
                   1852:        { &vop_open_desc, msdosfs_open },               /* open */
                   1853:        { &vop_close_desc, msdosfs_close },             /* close */
                   1854:        { &vop_access_desc, msdosfs_access },           /* access */
                   1855:        { &vop_getattr_desc, msdosfs_getattr },         /* getattr */
                   1856:        { &vop_setattr_desc, msdosfs_setattr },         /* setattr */
                   1857:        { &vop_read_desc, msdosfs_read },               /* read */
                   1858:        { &vop_write_desc, msdosfs_write },             /* write */
                   1859:        { &vop_ioctl_desc, msdosfs_ioctl },             /* ioctl */
                   1860:        { &vop_poll_desc, msdosfs_poll },               /* poll */
                   1861:        { &vop_fsync_desc, msdosfs_fsync },             /* fsync */
                   1862:        { &vop_remove_desc, msdosfs_remove },           /* remove */
                   1863:        { &vop_link_desc, msdosfs_link },               /* link */
                   1864:        { &vop_rename_desc, msdosfs_rename },           /* rename */
                   1865:        { &vop_mkdir_desc, msdosfs_mkdir },             /* mkdir */
                   1866:        { &vop_rmdir_desc, msdosfs_rmdir },             /* rmdir */
                   1867:        { &vop_symlink_desc, msdosfs_symlink },         /* symlink */
                   1868:        { &vop_readdir_desc, msdosfs_readdir },         /* readdir */
                   1869:        { &vop_readlink_desc, msdosfs_readlink },       /* readlink */
                   1870:        { &vop_abortop_desc, vop_generic_abortop },     /* abortop */
                   1871:        { &vop_inactive_desc, msdosfs_inactive },       /* inactive */
                   1872:        { &vop_reclaim_desc, msdosfs_reclaim },         /* reclaim */
                   1873:        { &vop_lock_desc, msdosfs_lock },               /* lock */
                   1874:        { &vop_unlock_desc, msdosfs_unlock },           /* unlock */
                   1875:        { &vop_bmap_desc, msdosfs_bmap },               /* bmap */
                   1876:        { &vop_strategy_desc, msdosfs_strategy },       /* strategy */
                   1877:        { &vop_print_desc, msdosfs_print },             /* print */
                   1878:        { &vop_islocked_desc, msdosfs_islocked },       /* islocked */
                   1879:        { &vop_pathconf_desc, msdosfs_pathconf },       /* pathconf */
                   1880:        { &vop_advlock_desc, msdosfs_advlock },         /* advlock */
                   1881:        { &vop_bwrite_desc, vop_generic_bwrite },               /* bwrite */
                   1882:        { (struct vnodeop_desc *)NULL, (int (*)(void *))NULL }
                   1883: };
                   1884: struct vnodeopv_desc msdosfs_vnodeop_opv_desc =
                   1885:        { &msdosfs_vnodeop_p, msdosfs_vnodeop_entries };

CVSweb