root/msdosfs/msdosfs_vnops.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. msdosfs_create
  2. msdosfs_mknod
  3. msdosfs_open
  4. msdosfs_close
  5. msdosfs_access
  6. msdosfs_getattr
  7. msdosfs_setattr
  8. msdosfs_read
  9. msdosfs_write
  10. msdosfs_ioctl
  11. msdosfs_poll
  12. msdosfs_fsync
  13. msdosfs_remove
  14. msdosfs_link
  15. msdosfs_rename
  16. msdosfs_mkdir
  17. msdosfs_rmdir
  18. msdosfs_symlink
  19. msdosfs_readdir
  20. msdosfs_readlink
  21. msdosfs_lock
  22. msdosfs_unlock
  23. msdosfs_islocked
  24. msdosfs_bmap
  25. msdosfs_strategy
  26. msdosfs_print
  27. msdosfs_advlock
  28. msdosfs_pathconf
  29. fileidhash

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

/* [<][>][^][v][top][bottom][index][help] */