The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/msdosfs/msdosfs_vnops.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /* $FreeBSD: src/sys/msdosfs/msdosfs_vnops.c,v 1.34.2.5 1999/09/05 08:17:22 peter Exp $ */
    2 /*      $NetBSD: msdosfs_vnops.c,v 1.68 1998/02/10 14:10:04 mrg Exp $   */
    3 
    4 /*-
    5  * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
    6  * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
    7  * All rights reserved.
    8  * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. All advertising materials mentioning features or use of this software
   19  *    must display the following acknowledgement:
   20  *      This product includes software developed by TooLs GmbH.
   21  * 4. The name of TooLs GmbH may not be used to endorse or promote products
   22  *    derived from this software without specific prior written permission.
   23  *
   24  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
   25  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   26  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   27  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   28  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   29  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
   30  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   31  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   32  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
   33  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   34  */
   35 /*
   36  * Written by Paul Popelka (paulp@uts.amdahl.com)
   37  *
   38  * You can do anything you want with this software, just don't say you wrote
   39  * it, and don't remove this notice.
   40  *
   41  * This software is provided "as is".
   42  *
   43  * The author supplies this software to be publicly redistributed on the
   44  * understanding that the author is not responsible for the correct
   45  * functioning of this software in any circumstances and is not liable for
   46  * any damages caused by this software.
   47  *
   48  * October 1992
   49  */
   50 
   51 #include <sys/param.h>
   52 #include <sys/systm.h>
   53 #include <sys/namei.h>
   54 #include <sys/resourcevar.h>    /* defines plimit structure in proc struct */
   55 #include <sys/kernel.h>
   56 #include <sys/stat.h>
   57 #include <sys/buf.h>
   58 #include <sys/proc.h>
   59 #include <sys/mount.h>
   60 #include <sys/unistd.h>
   61 #include <sys/vnode.h>
   62 #include <miscfs/specfs/specdev.h> /* XXX */    /* defines v_rdev */
   63 #include <sys/malloc.h>
   64 #ifdef __FreeBSD_version
   65 #include <sys/dirent.h>
   66 #else
   67 #include <sys/dir.h>
   68 #define GENERIC_DIRSIZ(a) DIRSIZ(a)
   69 #endif
   70 #include <sys/signalvar.h>
   71 
   72 #include <vm/vm.h>
   73 #include <vm/vm_extern.h>
   74 #ifdef __FreeBSD_version
   75 #include <vm/vm_zone.h>
   76 #endif
   77 #include <vm/vnode_pager.h>
   78 
   79 #include <msdosfs/bpb.h>
   80 #include <msdosfs/direntry.h>
   81 #include <msdosfs/denode.h>
   82 #include <msdosfs/msdosfsmount.h>
   83 #include <msdosfs/fat.h>
   84 
   85 /*
   86  * Prototypes for MSDOSFS vnode operations
   87  */
   88 static int msdosfs_create __P((struct vop_create_args *));
   89 static int msdosfs_mknod __P((struct vop_mknod_args *));
   90 #ifndef __FreeBSD_version
   91 static int msdosfs_open __P((struct vop_open_args *));
   92 static int msdosfs_ioctl __P((struct vop_ioctl_args *));
   93 static int msdosfs_select __P((struct vop_select_args *));
   94 static int msdosfs_mmap __P((struct vop_mmap_args *));
   95 static int msdosfs_seek __P((struct vop_seek_args *));
   96 static int msdosfs_lock __P((struct vop_lock_args *));
   97 static int msdosfs_unlock __P((struct vop_unlock_args *));
   98 static int msdosfs_readlink __P((struct vop_readlink_args *));
   99 static int msdosfs_islocked __P((struct vop_islocked_args *));
  100 static int msdosfs_advlock __P((struct vop_advlock_args *));
  101 static int msdosfs_reallocblks __P((struct vop_reallocblks_args *));
  102 #endif
  103 static int msdosfs_close __P((struct vop_close_args *));
  104 static int msdosfs_access __P((struct vop_access_args *));
  105 static int msdosfs_getattr __P((struct vop_getattr_args *));
  106 static int msdosfs_setattr __P((struct vop_setattr_args *));
  107 static int msdosfs_read __P((struct vop_read_args *));
  108 static int msdosfs_write __P((struct vop_write_args *));
  109 static int msdosfs_fsync __P((struct vop_fsync_args *));
  110 static int msdosfs_remove __P((struct vop_remove_args *));
  111 static int msdosfs_link __P((struct vop_link_args *));
  112 static int msdosfs_rename __P((struct vop_rename_args *));
  113 static int msdosfs_mkdir __P((struct vop_mkdir_args *));
  114 static int msdosfs_rmdir __P((struct vop_rmdir_args *));
  115 static int msdosfs_symlink __P((struct vop_symlink_args *));
  116 static int msdosfs_readdir __P((struct vop_readdir_args *));
  117 static int msdosfs_abortop __P((struct vop_abortop_args *));
  118 static int msdosfs_bmap __P((struct vop_bmap_args *));
  119 static int msdosfs_strategy __P((struct vop_strategy_args *));
  120 static int msdosfs_print __P((struct vop_print_args *));
  121 static int msdosfs_pathconf __P((struct vop_pathconf_args *ap));
  122 #ifdef __FreeBSD_version
  123 static int msdosfs_getpages __P((struct vop_getpages_args *));
  124 static int msdosfs_putpages __P((struct vop_putpages_args *));
  125 #else
  126 #define zfree(a, b) free(b, M_NAMEI)
  127 #define simple_lock(a)
  128 #define simple_unlock(a)
  129 #endif
  130 
  131 /*
  132  * Some general notes:
  133  *
  134  * In the ufs filesystem the inodes, superblocks, and indirect blocks are
  135  * read/written using the vnode for the filesystem. Blocks that represent
  136  * the contents of a file are read/written using the vnode for the file
  137  * (including directories when they are read/written as files). This
  138  * presents problems for the dos filesystem because data that should be in
  139  * an inode (if dos had them) resides in the directory itself.  Since we
  140  * must update directory entries without the benefit of having the vnode
  141  * for the directory we must use the vnode for the filesystem.  This means
  142  * that when a directory is actually read/written (via read, write, or
  143  * readdir, or seek) we must use the vnode for the filesystem instead of
  144  * the vnode for the directory as would happen in ufs. This is to insure we
  145  * retreive the correct block from the buffer cache since the hash value is
  146  * based upon the vnode address and the desired block number.
  147  */
  148 
  149 /*
  150  * Create a regular file. On entry the directory to contain the file being
  151  * created is locked.  We must release before we return. We must also free
  152  * the pathname buffer pointed at by cnp->cn_pnbuf, always on error, or
  153  * only if the SAVESTART bit in cn_flags is clear on success.
  154  */
  155 static int
  156 msdosfs_create(ap)
  157         struct vop_create_args /* {
  158                 struct vnode *a_dvp;
  159                 struct vnode **a_vpp;
  160                 struct componentname *a_cnp;
  161                 struct vattr *a_vap;
  162         } */ *ap;
  163 {
  164         struct componentname *cnp = ap->a_cnp;
  165         struct denode ndirent;
  166         struct denode *dep;
  167         struct denode *pdep = VTODE(ap->a_dvp);
  168         struct timespec ts;
  169         int error;
  170 
  171 #ifdef MSDOSFS_DEBUG
  172         printf("msdosfs_create(cnp %p, vap %p\n", cnp, ap->a_vap);
  173 #endif
  174 
  175         /*
  176          * If this is the root directory and there is no space left we
  177          * can't do anything.  This is because the root directory can not
  178          * change size.
  179          */
  180         if (pdep->de_StartCluster == MSDOSFSROOT
  181             && pdep->de_fndoffset >= pdep->de_FileSize) {
  182                 error = ENOSPC;
  183                 goto bad;
  184         }
  185 
  186         /*
  187          * Create a directory entry for the file, then call createde() to
  188          * have it installed. NOTE: DOS files are always executable.  We
  189          * use the absence of the owner write bit to make the file
  190          * readonly.
  191          */
  192 #ifdef DIAGNOSTIC
  193         if ((cnp->cn_flags & HASBUF) == 0)
  194                 panic("msdosfs_create: no name");
  195 #endif
  196         bzero(&ndirent, sizeof(ndirent));
  197         error = uniqdosname(pdep, cnp, ndirent.de_Name);
  198         if (error)
  199                 goto bad;
  200 
  201         ndirent.de_Attributes = (ap->a_vap->va_mode & VWRITE) ?
  202                                 ATTR_ARCHIVE : ATTR_ARCHIVE | ATTR_READONLY;
  203         ndirent.de_StartCluster = 0;
  204         ndirent.de_FileSize = 0;
  205         ndirent.de_dev = pdep->de_dev;
  206         ndirent.de_devvp = pdep->de_devvp;
  207         ndirent.de_pmp = pdep->de_pmp;
  208         ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE;
  209 #ifdef __FreeBSD_version
  210         getnanotime(&ts);
  211 #else
  212         TIMEVAL_TO_TIMESPEC(&time, &ts);
  213 #endif
  214         DETIMES(&ndirent, &ts, &ts, &ts);
  215         error = createde(&ndirent, pdep, &dep, cnp);
  216         if (error)
  217                 goto bad;
  218         if ((cnp->cn_flags & SAVESTART) == 0)
  219                 zfree(namei_zone, cnp->cn_pnbuf);
  220 #ifndef __FreeBSD_version
  221         vput(ap->a_dvp);
  222 #endif
  223         *ap->a_vpp = DETOV(dep);
  224         return (0);
  225 
  226 bad:
  227         zfree(namei_zone, cnp->cn_pnbuf);
  228 #ifndef __FreeBSD_version
  229         vput(ap->a_dvp);
  230 #endif
  231         return (error);
  232 }
  233 
  234 static int
  235 msdosfs_mknod(ap)
  236         struct vop_mknod_args /* {
  237                 struct vnode *a_dvp;
  238                 struct vnode **a_vpp;
  239                 struct componentname *a_cnp;
  240                 struct vattr *a_vap;
  241         } */ *ap;
  242 {
  243 
  244         switch (ap->a_vap->va_type) {
  245         case VDIR:
  246                 return (msdosfs_mkdir((struct vop_mkdir_args *)ap));
  247                 break;
  248 
  249         case VREG:
  250                 return (msdosfs_create((struct vop_create_args *)ap));
  251                 break;
  252 
  253         default:
  254                 zfree(namei_zone, ap->a_cnp->cn_pnbuf);
  255 #ifndef __FreeBSD_version
  256                 vput(ap->a_dvp);
  257 #endif
  258                 return (EINVAL);
  259         }
  260         /* NOTREACHED */
  261 }
  262 #ifndef __FreeBSD_version
  263 static int
  264 msdosfs_open(ap)
  265         struct vop_open_args /* {
  266                 struct vnode *a_vp;
  267                 int a_mode;
  268                 struct ucred *a_cred;
  269                 struct proc *a_p;
  270         } */ *ap;
  271 {
  272         return 0;
  273 }
  274 
  275 static int
  276 msdosfs_ioctl(ap)
  277         struct vop_ioctl_args /* {
  278                 struct vnode *a_vp;
  279                 int a_command;
  280                 caddr_t a_data;
  281                 int a_fflag;
  282                 struct ucred *a_cred;
  283                 struct proc *a_p;
  284         } */ *ap;
  285 {
  286         return ENOTTY;
  287 }
  288 static int
  289 msdosfs_select(ap)
  290         struct vop_select_args /* {
  291                 struct vnode *a_vp;
  292                 int a_which;
  293                 int a_fflags;
  294                 struct ucred *a_cred;
  295                 struct proc *a_p;
  296         } */ *ap;
  297 {
  298         return 1;               /* DOS filesystems never block? */
  299 }
  300 
  301 static int
  302 msdosfs_mmap(ap)
  303         struct vop_mmap_args /* {
  304                 struct vnode *a_vp;
  305                 int a_fflags;
  306                 struct ucred *a_cred;
  307                 struct proc *a_p;
  308         } */ *ap;
  309 {
  310         return EINVAL;
  311 }
  312 
  313 /*
  314  * Now the whole work of extending a file is done in the write function.
  315  * So nothing to do here.
  316  */
  317 static int
  318 msdosfs_seek(ap)
  319         struct vop_seek_args /* {
  320                 struct vnode *a_vp;
  321                 off_t a_oldoff;
  322                 off_t a_newoff;
  323                 struct ucred *a_cred;
  324         } */ *ap;
  325 {
  326         return 0;
  327 }
  328 
  329 static int msdosfslockdebug = 0;
  330 
  331 static int
  332 msdosfs_lock(ap)
  333         struct vop_lock_args /* {
  334                 struct vnode *a_vp;
  335         } */ *ap;
  336 {
  337         struct denode *dep = VTODE(ap->a_vp);
  338 
  339         if (msdosfslockdebug)
  340                 printf("vnode %x locking\n", dep);
  341         while (dep->de_flag & DE_LOCKED) {
  342                 if (dep->de_lockholder == curproc->p_pid) {
  343                         if ((dep->de_flag & DE_RECURSE) == 0)
  344                                 panic("msdosfs_lock: locking against myself");
  345                         else {
  346                                 ++dep->de_lockcount;
  347         if (msdosfslockdebug)
  348         printf("vnode %x countup, de_lockcount = %d\n", dep, dep->de_lockcount);
  349                                 return 0;
  350                         }
  351                 }
  352                 dep->de_flag |= DE_WANTED;
  353                 dep->de_lockwaiter = curproc->p_pid;
  354                 (void) tsleep((caddr_t) dep, PINOD, "msdlck", 0);
  355         }
  356         dep->de_lockwaiter = 0;
  357         dep->de_lockholder = curproc->p_pid;
  358         dep->de_flag |= DE_LOCKED;
  359         if (msdosfslockdebug)
  360                 printf("vnode %x locked, de_lockcount = %d\n", dep, dep->de_lockcount);
  361         return 0;
  362 }
  363 
  364 static int
  365 msdosfs_unlock(ap)
  366         struct vop_unlock_args /* {
  367                 struct vnode *vp;
  368         } */ *ap;
  369 {
  370         struct denode *dep = VTODE(ap->a_vp);
  371 
  372         if (msdosfslockdebug)
  373                 printf("vnode %x unlocked, de_lockcount = %d\n", dep, dep->de_lockcount);
  374         if(dep->de_lockcount > 0) {
  375                 --dep->de_lockcount;
  376                 return 0;
  377         }
  378         if (!(dep->de_flag & DE_LOCKED))
  379                 panic("msdosfs_unlock: denode not locked");
  380         dep->de_lockholder = 0;
  381         dep->de_flag &= ~(DE_LOCKED|DE_RECURSE);
  382         if (dep->de_flag & DE_WANTED) {
  383                 dep->de_flag &= ~DE_WANTED;
  384                 wakeup((caddr_t) dep);
  385         }
  386         return 0;
  387 }
  388 
  389 /*
  390  * DOS filesystems don't know what symlinks are.
  391  */
  392 static int
  393 msdosfs_readlink(ap)
  394         struct vop_readlink_args /* {
  395                 struct vnode *a_vp;
  396                 struct uio *a_uio;
  397                 struct ucred *a_cred;
  398         } */ *ap;
  399 {
  400         return EINVAL;
  401 }
  402 
  403 static int
  404 msdosfs_islocked(ap)
  405         struct vop_islocked_args /* {
  406                 struct vnode *a_vp;
  407         } */ *ap;
  408 {
  409         return VTODE(ap->a_vp)->de_flag & DE_LOCKED ? 1 : 0;
  410 }
  411 
  412 static int
  413 msdosfs_advlock(ap)
  414         struct vop_advlock_args /* {
  415                 struct vnode *a_vp;
  416                 caddr_t a_id;
  417                 int a_op;
  418                 struct flock *a_fl;
  419                 int a_flags;
  420         } */ *ap;
  421 {
  422         return EINVAL;          /* we don't do locking yet               */
  423 }
  424 
  425 static int
  426 msdosfs_reallocblks(ap)
  427         struct vop_reallocblks_args /* {
  428                 struct vnode *a_vp;
  429                 struct cluster_save *a_buflist;
  430         } */ *ap;
  431 {
  432         /* Currently no support for clustering */               /* XXX */
  433         return ENOSPC;
  434 }
  435 
  436 #endif
  437 
  438 static int
  439 msdosfs_close(ap)
  440         struct vop_close_args /* {
  441                 struct vnode *a_vp;
  442                 int a_fflag;
  443                 struct ucred *a_cred;
  444                 struct proc *a_p;
  445         } */ *ap;
  446 {
  447         struct vnode *vp = ap->a_vp;
  448         struct denode *dep = VTODE(vp);
  449         struct timespec ts;
  450 
  451         simple_lock(&vp->v_interlock);
  452         if (vp->v_usecount > 1) {
  453 #ifdef __FreeBSD_version
  454                 getnanotime(&ts);
  455 #else
  456                 TIMEVAL_TO_TIMESPEC(&time, &ts);
  457 #endif
  458                 DETIMES(dep, &ts, &ts, &ts);
  459         }
  460         simple_unlock(&vp->v_interlock);
  461         return 0;
  462 }
  463 
  464 static int
  465 msdosfs_access(ap)
  466         struct vop_access_args /* {
  467                 struct vnode *a_vp;
  468                 int a_mode;
  469                 struct ucred *a_cred;
  470                 struct proc *a_p;
  471         } */ *ap;
  472 {
  473         struct vnode *vp = ap->a_vp;
  474         struct denode *dep = VTODE(ap->a_vp);
  475         struct msdosfsmount *pmp = dep->de_pmp;
  476         struct ucred *cred = ap->a_cred;
  477         mode_t mask, file_mode, mode = ap->a_mode;
  478         register gid_t *gp;
  479         int i;
  480 
  481         file_mode = (S_IXUSR|S_IXGRP|S_IXOTH) | (S_IRUSR|S_IRGRP|S_IROTH) |
  482             ((dep->de_Attributes & ATTR_READONLY) ? 0 : (S_IWUSR|S_IWGRP|S_IWOTH));
  483         file_mode &= pmp->pm_mask;
  484 
  485         /*
  486          * Disallow write attempts on read-only file systems;
  487          * unless the file is a socket, fifo, or a block or
  488          * character device resident on the file system.
  489          */
  490         if (mode & VWRITE) {
  491                 switch (vp->v_type) {
  492                 case VDIR:
  493                 case VLNK:
  494                 case VREG:
  495                         if (vp->v_mount->mnt_flag & MNT_RDONLY)
  496                                 return (EROFS);
  497                         break;
  498                 }
  499         }
  500 
  501         /* User id 0 always gets access. */
  502         if (cred->cr_uid == 0)
  503                 return 0;
  504 
  505         mask = 0;
  506 
  507         /* Otherwise, check the owner. */
  508         if (cred->cr_uid == pmp->pm_uid) {
  509                 if (mode & VEXEC)
  510                         mask |= S_IXUSR;
  511                 if (mode & VREAD)
  512                         mask |= S_IRUSR;
  513                 if (mode & VWRITE)
  514                         mask |= S_IWUSR;
  515                 return (file_mode & mask) == mask ? 0 : EACCES;
  516         }
  517 
  518         /* Otherwise, check the groups. */
  519         for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++)
  520                 if (pmp->pm_gid == *gp) {
  521                         if (mode & VEXEC)
  522                                 mask |= S_IXGRP;
  523                         if (mode & VREAD)
  524                                 mask |= S_IRGRP;
  525                         if (mode & VWRITE)
  526                                 mask |= S_IWGRP;
  527                         return (file_mode & mask) == mask ? 0 : EACCES;
  528                 }
  529 
  530         /* Otherwise, check everyone else. */
  531         if (mode & VEXEC)
  532                 mask |= S_IXOTH;
  533         if (mode & VREAD)
  534                 mask |= S_IROTH;
  535         if (mode & VWRITE)
  536                 mask |= S_IWOTH;
  537         return (file_mode & mask) == mask ? 0 : EACCES;
  538 }
  539 
  540 static int
  541 msdosfs_getattr(ap)
  542         struct vop_getattr_args /* {
  543                 struct vnode *a_vp;
  544                 struct vattr *a_vap;
  545                 struct ucred *a_cred;
  546                 struct proc *a_p;
  547         } */ *ap;
  548 {
  549         u_int cn;
  550         struct denode *dep = VTODE(ap->a_vp);
  551         struct msdosfsmount *pmp = dep->de_pmp;
  552         struct vattr *vap = ap->a_vap;
  553         mode_t mode;
  554         struct timespec ts;
  555         u_long dirsperblk = pmp->pm_BytesPerSec / sizeof(struct direntry);
  556         u_long fileid;
  557 
  558 #ifdef __FreeBSD_version
  559         getnanotime(&ts);
  560 #else
  561         TIMEVAL_TO_TIMESPEC(&time, &ts);
  562 #endif
  563         DETIMES(dep, &ts, &ts, &ts);
  564         vap->va_fsid = dep->de_dev;
  565         /*
  566          * The following computation of the fileid must be the same as that
  567          * used in msdosfs_readdir() to compute d_fileno. If not, pwd
  568          * doesn't work.
  569          */
  570         if (dep->de_Attributes & ATTR_DIRECTORY) {
  571                 fileid = cntobn(pmp, dep->de_StartCluster) * dirsperblk;
  572                 if (dep->de_StartCluster == MSDOSFSROOT)
  573                         fileid = 1;
  574         } else {
  575                 fileid = cntobn(pmp, dep->de_dirclust) * dirsperblk;
  576                 if (dep->de_dirclust == MSDOSFSROOT)
  577                         fileid = roottobn(pmp, 0) * dirsperblk;
  578                 fileid += dep->de_diroffset / sizeof(struct direntry);
  579         }
  580         vap->va_fileid = fileid;
  581         if ((dep->de_Attributes & ATTR_READONLY) == 0)
  582                 mode = S_IRWXU|S_IRWXG|S_IRWXO;
  583         else
  584                 mode = S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP|S_IROTH|S_IXOTH;
  585         vap->va_mode = mode & pmp->pm_mask;
  586         vap->va_uid = pmp->pm_uid;
  587         vap->va_gid = pmp->pm_gid;
  588         vap->va_nlink = 1;
  589         vap->va_rdev = 0;
  590         vap->va_size = dep->de_FileSize;
  591         dos2unixtime(dep->de_MDate, dep->de_MTime, 0, &vap->va_mtime);
  592         if (pmp->pm_flags & MSDOSFSMNT_LONGNAME) {
  593                 dos2unixtime(dep->de_ADate, 0, 0, &vap->va_atime);
  594                 dos2unixtime(dep->de_CDate, dep->de_CTime, dep->de_CHun, &vap->va_ctime);
  595         } else {
  596                 vap->va_atime = vap->va_mtime;
  597                 vap->va_ctime = vap->va_mtime;
  598         }
  599         vap->va_flags = 0;
  600         if ((dep->de_Attributes & ATTR_ARCHIVE) == 0)
  601                 vap->va_flags |= SF_ARCHIVED;
  602         vap->va_gen = 0;
  603         vap->va_blocksize = pmp->pm_bpcluster;
  604         vap->va_bytes =
  605             (dep->de_FileSize + pmp->pm_crbomask) & ~pmp->pm_crbomask;
  606         vap->va_type = ap->a_vp->v_type;
  607         vap->va_filerev = dep->de_modrev;
  608         return (0);
  609 }
  610 
  611 static int
  612 msdosfs_setattr(ap)
  613         struct vop_setattr_args /* {
  614                 struct vnode *a_vp;
  615                 struct vattr *a_vap;
  616                 struct ucred *a_cred;
  617                 struct proc *a_p;
  618         } */ *ap;
  619 {
  620         struct vnode *vp = ap->a_vp;
  621         struct denode *dep = VTODE(ap->a_vp);
  622         struct msdosfsmount *pmp = dep->de_pmp;
  623         struct vattr *vap = ap->a_vap;
  624         struct ucred *cred = ap->a_cred;
  625         int error = 0;
  626 
  627 #ifdef MSDOSFS_DEBUG
  628         printf("msdosfs_setattr(): vp %p, vap %p, cred %p, p %p\n",
  629             ap->a_vp, vap, cred, ap->a_p);
  630 #endif
  631 
  632         /*
  633          * Check for unsettable attributes.
  634          */
  635         if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
  636             (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
  637             (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
  638             (vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
  639 #ifdef MSDOSFS_DEBUG
  640                 printf("msdosfs_setattr(): returning EINVAL\n");
  641                 printf("    va_type %d, va_nlink %x, va_fsid %lx, va_fileid %lx\n",
  642                     vap->va_type, vap->va_nlink, vap->va_fsid, vap->va_fileid);
  643                 printf("    va_blocksize %lx, va_rdev %x, va_bytes %qx, va_gen %lx\n",
  644                     vap->va_blocksize, vap->va_rdev, vap->va_bytes, vap->va_gen);
  645                 printf("    va_uid %x, va_gid %x\n",
  646                     vap->va_uid, vap->va_gid);
  647 #endif
  648                 return (EINVAL);
  649         }
  650         if (vap->va_flags != VNOVAL) {
  651                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
  652                         return (EROFS);
  653                 if (cred->cr_uid != pmp->pm_uid &&
  654                     (error = suser(cred, &ap->a_p->p_acflag)))
  655                         return (error);
  656                 /*
  657                  * We are very inconsistent about handling unsupported
  658                  * attributes.  We ignored the access time and the
  659                  * read and execute bits.  We were strict for the other
  660                  * attributes.
  661                  *
  662                  * Here we are strict, stricter than ufs in not allowing
  663                  * users to attempt to set SF_SETTABLE bits or anyone to
  664                  * set unsupported bits.  However, we ignore attempts to
  665                  * set ATTR_ARCHIVE for directories `cp -pr' from a more
  666                  * sensible file system attempts it a lot.
  667                  */
  668                 if (cred->cr_uid != 0) {
  669                         if (vap->va_flags & SF_SETTABLE)
  670                                 return EPERM;
  671                 }
  672                 if (vap->va_flags & ~SF_ARCHIVED)
  673                         return EOPNOTSUPP;
  674                 if (vap->va_flags & SF_ARCHIVED)
  675                         dep->de_Attributes &= ~ATTR_ARCHIVE;
  676                 else if (!(dep->de_Attributes & ATTR_DIRECTORY))
  677                         dep->de_Attributes |= ATTR_ARCHIVE;
  678                 dep->de_flag |= DE_MODIFIED;
  679         }
  680 
  681         if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
  682                 uid_t uid;
  683                 gid_t gid;
  684                 
  685                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
  686                         return (EROFS);
  687                 uid = vap->va_uid;
  688                 if (uid == (uid_t)VNOVAL)
  689                         uid = pmp->pm_uid;
  690                 gid = vap->va_gid;
  691                 if (gid == (gid_t)VNOVAL)
  692                         gid = pmp->pm_gid;
  693                 if ((cred->cr_uid != pmp->pm_uid || uid != pmp->pm_uid ||
  694                     (gid != pmp->pm_gid && !groupmember(gid, cred))) &&
  695                     (error = suser(cred, &ap->a_p->p_acflag)))
  696                         return error;
  697                 if (uid != pmp->pm_uid || gid != pmp->pm_gid)
  698                         return EINVAL;
  699         }
  700 
  701         if (vap->va_size != VNOVAL) {
  702                 /*
  703                  * Disallow write attempts on read-only file systems;
  704                  * unless the file is a socket, fifo, or a block or
  705                  * character device resident on the file system.
  706                  */
  707                 switch (vp->v_type) {
  708                 case VDIR:
  709                         return (EISDIR);
  710                 case VLNK:
  711                 case VREG:
  712                         if (vp->v_mount->mnt_flag & MNT_RDONLY)
  713                                 return (EROFS);
  714                         break;
  715                 }
  716                 error = detrunc(dep, vap->va_size, 0, cred, ap->a_p);
  717                 if (error)
  718                         return error;
  719         }
  720         if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
  721                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
  722                         return (EROFS);
  723                 if (cred->cr_uid != pmp->pm_uid &&
  724                     (error = suser(cred, &ap->a_p->p_acflag)) &&
  725                     ((vap->va_vaflags & VA_UTIMES_NULL) == 0 ||
  726                     (error = VOP_ACCESS(ap->a_vp, VWRITE, cred, ap->a_p))))
  727                         return (error);
  728                 if (vp->v_type != VDIR) {
  729                         if ((pmp->pm_flags & MSDOSFSMNT_NOWIN95) == 0 &&
  730                             vap->va_atime.tv_sec != VNOVAL) {
  731                                 unix2dostime(&vap->va_atime, &dep->de_ADate, NULL, NULL);
  732 #ifndef __FreeBSD_version
  733                                 dep->de_flag &= ~DE_ACCESS;
  734 #endif
  735                         }
  736                         if (vap->va_mtime.tv_sec != VNOVAL){
  737                                 unix2dostime(&vap->va_mtime, &dep->de_MDate, &dep->de_MTime, NULL);
  738 #ifndef __FreeBSD_version
  739                                 dep->de_flag &= ~DE_UPDATE;
  740 #endif
  741                         }
  742 
  743                         dep->de_Attributes |= ATTR_ARCHIVE;
  744                         dep->de_flag |= DE_MODIFIED;
  745                 }
  746         }
  747         /*
  748          * DOS files only have the ability to have their writability
  749          * attribute set, so we use the owner write bit to set the readonly
  750          * attribute.
  751          */
  752         if (vap->va_mode != (mode_t)VNOVAL) {
  753                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
  754                         return (EROFS);
  755                 if (cred->cr_uid != pmp->pm_uid &&
  756                     (error = suser(cred, &ap->a_p->p_acflag)))
  757                         return (error);
  758                 if (vp->v_type != VDIR) {
  759                         /* We ignore the read and execute bits. */
  760                         if (vap->va_mode & VWRITE)
  761                                 dep->de_Attributes &= ~ATTR_READONLY;
  762                         else
  763                                 dep->de_Attributes |= ATTR_READONLY;
  764                         dep->de_flag |= DE_MODIFIED;
  765                 }
  766         }
  767         return (deupdat(dep, 1));
  768 }
  769 
  770 static int
  771 msdosfs_read(ap)
  772         struct vop_read_args /* {
  773                 struct vnode *a_vp;
  774                 struct uio *a_uio;
  775                 int a_ioflag;
  776                 struct ucred *a_cred;
  777         } */ *ap;
  778 {
  779         int error = 0;
  780         int diff;
  781         int blsize;
  782         int isadir;
  783         long n;
  784         long on;
  785         daddr_t lbn;
  786         daddr_t rablock;
  787         int rasize;
  788         struct buf *bp;
  789         struct vnode *vp = ap->a_vp;
  790         struct denode *dep = VTODE(vp);
  791         struct msdosfsmount *pmp = dep->de_pmp;
  792         struct uio *uio = ap->a_uio;
  793 
  794         /*
  795          * If they didn't ask for any data, then we are done.
  796          */
  797         if (uio->uio_resid == 0)
  798                 return (0);
  799         if (uio->uio_offset < 0)
  800                 return (EINVAL);
  801 
  802         isadir = dep->de_Attributes & ATTR_DIRECTORY;
  803         do {
  804                 lbn = de_cluster(pmp, uio->uio_offset);
  805                 on = uio->uio_offset & pmp->pm_crbomask;
  806                 n = min((u_long) (pmp->pm_bpcluster - on), uio->uio_resid);
  807                 diff = dep->de_FileSize - uio->uio_offset;
  808                 if (diff <= 0)
  809                         return (0);
  810                 if (diff < n)
  811                         n = diff;
  812                 /* convert cluster # to block # if a directory */
  813                 if (isadir) {
  814                         error = pcbmap(dep, lbn, &lbn, 0, &blsize);
  815                         if (error)
  816                                 return (error);
  817                 }
  818                 /*
  819                  * If we are operating on a directory file then be sure to
  820                  * do i/o with the vnode for the filesystem instead of the
  821                  * vnode for the directory.
  822                  */
  823                 if (isadir) {
  824                         error = bread(pmp->pm_devvp, lbn, blsize, NOCRED, &bp);
  825                 } else {
  826                         rablock = lbn + 1;
  827 #ifdef  PC98
  828                         /*
  829                          * 1024byte/sector support
  830                          */
  831                         if (pmp->pm_BytesPerSec == 1024)
  832                                         vp->v_flag |= 0x10000;
  833 #endif
  834                         if (vp->v_lastr + 1 == lbn &&
  835                             de_cn2off(pmp, rablock) < dep->de_FileSize) {
  836                                 rasize = pmp->pm_bpcluster;
  837                                 error = breadn(vp, lbn, pmp->pm_bpcluster,
  838                                     &rablock, &rasize, 1, NOCRED, &bp); 
  839                         } else
  840                                 error = bread(vp, lbn, pmp->pm_bpcluster, 
  841                                     NOCRED, &bp);
  842                         vp->v_lastr = lbn;
  843                 }
  844                 n = min(n, pmp->pm_bpcluster - bp->b_resid);
  845                 if (error) {
  846                         brelse(bp);
  847                         return (error);
  848                 }
  849                 error = uiomove(bp->b_data + on, (int) n, uio);
  850                 if (!isadir)
  851                         dep->de_flag |= DE_ACCESS;
  852                 brelse(bp);
  853         } while (error == 0 && uio->uio_resid > 0 && n != 0);
  854         return (error);
  855 }
  856 
  857 /*
  858  * Write data to a file or directory.
  859  */
  860 static int
  861 msdosfs_write(ap)
  862         struct vop_write_args /* {
  863                 struct vnode *a_vp;
  864                 struct uio *a_uio;
  865                 int a_ioflag;
  866                 struct ucred *a_cred;
  867         } */ *ap;
  868 {
  869         int n;
  870         int croffset;
  871         int resid;
  872         u_long osize;
  873         int error = 0;
  874         u_long count;
  875         daddr_t bn, lastcn;
  876         struct buf *bp;
  877         int ioflag = ap->a_ioflag;
  878         struct uio *uio = ap->a_uio;
  879         struct proc *p = uio->uio_procp;
  880         struct vnode *vp = ap->a_vp;
  881         struct vnode *thisvp;
  882         struct denode *dep = VTODE(vp);
  883         struct msdosfsmount *pmp = dep->de_pmp;
  884         struct ucred *cred = ap->a_cred;
  885 
  886 #ifdef MSDOSFS_DEBUG
  887         printf("msdosfs_write(vp %p, uio %p, ioflag %x, cred %p\n",
  888             vp, uio, ioflag, cred);
  889         printf("msdosfs_write(): diroff %lu, dirclust %lu, startcluster %lu\n",
  890             dep->de_diroffset, dep->de_dirclust, dep->de_StartCluster);
  891 #endif
  892 
  893         switch (vp->v_type) {
  894         case VREG:
  895                 if (ioflag & IO_APPEND)
  896                         uio->uio_offset = dep->de_FileSize;
  897                 thisvp = vp;
  898                 break;
  899         case VDIR:
  900                 return EISDIR;
  901         default:
  902                 panic("msdosfs_write(): bad file type");
  903         }
  904 
  905         if (uio->uio_offset < 0)
  906                 return (EINVAL);
  907 
  908         if (uio->uio_resid == 0)
  909                 return (0);
  910 
  911         /*
  912          * If they've exceeded their filesize limit, tell them about it.
  913          */
  914         if (p &&
  915             ((uio->uio_offset + uio->uio_resid) >
  916             p->p_rlimit[RLIMIT_FSIZE].rlim_cur)) {
  917                 psignal(p, SIGXFSZ);
  918                 return (EFBIG);
  919         }
  920 
  921         /*
  922          * If the offset we are starting the write at is beyond the end of
  923          * the file, then they've done a seek.  Unix filesystems allow
  924          * files with holes in them, DOS doesn't so we must fill the hole
  925          * with zeroed blocks.
  926          */
  927         if (uio->uio_offset > dep->de_FileSize) {
  928                 error = deextend(dep, uio->uio_offset, cred);
  929                 if (error)
  930                         return (error);
  931         }
  932 
  933         /*
  934          * Remember some values in case the write fails.
  935          */
  936         resid = uio->uio_resid;
  937         osize = dep->de_FileSize;
  938 
  939 #ifdef  PC98
  940         /*
  941          * 1024byte/sector support
  942          */
  943         if (pmp->pm_BytesPerSec == 1024)
  944                 thisvp->v_flag |= 0x10000;
  945 #endif
  946         /*
  947          * If we write beyond the end of the file, extend it to its ultimate
  948          * size ahead of the time to hopefully get a contiguous area.
  949          */
  950         if (uio->uio_offset + resid > osize) {
  951                 count = de_clcount(pmp, uio->uio_offset + resid) -
  952                         de_clcount(pmp, osize);
  953                 error = extendfile(dep, count, NULL, NULL, 0);
  954                 if (error &&  (error != ENOSPC || (ioflag & IO_UNIT)))
  955                         goto errexit;
  956                 lastcn = dep->de_fc[FC_LASTFC].fc_frcn;
  957         } else
  958                 lastcn = de_clcount(pmp, osize) - 1;
  959 
  960         do {
  961                 if (de_cluster(pmp, uio->uio_offset) > lastcn) {
  962                         error = ENOSPC;
  963                         break;
  964                 }
  965 
  966                 croffset = uio->uio_offset & pmp->pm_crbomask;
  967                 n = min(uio->uio_resid, pmp->pm_bpcluster - croffset);
  968                 if (uio->uio_offset + n > dep->de_FileSize) {
  969                         dep->de_FileSize = uio->uio_offset + n;
  970                         /* The object size needs to be set before buffer is allocated */
  971                         vnode_pager_setsize(vp, dep->de_FileSize);
  972                 }
  973 
  974                 bn = de_cluster(pmp, uio->uio_offset);
  975                 if ((uio->uio_offset & pmp->pm_crbomask) == 0
  976                     && (de_cluster(pmp, uio->uio_offset + uio->uio_resid) 
  977                         > de_cluster(pmp, uio->uio_offset)
  978                         || uio->uio_offset + uio->uio_resid >= dep->de_FileSize)) {
  979                         /*
  980                          * If either the whole cluster gets written,
  981                          * or we write the cluster from its start beyond EOF,
  982                          * then no need to read data from disk.
  983                          */
  984                         bp = getblk(thisvp, bn, pmp->pm_bpcluster, 0, 0);
  985                         clrbuf(bp);
  986                         /*
  987                          * Do the bmap now, since pcbmap needs buffers
  988                          * for the fat table. (see msdosfs_strategy)
  989                          */
  990                         if (bp->b_blkno == bp->b_lblkno) {
  991                                 error = pcbmap(dep, bp->b_lblkno, &bp->b_blkno, 
  992                                      0, 0);
  993                                 if (error)
  994                                         bp->b_blkno = -1;
  995                         }
  996                         if (bp->b_blkno == -1) {
  997                                 brelse(bp);
  998                                 if (!error)
  999                                         error = EIO;            /* XXX */
 1000                                 break;
 1001                         }
 1002                 } else {
 1003                         /*
 1004                          * The block we need to write into exists, so read it in.
 1005                          */
 1006                         error = bread(thisvp, bn, pmp->pm_bpcluster, cred, &bp);
 1007                         if (error) {
 1008                                 brelse(bp);
 1009                                 break;
 1010                         }
 1011                 }
 1012 
 1013                 /*
 1014                  * Should these vnode_pager_* functions be done on dir
 1015                  * files?
 1016                  */
 1017 
 1018                 /*
 1019                  * Copy the data from user space into the buf header.
 1020                  */
 1021                 error = uiomove(bp->b_data + croffset, n, uio);
 1022 
 1023                 /*
 1024                  * If they want this synchronous then write it and wait for
 1025                  * it.  Otherwise, if on a cluster boundary write it
 1026                  * asynchronously so we can move on to the next block
 1027                  * without delay.  Otherwise do a delayed write because we
 1028                  * may want to write somemore into the block later.
 1029                  */
 1030                 if (ioflag & IO_SYNC)
 1031                         (void) bwrite(bp);
 1032                 else if (n + croffset == pmp->pm_bpcluster)
 1033                         bawrite(bp);
 1034                 else
 1035                         bdwrite(bp);
 1036                 dep->de_flag |= DE_UPDATE;
 1037         } while (error == 0 && uio->uio_resid > 0);
 1038 
 1039         /*
 1040          * If the write failed and they want us to, truncate the file back
 1041          * to the size it was before the write was attempted.
 1042          */
 1043 errexit:
 1044         if (error) {
 1045                 if (ioflag & IO_UNIT) {
 1046                         detrunc(dep, osize, ioflag & IO_SYNC, NOCRED, NULL);
 1047                         uio->uio_offset -= resid - uio->uio_resid;
 1048                         uio->uio_resid = resid;
 1049                 } else {
 1050                         detrunc(dep, dep->de_FileSize, ioflag & IO_SYNC, NOCRED, NULL);
 1051                         if (uio->uio_resid != resid)
 1052                                 error = 0;
 1053                 }
 1054         } else if (ioflag & IO_SYNC)
 1055                 error = deupdat(dep, 1);
 1056         return (error);
 1057 }
 1058 
 1059 /*
 1060  * Flush the blocks of a file to disk.
 1061  *
 1062  * This function is worthless for vnodes that represent directories. Maybe we
 1063  * could just do a sync if they try an fsync on a directory file.
 1064  */
 1065 static int
 1066 msdosfs_fsync(ap)
 1067         struct vop_fsync_args /* {
 1068                 struct vnode *a_vp;
 1069                 struct ucred *a_cred;
 1070                 int a_waitfor;
 1071                 struct proc *a_p;
 1072         } */ *ap;
 1073 {
 1074         struct vnode *vp = ap->a_vp;
 1075         int s;
 1076         struct buf *bp, *nbp;
 1077 
 1078         /*
 1079          * Flush all dirty buffers associated with a vnode.
 1080          */
 1081 loop:
 1082         s = splbio();
 1083         for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
 1084                 nbp = bp->b_vnbufs.le_next;
 1085                 if ((bp->b_flags & B_BUSY))
 1086                         continue;
 1087                 if ((bp->b_flags & B_DELWRI) == 0)
 1088                         panic("msdosfs_fsync: not dirty");
 1089                 bremfree(bp);
 1090                 bp->b_flags |= B_BUSY;
 1091                 splx(s);
 1092                 (void) bwrite(bp);
 1093                 goto loop;
 1094         }
 1095         while (vp->v_numoutput) {
 1096                 vp->v_flag |= VBWAIT;
 1097                 (void) tsleep((caddr_t)&vp->v_numoutput, PRIBIO + 1, "msdosfsn", 0);
 1098         }
 1099 #ifdef DIAGNOSTIC
 1100         if (vp->v_dirtyblkhd.lh_first) {
 1101                 vprint("msdosfs_fsync: dirty", vp);
 1102                 goto loop;
 1103         }
 1104 #endif
 1105         splx(s);
 1106         return (deupdat(VTODE(vp), ap->a_waitfor == MNT_WAIT));
 1107 }
 1108 
 1109 static int
 1110 msdosfs_remove(ap)
 1111         struct vop_remove_args /* {
 1112                 struct vnode *a_dvp;
 1113                 struct vnode *a_vp;
 1114                 struct componentname *a_cnp;
 1115         } */ *ap;
 1116 {
 1117         struct denode *dep = VTODE(ap->a_vp);
 1118         struct denode *ddep = VTODE(ap->a_dvp);
 1119         int error;
 1120 
 1121         if (ap->a_vp->v_type == VDIR)
 1122                 error = EPERM;
 1123         else
 1124                 error = removede(ddep, dep);
 1125 #ifdef MSDOSFS_DEBUG
 1126         printf("msdosfs_remove(), dep %p, v_usecount %d\n", dep, ap->a_vp->v_usecount);
 1127 #endif
 1128 #ifndef __FreeBSD_version
 1129         if (ddep == dep)
 1130                 vrele(ap->a_vp);
 1131         else
 1132                 vput(ap->a_vp); /* causes msdosfs_inactive() to be called
 1133                                  * via vrele() */
 1134         vput(ap->a_dvp);
 1135 #endif
 1136         return (error);
 1137 }
 1138 
 1139 /*
 1140  * DOS filesystems don't know what links are. But since we already called
 1141  * msdosfs_lookup() with create and lockparent, the parent is locked so we
 1142  * have to free it before we return the error.
 1143  */
 1144 static int
 1145 msdosfs_link(ap)
 1146         struct vop_link_args /* {
 1147                 struct vnode *a_tdvp;
 1148                 struct vnode *a_vp;
 1149                 struct componentname *a_cnp;
 1150         } */ *ap;
 1151 {
 1152         VOP_ABORTOP(ap->a_tdvp, ap->a_cnp);
 1153 #ifndef __FreeBSD_version
 1154         vput(ap->a_tdvp);
 1155 #endif
 1156         return (EOPNOTSUPP);
 1157 }
 1158 
 1159 /*
 1160  * Renames on files require moving the denode to a new hash queue since the
 1161  * denode's location is used to compute which hash queue to put the file
 1162  * in. Unless it is a rename in place.  For example "mv a b".
 1163  *
 1164  * What follows is the basic algorithm:
 1165  *
 1166  * if (file move) {
 1167  *      if (dest file exists) {
 1168  *              remove dest file
 1169  *      }
 1170  *      if (dest and src in same directory) {
 1171  *              rewrite name in existing directory slot
 1172  *      } else {
 1173  *              write new entry in dest directory
 1174  *              update offset and dirclust in denode
 1175  *              move denode to new hash chain
 1176  *              clear old directory entry
 1177  *      }
 1178  * } else {
 1179  *      directory move
 1180  *      if (dest directory exists) {
 1181  *              if (dest is not empty) {
 1182  *                      return ENOTEMPTY
 1183  *              }
 1184  *              remove dest directory
 1185  *      }
 1186  *      if (dest and src in same directory) {
 1187  *              rewrite name in existing entry
 1188  *      } else {
 1189  *              be sure dest is not a child of src directory
 1190  *              write entry in dest directory
 1191  *              update "." and ".." in moved directory
 1192  *              clear old directory entry for moved directory
 1193  *      }
 1194  * }
 1195  *
 1196  * On entry:
 1197  *      source's parent directory is unlocked
 1198  *      source file or directory is unlocked
 1199  *      destination's parent directory is locked
 1200  *      destination file or directory is locked if it exists
 1201  *
 1202  * On exit:
 1203  *      all denodes should be released
 1204  *
 1205  * Notes:
 1206  * I'm not sure how the memory containing the pathnames pointed at by the
 1207  * componentname structures is freed, there may be some memory bleeding
 1208  * for each rename done.
 1209  */
 1210 static int
 1211 msdosfs_rename(ap)
 1212         struct vop_rename_args /* {
 1213                 struct vnode *a_fdvp;
 1214                 struct vnode *a_fvp;
 1215                 struct componentname *a_fcnp;
 1216                 struct vnode *a_tdvp;
 1217                 struct vnode *a_tvp;
 1218                 struct componentname *a_tcnp;
 1219         } */ *ap;
 1220 {
 1221         struct vnode *tdvp = ap->a_tdvp;
 1222         struct vnode *fvp = ap->a_fvp;
 1223         struct vnode *fdvp = ap->a_fdvp;
 1224         struct vnode *tvp = ap->a_tvp;
 1225         struct componentname *tcnp = ap->a_tcnp;
 1226         struct componentname *fcnp = ap->a_fcnp;
 1227         struct proc *p = fcnp->cn_proc;
 1228         struct denode *ip, *xp, *dp, *zp;
 1229         u_char toname[11], oldname[11];
 1230         u_long from_diroffset, to_diroffset;
 1231         u_char to_count;
 1232         int doingdirectory = 0, newparent = 0;
 1233         int error;
 1234         u_long cn;
 1235         daddr_t bn;
 1236         struct denode *fddep;   /* from file's parent directory  */
 1237         struct denode *fdep;    /* from file or directory        */
 1238         struct denode *tddep;   /* to file's parent directory    */
 1239         struct denode *tdep;    /* to file or directory          */
 1240         struct msdosfsmount *pmp;
 1241         struct direntry *dotdotp;
 1242         struct buf *bp;
 1243 
 1244         fddep = VTODE(ap->a_fdvp);
 1245         fdep = VTODE(ap->a_fvp);
 1246         tddep = VTODE(ap->a_tdvp);
 1247         tdep = tvp ? VTODE(tvp) : NULL;
 1248         pmp = fddep->de_pmp;
 1249 
 1250         pmp = VFSTOMSDOSFS(fdvp->v_mount);
 1251 
 1252 #ifdef DIAGNOSTIC
 1253         if ((tcnp->cn_flags & HASBUF) == 0 ||
 1254             (fcnp->cn_flags & HASBUF) == 0)
 1255                 panic("msdosfs_rename: no name");
 1256 #endif
 1257         /*
 1258          * Check for cross-device rename.
 1259          */
 1260         if ((fvp->v_mount != tdvp->v_mount) ||
 1261             (tvp && (fvp->v_mount != tvp->v_mount))) {
 1262                 error = EXDEV;
 1263 abortit:
 1264                 VOP_ABORTOP(tdvp, tcnp);
 1265                 if (tdvp == tvp)
 1266                         vrele(tdvp);
 1267                 else
 1268                         vput(tdvp);
 1269                 if (tvp)
 1270                         vput(tvp);
 1271                 VOP_ABORTOP(fdvp, fcnp);
 1272                 vrele(fdvp);
 1273                 vrele(fvp);
 1274                 return (error);
 1275         }
 1276 
 1277         /*
 1278          * If source and dest are the same, do nothing.
 1279          */
 1280         if (tvp == fvp) {
 1281                 error = 0;
 1282                 goto abortit;
 1283         }
 1284 
 1285         error = vn_lock(fvp, LK_EXCLUSIVE, p);
 1286         if (error)
 1287                 goto abortit;
 1288         dp = VTODE(fdvp);
 1289         ip = VTODE(fvp);
 1290 
 1291         /*
 1292          * Be sure we are not renaming ".", "..", or an alias of ".". This
 1293          * leads to a crippled directory tree.  It's pretty tough to do a
 1294          * "ls" or "pwd" with the "." directory entry missing, and "cd .."
 1295          * doesn't work if the ".." entry is missing.
 1296          */
 1297         if (ip->de_Attributes & ATTR_DIRECTORY) {
 1298                 /*
 1299                  * Avoid ".", "..", and aliases of "." for obvious reasons.
 1300                  */
 1301                 if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
 1302                     dp == ip ||
 1303                     (fcnp->cn_flags & ISDOTDOT) ||
 1304                     (tcnp->cn_flags & ISDOTDOT) ||
 1305                     (ip->de_flag & DE_RENAME)) {
 1306 #ifdef __FreeBSD_version
 1307                         VOP_UNLOCK(fvp, 0, p);
 1308 #else
 1309                         VOP_UNLOCK(fvp);
 1310 #endif
 1311                         error = EINVAL;
 1312                         goto abortit;
 1313                 }
 1314                 ip->de_flag |= DE_RENAME;
 1315                 doingdirectory++;
 1316         }
 1317 
 1318         /*
 1319          * When the target exists, both the directory
 1320          * and target vnodes are returned locked.
 1321          */
 1322         dp = VTODE(tdvp);
 1323         xp = tvp ? VTODE(tvp) : NULL;
 1324         /*
 1325          * Remember direntry place to use for destination
 1326          */
 1327         to_diroffset = dp->de_fndoffset;
 1328         to_count = dp->de_fndcnt;
 1329 
 1330         /*
 1331          * If ".." must be changed (ie the directory gets a new
 1332          * parent) then the source directory must not be in the
 1333          * directory heirarchy above the target, as this would
 1334          * orphan everything below the source directory. Also
 1335          * the user must have write permission in the source so
 1336          * as to be able to change "..". We must repeat the call
 1337          * to namei, as the parent directory is unlocked by the
 1338          * call to doscheckpath().
 1339          */
 1340         error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_proc);
 1341 #ifdef __FreeBSD_version
 1342         VOP_UNLOCK(fvp, 0, p);
 1343 #else
 1344         VOP_UNLOCK(fvp);
 1345 #endif
 1346         if (VTODE(fdvp)->de_StartCluster != VTODE(tdvp)->de_StartCluster)
 1347                 newparent = 1;
 1348         vrele(fdvp);
 1349         if (doingdirectory && newparent) {
 1350                 if (error)      /* write access check above */
 1351                         goto bad;
 1352                 if (xp != NULL)
 1353                         vput(tvp);
 1354                 /*
 1355                  * doscheckpath() vput()'s dp,
 1356                  * so we have to do a relookup afterwards
 1357                  */
 1358                 error = doscheckpath(ip, dp);
 1359                 if (error)
 1360                         goto out;
 1361                 if ((tcnp->cn_flags & SAVESTART) == 0)
 1362                         panic("msdosfs_rename: lost to startdir");
 1363                 error = relookup(tdvp, &tvp, tcnp);
 1364                 if (error)
 1365                         goto out;
 1366                 dp = VTODE(tdvp);
 1367                 xp = tvp ? VTODE(tvp) : NULL;
 1368         }
 1369 
 1370         if (xp != NULL) {
 1371                 /*
 1372                  * Target must be empty if a directory and have no links
 1373                  * to it. Also, ensure source and target are compatible
 1374                  * (both directories, or both not directories).
 1375                  */
 1376                 if (xp->de_Attributes & ATTR_DIRECTORY) {
 1377                         if (!dosdirempty(xp)) {
 1378                                 error = ENOTEMPTY;
 1379                                 goto bad;
 1380                         }
 1381                         if (!doingdirectory) {
 1382                                 error = ENOTDIR;
 1383                                 goto bad;
 1384                         }
 1385                         cache_purge(tdvp);
 1386                 } else if (doingdirectory) {
 1387                         error = EISDIR;
 1388                         goto bad;
 1389                 }
 1390                 error = removede(dp, xp);
 1391                 if (error)
 1392                         goto bad;
 1393                 vput(tvp);
 1394                 xp = NULL;
 1395         }
 1396 
 1397         /*
 1398          * Convert the filename in tcnp into a dos filename. We copy this
 1399          * into the denode and directory entry for the destination
 1400          * file/directory.
 1401          */
 1402         error = uniqdosname(VTODE(tdvp), tcnp, toname);
 1403         if (error)
 1404                 goto abortit;
 1405 
 1406         /*
 1407          * Since from wasn't locked at various places above,
 1408          * have to do a relookup here.
 1409          */
 1410         fcnp->cn_flags &= ~MODMASK;
 1411         fcnp->cn_flags |= LOCKPARENT | LOCKLEAF;
 1412         if ((fcnp->cn_flags & SAVESTART) == 0)
 1413                 panic("msdosfs_rename: lost from startdir");
 1414         if (!newparent)
 1415 #ifdef __FreeBSD_version
 1416                 VOP_UNLOCK(tdvp, 0, p);
 1417 #else
 1418                 VOP_UNLOCK(tdvp);
 1419 #endif
 1420         (void) relookup(fdvp, &fvp, fcnp);
 1421         if (fvp == NULL) {
 1422                 /*
 1423                  * From name has disappeared.
 1424                  */
 1425                 if (doingdirectory)
 1426                         panic("rename: lost dir entry");
 1427                 vrele(ap->a_fvp);
 1428                 if (newparent)
 1429 #ifdef __FreeBSD_version
 1430                         VOP_UNLOCK(tdvp, 0, p);
 1431 #else
 1432                         VOP_UNLOCK(tdvp);
 1433 #endif
 1434                 vrele(tdvp);
 1435                 return 0;
 1436         }
 1437         xp = VTODE(fvp);
 1438         zp = VTODE(fdvp);
 1439         from_diroffset = zp->de_fndoffset;
 1440 
 1441         /*
 1442          * Ensure that the directory entry still exists and has not
 1443          * changed till now. If the source is a file the entry may
 1444          * have been unlinked or renamed. In either case there is
 1445          * no further work to be done. If the source is a directory
 1446          * then it cannot have been rmdir'ed or renamed; this is
 1447          * prohibited by the DE_RENAME flag.
 1448          */
 1449         if (xp != ip) {
 1450                 if (doingdirectory)
 1451                         panic("rename: lost dir entry");
 1452                 vrele(ap->a_fvp);
 1453 #ifdef __FreeBSD_version
 1454                 VOP_UNLOCK(fvp, 0, p);
 1455 #else
 1456                 VOP_UNLOCK(fvp);
 1457 #endif
 1458                 if (newparent)
 1459 #ifdef __FreeBSD_version
 1460                         VOP_UNLOCK(fdvp, 0, p);
 1461 #else
 1462                         VOP_UNLOCK(fdvp);
 1463 #endif
 1464                 xp = NULL;
 1465         } else {
 1466                 vrele(fvp);
 1467                 xp = NULL;
 1468 
 1469                 /*
 1470                  * First write a new entry in the destination
 1471                  * directory and mark the entry in the source directory
 1472                  * as deleted.  Then move the denode to the correct hash
 1473                  * chain for its new location in the filesystem.  And, if
 1474                  * we moved a directory, then update its .. entry to point
 1475                  * to the new parent directory.
 1476                  */
 1477                 bcopy(ip->de_Name, oldname, 11);
 1478                 bcopy(toname, ip->de_Name, 11); /* update denode */
 1479                 dp->de_fndoffset = to_diroffset;
 1480                 dp->de_fndcnt = to_count;
 1481                 error = createde(ip, dp, (struct denode **)0, tcnp);
 1482                 if (error) {
 1483                         bcopy(oldname, ip->de_Name, 11);
 1484                         if (newparent)
 1485 #ifdef __FreeBSD_version
 1486                                 VOP_UNLOCK(fdvp, 0, p);
 1487                         VOP_UNLOCK(fvp, 0, p);
 1488 #else
 1489                                 VOP_UNLOCK(fdvp);
 1490                         VOP_UNLOCK(fvp);
 1491 #endif
 1492                         goto bad;
 1493                 }
 1494                 ip->de_refcnt++;
 1495                 zp->de_fndoffset = from_diroffset;
 1496                 error = removede(zp, ip);
 1497                 if (error) {
 1498                         /* XXX should really panic here, fs is corrupt */
 1499                         if (newparent)
 1500 #ifdef __FreeBSD_version
 1501                                 VOP_UNLOCK(fdvp, 0, p);
 1502                         VOP_UNLOCK(fvp, 0, p);
 1503 #else
 1504                                 VOP_UNLOCK(fdvp);
 1505                         VOP_UNLOCK(fvp);
 1506 #endif
 1507                         goto bad;
 1508                 }
 1509                 if (!doingdirectory) {
 1510                         error = pcbmap(dp, de_cluster(pmp, to_diroffset), 0,
 1511                                        &ip->de_dirclust, 0);
 1512                         if (error) {
 1513                                 /* XXX should really panic here, fs is corrupt */
 1514                                 if (newparent)
 1515 #ifdef __FreeBSD_version
 1516                                         VOP_UNLOCK(fdvp, 0, p);
 1517                                 VOP_UNLOCK(fvp, 0, p);
 1518 #else
 1519                                         VOP_UNLOCK(fdvp);
 1520                                 VOP_UNLOCK(fvp);
 1521 #endif
 1522                                 goto bad;
 1523                         }
 1524                         if (ip->de_dirclust == MSDOSFSROOT)
 1525                                 ip->de_diroffset = to_diroffset;
 1526                         else
 1527                                 ip->de_diroffset = to_diroffset & pmp->pm_crbomask;
 1528                 }
 1529                 reinsert(ip);
 1530                 if (newparent)
 1531 #ifdef __FreeBSD_version
 1532                         VOP_UNLOCK(fdvp, 0, p);
 1533 #else
 1534                         VOP_UNLOCK(fdvp);
 1535 #endif
 1536         }
 1537 
 1538         /*
 1539          * If we moved a directory to a new parent directory, then we must
 1540          * fixup the ".." entry in the moved directory.
 1541          */
 1542         if (doingdirectory && newparent) {
 1543                 cn = ip->de_StartCluster;
 1544                 if (cn == MSDOSFSROOT) {
 1545                         /* this should never happen */
 1546                         panic("msdosfs_rename(): updating .. in root directory?");
 1547                 } else
 1548                         bn = cntobn(pmp, cn);
 1549                 error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster,
 1550                               NOCRED, &bp);
 1551                 if (error) {
 1552                         /* XXX should really panic here, fs is corrupt */
 1553                         brelse(bp);
 1554 #ifdef __FreeBSD_version
 1555                         VOP_UNLOCK(fvp, 0, p);
 1556 #else
 1557                         VOP_UNLOCK(fvp);
 1558 #endif
 1559                         goto bad;
 1560                 }
 1561                 dotdotp = (struct direntry *)bp->b_data + 1;
 1562                 putushort(dotdotp->deStartCluster, dp->de_StartCluster);
 1563                 if (FAT32(pmp))
 1564                         putushort(dotdotp->deHighClust, dp->de_StartCluster >> 16);
 1565                 error = bwrite(bp);
 1566                 if (error) {
 1567                         /* XXX should really panic here, fs is corrupt */
 1568 #ifdef __FreeBSD_version
 1569                         VOP_UNLOCK(fvp, 0, p);
 1570 #else
 1571                         VOP_UNLOCK(fvp);
 1572 #endif
 1573                         goto bad;
 1574                 }
 1575         }
 1576 
 1577 #ifdef __FreeBSD_version
 1578         VOP_UNLOCK(fvp, 0, p);
 1579 #else
 1580         VOP_UNLOCK(fvp);
 1581 #endif
 1582 bad:
 1583         if (xp)
 1584                 vput(tvp);
 1585         vput(tdvp);
 1586 out:
 1587         ip->de_flag &= ~DE_RENAME;
 1588         vrele(fdvp);
 1589         vrele(fvp);
 1590         return (error);
 1591 
 1592 }
 1593 
 1594 static struct {
 1595         struct direntry dot;
 1596         struct direntry dotdot;
 1597 } dosdirtemplate = {
 1598         {       ".       ", "   ",                      /* the . entry */
 1599                 ATTR_DIRECTORY,                         /* file attribute */
 1600                 0,                                      /* reserved */
 1601                 0, { 0, 0 }, { 0, 0 },                  /* create time & date */
 1602                 { 0, 0 },                               /* access date */
 1603                 { 0, 0 },                               /* high bits of start cluster */
 1604                 { 210, 4 }, { 210, 4 },                 /* modify time & date */
 1605                 { 0, 0 },                               /* startcluster */
 1606                 { 0, 0, 0, 0 }                          /* filesize */
 1607         },
 1608         {       "..      ", "   ",                      /* the .. entry */
 1609                 ATTR_DIRECTORY,                         /* file attribute */
 1610                 0,                                      /* reserved */
 1611                 0, { 0, 0 }, { 0, 0 },                  /* create time & date */
 1612                 { 0, 0 },                               /* access date */
 1613                 { 0, 0 },                               /* high bits of start cluster */
 1614                 { 210, 4 }, { 210, 4 },                 /* modify time & date */
 1615                 { 0, 0 },                               /* startcluster */
 1616                 { 0, 0, 0, 0 }                          /* filesize */
 1617         }
 1618 };
 1619 
 1620 static int
 1621 msdosfs_mkdir(ap)
 1622         struct vop_mkdir_args /* {
 1623                 struct vnode *a_dvp;
 1624                 struvt vnode **a_vpp;
 1625                 struvt componentname *a_cnp;
 1626                 struct vattr *a_vap;
 1627         } */ *ap;
 1628 {
 1629         struct componentname *cnp = ap->a_cnp;
 1630         struct denode *dep;
 1631         struct denode *pdep = VTODE(ap->a_dvp);
 1632         struct direntry *denp;
 1633         struct msdosfsmount *pmp = pdep->de_pmp;
 1634         struct buf *bp;
 1635         u_long newcluster, pcl;
 1636         int bn;
 1637         int error;
 1638         struct denode ndirent;
 1639         struct timespec ts;
 1640 
 1641         /*
 1642          * If this is the root directory and there is no space left we
 1643          * can't do anything.  This is because the root directory can not
 1644          * change size.
 1645          */
 1646         if (pdep->de_StartCluster == MSDOSFSROOT
 1647             && pdep->de_fndoffset >= pdep->de_FileSize) {
 1648                 error = ENOSPC;
 1649                 goto bad2;
 1650         }
 1651 
 1652         /*
 1653          * Allocate a cluster to hold the about to be created directory.
 1654          */
 1655         error = clusteralloc(pmp, 0, 1, CLUST_EOFE, &newcluster, NULL);
 1656         if (error)
 1657                 goto bad2;
 1658 
 1659         bzero(&ndirent, sizeof(ndirent));
 1660         ndirent.de_pmp = pmp;
 1661         ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE;
 1662 #ifdef __FreeBSD_version
 1663         getnanotime(&ts);
 1664 #else
 1665         TIMEVAL_TO_TIMESPEC(&time, &ts);
 1666 #endif
 1667         DETIMES(&ndirent, &ts, &ts, &ts);
 1668 
 1669         /*
 1670          * Now fill the cluster with the "." and ".." entries. And write
 1671          * the cluster to disk.  This way it is there for the parent
 1672          * directory to be pointing at if there were a crash.
 1673          */
 1674         bn = cntobn(pmp, newcluster);
 1675         /* always succeeds */
 1676         bp = getblk(pmp->pm_devvp, bn, pmp->pm_bpcluster, 0, 0);
 1677         bzero(bp->b_data, pmp->pm_bpcluster);
 1678         bcopy(&dosdirtemplate, bp->b_data, sizeof dosdirtemplate);
 1679         denp = (struct direntry *)bp->b_data;
 1680         putushort(denp[0].deStartCluster, newcluster);
 1681         putushort(denp[0].deCDate, ndirent.de_CDate);
 1682         putushort(denp[0].deCTime, ndirent.de_CTime);
 1683         denp[0].deCHundredth = ndirent.de_CHun;
 1684         putushort(denp[0].deADate, ndirent.de_ADate);
 1685         putushort(denp[0].deMDate, ndirent.de_MDate);
 1686         putushort(denp[0].deMTime, ndirent.de_MTime);
 1687         pcl = pdep->de_StartCluster;
 1688         if (FAT32(pmp) && pcl == pmp->pm_rootdirblk)
 1689                 pcl = 0;
 1690         putushort(denp[1].deStartCluster, pcl);
 1691         putushort(denp[1].deCDate, ndirent.de_CDate);
 1692         putushort(denp[1].deCTime, ndirent.de_CTime);
 1693         denp[1].deCHundredth = ndirent.de_CHun;
 1694         putushort(denp[1].deADate, ndirent.de_ADate);
 1695         putushort(denp[1].deMDate, ndirent.de_MDate);
 1696         putushort(denp[1].deMTime, ndirent.de_MTime);
 1697         if (FAT32(pmp)) {
 1698                 putushort(denp[0].deHighClust, newcluster >> 16);
 1699                 putushort(denp[1].deHighClust, pdep->de_StartCluster >> 16);
 1700         }
 1701 
 1702         error = bwrite(bp);
 1703         if (error)
 1704                 goto bad;
 1705 
 1706         /*
 1707          * Now build up a directory entry pointing to the newly allocated
 1708          * cluster.  This will be written to an empty slot in the parent
 1709          * directory.
 1710          */
 1711 #ifdef DIAGNOSTIC
 1712         if ((cnp->cn_flags & HASBUF) == 0)
 1713                 panic("msdosfs_mkdir: no name");
 1714 #endif
 1715         error = uniqdosname(pdep, cnp, ndirent.de_Name);
 1716         if (error)
 1717                 goto bad;
 1718 
 1719         ndirent.de_Attributes = ATTR_DIRECTORY;
 1720         ndirent.de_StartCluster = newcluster;
 1721         ndirent.de_FileSize = 0;
 1722         ndirent.de_dev = pdep->de_dev;
 1723         ndirent.de_devvp = pdep->de_devvp;
 1724         error = createde(&ndirent, pdep, &dep, cnp);
 1725         if (error)
 1726                 goto bad;
 1727         if ((cnp->cn_flags & SAVESTART) == 0)
 1728                 zfree(namei_zone, cnp->cn_pnbuf);
 1729 #ifndef __FreeBSD_version
 1730         vput(ap->a_dvp);
 1731 #endif
 1732         *ap->a_vpp = DETOV(dep);
 1733         return (0);
 1734 
 1735 bad:
 1736         clusterfree(pmp, newcluster, NULL);
 1737 bad2:
 1738         zfree(namei_zone, cnp->cn_pnbuf);
 1739 #ifndef __FreeBSD_version
 1740         vput(ap->a_dvp);
 1741 #endif
 1742         return (error);
 1743 }
 1744 
 1745 static int
 1746 msdosfs_rmdir(ap)
 1747         struct vop_rmdir_args /* {
 1748                 struct vnode *a_dvp;
 1749                 struct vnode *a_vp;
 1750                 struct componentname *a_cnp;
 1751         } */ *ap;
 1752 {
 1753         register struct vnode *vp = ap->a_vp;
 1754         register struct vnode *dvp = ap->a_dvp;
 1755         register struct componentname *cnp = ap->a_cnp;
 1756         register struct denode *ip, *dp;
 1757         struct proc *p = cnp->cn_proc;
 1758         int error;
 1759         
 1760         ip = VTODE(vp);
 1761         dp = VTODE(dvp);
 1762 
 1763         /*
 1764          * Verify the directory is empty (and valid).
 1765          * (Rmdir ".." won't be valid since
 1766          *  ".." will contain a reference to
 1767          *  the current directory and thus be
 1768          *  non-empty.)
 1769          */
 1770         error = 0;
 1771         if (!dosdirempty(ip) || ip->de_flag & DE_RENAME) {
 1772                 error = ENOTEMPTY;
 1773                 goto out;
 1774         }
 1775         /*
 1776          * Delete the entry from the directory.  For dos filesystems this
 1777          * gets rid of the directory entry on disk, the in memory copy
 1778          * still exists but the de_refcnt is <= 0.  This prevents it from
 1779          * being found by deget().  When the vput() on dep is done we give
 1780          * up access and eventually msdosfs_reclaim() will be called which
 1781          * will remove it from the denode cache.
 1782          */
 1783         error = removede(dp, ip);
 1784         if (error)
 1785                 goto out;
 1786         /*
 1787          * This is where we decrement the link count in the parent
 1788          * directory.  Since dos filesystems don't do this we just purge
 1789          * the name cache.
 1790          */
 1791         cache_purge(dvp);
 1792 #ifndef __FreeBSD_version
 1793         VOP_UNLOCK(dvp);
 1794 #else
 1795         VOP_UNLOCK(dvp, 0, p);
 1796 #endif
 1797         /*
 1798          * Truncate the directory that is being deleted.
 1799          */
 1800         error = detrunc(ip, (u_long)0, IO_SYNC, cnp->cn_cred, p);
 1801         cache_purge(vp);
 1802 
 1803         vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY, p);
 1804 out:
 1805 #ifndef __FreeBSD_version
 1806         if (dvp)
 1807                 vput(dvp);
 1808         vput(vp);
 1809 #endif
 1810         return (error);
 1811 }
 1812 
 1813 /*
 1814  * DOS filesystems don't know what symlinks are.
 1815  */
 1816 static int
 1817 msdosfs_symlink(ap)
 1818         struct vop_symlink_args /* {
 1819                 struct vnode *a_dvp;
 1820                 struct vnode **a_vpp;
 1821                 struct componentname *a_cnp;
 1822                 struct vattr *a_vap;
 1823                 char *a_target;
 1824         } */ *ap;
 1825 {
 1826         zfree(namei_zone, ap->a_cnp->cn_pnbuf);
 1827         /* VOP_ABORTOP(ap->a_dvp, ap->a_cnp); ??? */
 1828 #ifndef __FreeBSD_version
 1829         vput(ap->a_dvp);
 1830 #endif
 1831         return (EOPNOTSUPP);
 1832 }
 1833 
 1834 static int
 1835 msdosfs_readdir(ap)
 1836         struct vop_readdir_args /* {
 1837                 struct vnode *a_vp;
 1838                 struct uio *a_uio;
 1839                 struct ucred *a_cred;
 1840                 int *a_eofflag;
 1841                 int *a_ncookies;
 1842                 u_long **a_cookies;
 1843         } */ *ap;
 1844 {
 1845         int error = 0;
 1846         int diff;
 1847         long n;
 1848         int blsize;
 1849         long on;
 1850         u_long cn;
 1851         u_long fileno;
 1852         u_long dirsperblk;
 1853         long bias = 0;
 1854         daddr_t bn, lbn;
 1855         struct buf *bp;
 1856         struct denode *dep = VTODE(ap->a_vp);
 1857         struct msdosfsmount *pmp = dep->de_pmp;
 1858         struct direntry *dentp;
 1859         struct dirent dirbuf;
 1860         struct uio *uio = ap->a_uio;
 1861         u_long *cookies = NULL;
 1862         int ncookies = 0;
 1863         off_t offset, off;
 1864         int chksum = -1;
 1865 
 1866 #ifdef MSDOSFS_DEBUG
 1867         printf("msdosfs_readdir(): vp %p, uio %p, cred %p, eofflagp %p\n",
 1868             ap->a_vp, uio, ap->a_cred, ap->a_eofflag);
 1869 #endif
 1870 
 1871         /*
 1872          * msdosfs_readdir() won't operate properly on regular files since
 1873          * it does i/o only with the the filesystem vnode, and hence can
 1874          * retrieve the wrong block from the buffer cache for a plain file.
 1875          * So, fail attempts to readdir() on a plain file.
 1876          */
 1877         if ((dep->de_Attributes & ATTR_DIRECTORY) == 0)
 1878                 return (ENOTDIR);
 1879 
 1880         /*
 1881          * To be safe, initialize dirbuf
 1882          */
 1883         bzero(dirbuf.d_name, sizeof(dirbuf.d_name));
 1884 
 1885         /*
 1886          * If the user buffer is smaller than the size of one dos directory
 1887          * entry or the file offset is not a multiple of the size of a
 1888          * directory entry, then we fail the read.
 1889          */
 1890         off = offset = uio->uio_offset;
 1891         if (uio->uio_resid < sizeof(struct direntry) ||
 1892             (offset & (sizeof(struct direntry) - 1)))
 1893                 return (EINVAL);
 1894 
 1895         if (ap->a_ncookies) {
 1896                 ncookies = uio->uio_resid / 16;
 1897                 MALLOC(cookies, u_long *, ncookies * sizeof(u_long), M_TEMP,
 1898                        M_WAITOK);
 1899 #ifdef __FreeBSD_version
 1900                 *ap->a_cookies = cookies;
 1901 #else
 1902                 *ap->a_cookies = (u_int *)cookies;
 1903 #endif
 1904                 *ap->a_ncookies = ncookies;
 1905         }
 1906 
 1907         dirsperblk = pmp->pm_BytesPerSec / sizeof(struct direntry);
 1908 
 1909         /*
 1910          * If they are reading from the root directory then, we simulate
 1911          * the . and .. entries since these don't exist in the root
 1912          * directory.  We also set the offset bias to make up for having to
 1913          * simulate these entries. By this I mean that at file offset 64 we
 1914          * read the first entry in the root directory that lives on disk.
 1915          */
 1916         if (dep->de_StartCluster == MSDOSFSROOT
 1917             || (FAT32(pmp) && dep->de_StartCluster == pmp->pm_rootdirblk)) {
 1918 #if 0
 1919                 printf("msdosfs_readdir(): going after . or .. in root dir, offset %d\n",
 1920                     offset);
 1921 #endif
 1922                 bias = 2 * sizeof(struct direntry);
 1923                 if (offset < bias) {
 1924                         for (n = (int)offset / sizeof(struct direntry);
 1925                              n < 2; n++) {
 1926                                 if (FAT32(pmp))
 1927                                         dirbuf.d_fileno = cntobn(pmp,
 1928                                                                  pmp->pm_rootdirblk)
 1929                                                           * dirsperblk;
 1930                                 else
 1931                                         dirbuf.d_fileno = 1;
 1932                                 dirbuf.d_type = DT_DIR;
 1933                                 switch (n) {
 1934                                 case 0:
 1935                                         dirbuf.d_namlen = 1;
 1936                                         strcpy(dirbuf.d_name, ".");
 1937                                         break;
 1938                                 case 1:
 1939                                         dirbuf.d_namlen = 2;
 1940                                         strcpy(dirbuf.d_name, "..");
 1941                                         break;
 1942                                 }
 1943                                 dirbuf.d_reclen = GENERIC_DIRSIZ(&dirbuf);
 1944                                 if (uio->uio_resid < dirbuf.d_reclen)
 1945                                         goto out;
 1946                                 error = uiomove((caddr_t) &dirbuf,
 1947                                                 dirbuf.d_reclen, uio);
 1948                                 if (error)
 1949                                         goto out;
 1950                                 offset += sizeof(struct direntry);
 1951                                 off = offset;
 1952                                 if (cookies) {
 1953                                         *cookies++ = offset;
 1954                                         if (--ncookies <= 0)
 1955                                                 goto out;
 1956                                 }
 1957                         }
 1958                 }
 1959         }
 1960 
 1961         off = offset;
 1962         while (uio->uio_resid > 0) {
 1963                 lbn = de_cluster(pmp, offset - bias);
 1964                 on = (offset - bias) & pmp->pm_crbomask;
 1965                 n = min(pmp->pm_bpcluster - on, uio->uio_resid);
 1966                 diff = dep->de_FileSize - (offset - bias);
 1967                 if (diff <= 0)
 1968                         break;
 1969                 n = min(n, diff);
 1970                 error = pcbmap(dep, lbn, &bn, &cn, &blsize);
 1971                 if (error)
 1972                         break;
 1973                 error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp);
 1974                 if (error) {
 1975                         brelse(bp);
 1976                         return (error);
 1977                 }
 1978                 n = min(n, blsize - bp->b_resid);
 1979 
 1980                 /*
 1981                  * Convert from dos directory entries to fs-independent
 1982                  * directory entries.
 1983                  */
 1984                 for (dentp = (struct direntry *)(bp->b_data + on);
 1985                      (char *)dentp < bp->b_data + on + n;
 1986                      dentp++, offset += sizeof(struct direntry)) {
 1987 #if 0
 1988                         printf("rd: dentp %08x prev %08x crnt %08x deName %02x attr %02x\n",
 1989                             dentp, prev, crnt, dentp->deName[0], dentp->deAttributes);
 1990 #endif
 1991                         /*
 1992                          * If this is an unused entry, we can stop.
 1993                          */
 1994                         if (dentp->deName[0] == SLOT_EMPTY) {
 1995                                 brelse(bp);
 1996                                 goto out;
 1997                         }
 1998                         /*
 1999                          * Skip deleted entries.
 2000                          */
 2001                         if (dentp->deName[0] == SLOT_DELETED) {
 2002                                 chksum = -1;
 2003                                 continue;
 2004                         }
 2005 
 2006                         /*
 2007                          * Handle Win95 long directory entries
 2008                          */
 2009                         if (dentp->deAttributes == ATTR_WIN95) {
 2010                                 if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
 2011                                         continue;
 2012                                 chksum = win2unixfn((struct winentry *)dentp,
 2013                                         &dirbuf, chksum,
 2014                                         pmp->pm_flags & MSDOSFSMNT_U2WTABLE,
 2015                                         pmp->pm_u2w);
 2016                                 continue;
 2017                         }
 2018 
 2019                         /*
 2020                          * Skip volume labels
 2021                          */
 2022                         if (dentp->deAttributes & ATTR_VOLUME) {
 2023                                 chksum = -1;
 2024                                 continue;
 2025                         }
 2026                         /*
 2027                          * This computation of d_fileno must match
 2028                          * the computation of va_fileid in
 2029                          * msdosfs_getattr.
 2030                          */
 2031                         if (dentp->deAttributes & ATTR_DIRECTORY) {
 2032                                 fileno = getushort(dentp->deStartCluster);
 2033                                 if (FAT32(pmp))
 2034                                         fileno |= getushort(dentp->deHighClust) << 16;
 2035                                 /* if this is the root directory */
 2036                                 if (fileno == MSDOSFSROOT)
 2037                                         if (FAT32(pmp))
 2038                                                 fileno = cntobn(pmp,
 2039                                                                 pmp->pm_rootdirblk)
 2040                                                          * dirsperblk;
 2041                                         else
 2042                                                 fileno = 1;
 2043                                 else
 2044                                         fileno = cntobn(pmp, fileno) * dirsperblk;
 2045                                 dirbuf.d_fileno = fileno;
 2046                                 dirbuf.d_type = DT_DIR;
 2047                         } else {
 2048                                 dirbuf.d_fileno = offset / sizeof(struct direntry);
 2049                                 dirbuf.d_type = DT_REG;
 2050                         }
 2051                         if (chksum != winChksum(dentp->deName))
 2052                                 dirbuf.d_namlen = dos2unixfn(dentp->deName,
 2053                                     (u_char *)dirbuf.d_name,
 2054                                     pmp->pm_flags & MSDOSFSMNT_SHORTNAME,
 2055                                     pmp->pm_flags & MSDOSFSMNT_U2WTABLE,
 2056                                     pmp->pm_d2u,
 2057                                     pmp->pm_flags & MSDOSFSMNT_ULTABLE,
 2058                                     pmp->pm_ul);
 2059                         else
 2060                                 dirbuf.d_name[dirbuf.d_namlen] = 0;
 2061                         chksum = -1;
 2062                         dirbuf.d_reclen = GENERIC_DIRSIZ(&dirbuf);
 2063                         if (uio->uio_resid < dirbuf.d_reclen) {
 2064                                 brelse(bp);
 2065                                 goto out;
 2066                         }
 2067                         error = uiomove((caddr_t) &dirbuf,
 2068                                         dirbuf.d_reclen, uio);
 2069                         if (error) {
 2070                                 brelse(bp);
 2071                                 goto out;
 2072                         }
 2073                         if (cookies) {
 2074                                 *cookies++ = offset + sizeof(struct direntry);
 2075                                 if (--ncookies <= 0) {
 2076                                         brelse(bp);
 2077                                         goto out;
 2078                                 }
 2079                         }
 2080                         off = offset + sizeof(struct direntry);
 2081                 }
 2082                 brelse(bp);
 2083         }
 2084 out:
 2085         /* Subtract unused cookies */
 2086         if (ap->a_ncookies)
 2087                 *ap->a_ncookies -= ncookies;
 2088 
 2089         uio->uio_offset = off;
 2090 
 2091         /*
 2092          * Set the eofflag (NFS uses it)
 2093          */
 2094         if (ap->a_eofflag)
 2095                 if (dep->de_FileSize - (offset - bias) <= 0)
 2096                         *ap->a_eofflag = 1;
 2097                 else
 2098                         *ap->a_eofflag = 0;
 2099 
 2100         return (error);
 2101 }
 2102 
 2103 static int
 2104 msdosfs_abortop(ap)
 2105         struct vop_abortop_args /* {
 2106                 struct vnode *a_dvp;
 2107                 struct componentname *a_cnp;
 2108         } */ *ap;
 2109 {
 2110         if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF)
 2111                 zfree(namei_zone, ap->a_cnp->cn_pnbuf);
 2112         return (0);
 2113 }
 2114 
 2115 /*
 2116  * vp  - address of vnode file the file
 2117  * bn  - which cluster we are interested in mapping to a filesystem block number.
 2118  * vpp - returns the vnode for the block special file holding the filesystem
 2119  *       containing the file of interest
 2120  * bnp - address of where to return the filesystem relative block number
 2121  */
 2122 static int
 2123 msdosfs_bmap(ap)
 2124         struct vop_bmap_args /* {
 2125                 struct vnode *a_vp;
 2126                 daddr_t a_bn;
 2127                 struct vnode **a_vpp;
 2128                 daddr_t *a_bnp;
 2129                 int *a_runp;
 2130                 int *a_runb;
 2131         } */ *ap;
 2132 {
 2133         struct denode *dep = VTODE(ap->a_vp);
 2134         struct msdosfsmount *pmp = dep->de_pmp;
 2135 
 2136         if (ap->a_vpp != NULL)
 2137                 *ap->a_vpp = dep->de_devvp;
 2138         if (ap->a_bnp == NULL)
 2139                 return (0);
 2140         if (ap->a_runp) {
 2141                 /*
 2142                  * Sequential clusters should be counted here.
 2143                  */
 2144                 *ap->a_runp = 0;
 2145         }
 2146         if (ap->a_runb) {
 2147                 *ap->a_runb = 0;
 2148         }
 2149         return (pcbmap(dep, ap->a_bn, ap->a_bnp, 0, 0));
 2150 }
 2151 
 2152 static int
 2153 msdosfs_strategy(ap)
 2154         struct vop_strategy_args /* {
 2155                 struct buf *a_bp;
 2156         } */ *ap;
 2157 {
 2158         struct buf *bp = ap->a_bp;
 2159         struct denode *dep = VTODE(bp->b_vp);
 2160         struct vnode *vp;
 2161         int error = 0;
 2162 
 2163         if (bp->b_vp->v_type == VBLK || bp->b_vp->v_type == VCHR)
 2164                 panic("msdosfs_strategy: spec");
 2165         /*
 2166          * If we don't already know the filesystem relative block number
 2167          * then get it using pcbmap().  If pcbmap() returns the block
 2168          * number as -1 then we've got a hole in the file.  DOS filesystems
 2169          * don't allow files with holes, so we shouldn't ever see this.
 2170          */
 2171         if (bp->b_blkno == bp->b_lblkno) {
 2172                 error = pcbmap(dep, bp->b_lblkno, &bp->b_blkno, 0, 0);
 2173                 if (error) {
 2174                         bp->b_error = error;
 2175                         bp->b_flags |= B_ERROR;
 2176                         biodone(bp);
 2177                         return (error);
 2178                 }
 2179                 if ((long)bp->b_blkno == -1)
 2180                         vfs_bio_clrbuf(bp);
 2181         }
 2182         if (bp->b_blkno == -1) {
 2183                 biodone(bp);
 2184                 return (0);
 2185         }
 2186         /*
 2187          * Read/write the block from/to the disk that contains the desired
 2188          * file block.
 2189          */
 2190         vp = dep->de_devvp;
 2191         bp->b_dev = vp->v_rdev;
 2192         VOCALL(vp->v_op, VOFFSET(vop_strategy), ap);
 2193         return (0);
 2194 }
 2195 
 2196 static int
 2197 msdosfs_print(ap)
 2198         struct vop_print_args /* {
 2199                 struct vnode *vp;
 2200         } */ *ap;
 2201 {
 2202         struct denode *dep = VTODE(ap->a_vp);
 2203 
 2204         printf(
 2205             "tag VT_MSDOSFS, startcluster %d, dircluster %ld, diroffset %ld ",
 2206                dep->de_StartCluster, dep->de_dirclust, dep->de_diroffset);
 2207         printf(" dev %d, %d", major(dep->de_dev), minor(dep->de_dev));
 2208 #ifdef __FreeBSD_version
 2209         lockmgr_printinfo(&dep->de_lock);
 2210 #endif
 2211         printf("\n");
 2212         return (0);
 2213 }
 2214 
 2215 static int
 2216 msdosfs_pathconf(ap)
 2217         struct vop_pathconf_args /* {
 2218                 struct vnode *a_vp;
 2219                 int a_name;
 2220                 int *a_retval;
 2221         } */ *ap;
 2222 {
 2223         struct msdosfsmount *pmp = VTODE(ap->a_vp)->de_pmp;
 2224 
 2225         switch (ap->a_name) {
 2226         case _PC_LINK_MAX:
 2227                 *ap->a_retval = 1;
 2228                 return (0);
 2229         case _PC_NAME_MAX:
 2230                 *ap->a_retval = pmp->pm_flags & MSDOSFSMNT_LONGNAME ? WIN_MAXLEN : 12;
 2231                 return (0);
 2232         case _PC_PATH_MAX:
 2233                 *ap->a_retval = PATH_MAX;
 2234                 return (0);
 2235         case _PC_CHOWN_RESTRICTED:
 2236                 *ap->a_retval = 1;
 2237                 return (0);
 2238         case _PC_NO_TRUNC:
 2239                 *ap->a_retval = 0;
 2240                 return (0);
 2241         default:
 2242                 return (EINVAL);
 2243         }
 2244         /* NOTREACHED */
 2245 }
 2246 
 2247 #ifdef __FreeBSD_version
 2248 /*
 2249  * get page routine
 2250  *
 2251  * XXX By default, wimp out... note that a_offset is ignored (and always
 2252  * XXX has been).
 2253  */
 2254 int
 2255 msdosfs_getpages(ap)
 2256         struct vop_getpages_args *ap;
 2257 {
 2258         return vnode_pager_generic_getpages(ap->a_vp, ap->a_m, ap->a_count,
 2259                 ap->a_reqpage);
 2260 }
 2261 
 2262 /*
 2263  * put page routine
 2264  *
 2265  * XXX By default, wimp out... note that a_offset is ignored (and always
 2266  * XXX has been).
 2267  */
 2268 int
 2269 msdosfs_putpages(ap)
 2270         struct vop_putpages_args *ap;
 2271 {
 2272         return vnode_pager_generic_putpages(ap->a_vp, ap->a_m, ap->a_count,
 2273                 ap->a_sync, ap->a_rtvals);
 2274 }
 2275 #endif
 2276 
 2277 /* Global vfs data structures for msdosfs */
 2278 vop_t **msdosfs_vnodeop_p;
 2279 #ifdef __FreeBSD_version
 2280 static struct vnodeopv_entry_desc msdosfs_vnodeop_entries[] = {
 2281         { &vop_default_desc,            (vop_t *) vop_defaultop },
 2282         { &vop_abortop_desc,            (vop_t *) msdosfs_abortop },
 2283         { &vop_access_desc,             (vop_t *) msdosfs_access },
 2284         { &vop_bmap_desc,               (vop_t *) msdosfs_bmap },
 2285         { &vop_cachedlookup_desc,       (vop_t *) msdosfs_lookup },
 2286         { &vop_close_desc,              (vop_t *) msdosfs_close },
 2287         { &vop_create_desc,             (vop_t *) msdosfs_create },
 2288         { &vop_fsync_desc,              (vop_t *) msdosfs_fsync },
 2289         { &vop_getattr_desc,            (vop_t *) msdosfs_getattr },
 2290         { &vop_inactive_desc,           (vop_t *) msdosfs_inactive },
 2291         { &vop_islocked_desc,           (vop_t *) vop_stdislocked },
 2292         { &vop_link_desc,               (vop_t *) msdosfs_link },
 2293         { &vop_lock_desc,               (vop_t *) vop_stdlock },
 2294         { &vop_lookup_desc,             (vop_t *) vfs_cache_lookup },
 2295         { &vop_mkdir_desc,              (vop_t *) msdosfs_mkdir },
 2296         { &vop_mknod_desc,              (vop_t *) msdosfs_mknod },
 2297         { &vop_pathconf_desc,           (vop_t *) msdosfs_pathconf },
 2298         { &vop_print_desc,              (vop_t *) msdosfs_print },
 2299         { &vop_read_desc,               (vop_t *) msdosfs_read },
 2300         { &vop_readdir_desc,            (vop_t *) msdosfs_readdir },
 2301         { &vop_reclaim_desc,            (vop_t *) msdosfs_reclaim },
 2302         { &vop_remove_desc,             (vop_t *) msdosfs_remove },
 2303         { &vop_rename_desc,             (vop_t *) msdosfs_rename },
 2304         { &vop_rmdir_desc,              (vop_t *) msdosfs_rmdir },
 2305         { &vop_setattr_desc,            (vop_t *) msdosfs_setattr },
 2306         { &vop_strategy_desc,           (vop_t *) msdosfs_strategy },
 2307         { &vop_symlink_desc,            (vop_t *) msdosfs_symlink },
 2308         { &vop_unlock_desc,             (vop_t *) vop_stdunlock },
 2309         { &vop_write_desc,              (vop_t *) msdosfs_write },
 2310         { &vop_getpages_desc,           (vop_t *) msdosfs_getpages },
 2311         { &vop_putpages_desc,           (vop_t *) msdosfs_putpages },
 2312         { NULL, NULL }
 2313 };
 2314 #else
 2315 static struct vnodeopv_entry_desc msdosfs_vnodeop_entries[] = {
 2316         { &vop_default_desc, (vop_t *)vn_default_error },
 2317         { &vop_lookup_desc, (vop_t *)msdosfs_lookup },          /* lookup */
 2318         { &vop_create_desc, (vop_t *)msdosfs_create },          /* create */
 2319         { &vop_mknod_desc, (vop_t *)msdosfs_mknod },            /* mknod */
 2320         { &vop_open_desc, (vop_t *)msdosfs_open },              /* open */
 2321         { &vop_close_desc, (vop_t *)msdosfs_close },            /* close */
 2322         { &vop_access_desc, (vop_t *)msdosfs_access },          /* access */
 2323         { &vop_getattr_desc, (vop_t *)msdosfs_getattr },        /* getattr */
 2324         { &vop_setattr_desc, (vop_t *)msdosfs_setattr },        /* setattr */
 2325         { &vop_read_desc, (vop_t *)msdosfs_read },              /* read */
 2326         { &vop_write_desc, (vop_t *)msdosfs_write },            /* write */
 2327         { &vop_ioctl_desc, (vop_t *)msdosfs_ioctl },            /* ioctl */
 2328         { &vop_select_desc, (vop_t *)msdosfs_select },          /* select */
 2329         { &vop_mmap_desc, (vop_t *)msdosfs_mmap },              /* mmap */
 2330         { &vop_fsync_desc, (vop_t *)msdosfs_fsync },            /* fsync */
 2331         { &vop_seek_desc, (vop_t *)msdosfs_seek },              /* seek */
 2332         { &vop_remove_desc, (vop_t *)msdosfs_remove },          /* remove */
 2333         { &vop_link_desc, (vop_t *)msdosfs_link },              /* link */
 2334         { &vop_rename_desc, (vop_t *)msdosfs_rename },          /* rename */
 2335         { &vop_mkdir_desc, (vop_t *)msdosfs_mkdir },            /* mkdir */
 2336         { &vop_rmdir_desc, (vop_t *)msdosfs_rmdir },            /* rmdir */
 2337         { &vop_symlink_desc, (vop_t *)msdosfs_symlink },        /* symlink */
 2338         { &vop_readdir_desc, (vop_t *)msdosfs_readdir },        /* readdir */
 2339         { &vop_readlink_desc, (vop_t *)msdosfs_readlink },      /* readlink */
 2340         { &vop_abortop_desc, (vop_t *)msdosfs_abortop },        /* abortop */
 2341         { &vop_inactive_desc, (vop_t *)msdosfs_inactive },      /* inactive */
 2342         { &vop_reclaim_desc, (vop_t *)msdosfs_reclaim },        /* reclaim */
 2343         { &vop_lock_desc, (vop_t *)msdosfs_lock },              /* lock */
 2344         { &vop_unlock_desc, (vop_t *)msdosfs_unlock },          /* unlock */
 2345         { &vop_bmap_desc, (vop_t *)msdosfs_bmap },              /* bmap */
 2346         { &vop_strategy_desc, (vop_t *)msdosfs_strategy },      /* strategy */
 2347         { &vop_print_desc, (vop_t *)msdosfs_print },            /* print */
 2348         { &vop_islocked_desc, (vop_t *)msdosfs_islocked },      /* islocked */
 2349         { &vop_pathconf_desc, (vop_t *)msdosfs_pathconf },      /* pathconf */
 2350         { &vop_advlock_desc, (vop_t *)msdosfs_advlock },        /* advlock */
 2351         { &vop_reallocblks_desc, (vop_t *)msdosfs_reallocblks },        /* reallocblks */
 2352         { &vop_bwrite_desc, (vop_t *)vn_bwrite },               /* bwrite */
 2353         { NULL, NULL }
 2354 };
 2355 #endif
 2356 static struct vnodeopv_desc msdosfs_vnodeop_opv_desc =
 2357         { &msdosfs_vnodeop_p, msdosfs_vnodeop_entries };
 2358 
 2359 VNODEOP_SET(msdosfs_vnodeop_opv_desc);

Cache object: fab6f6feaca223b6d2910b3534e9e3d0


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.