[BACK]Return to msdosfs_vnops.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sys / fs / msdosfs

Annotation of src/sys/fs/msdosfs/msdosfs_vnops.c, Revision 1.96

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

CVSweb <webmaster@jp.NetBSD.org>