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/fs/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$ */
    2 /*      $NetBSD: msdosfs_vnops.c,v 1.68 1998/02/10 14:10:04 mrg Exp $   */
    3 
    4 /*-
    5  * SPDX-License-Identifier: BSD-4-Clause
    6  *
    7  * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
    8  * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
    9  * All rights reserved.
   10  * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  * 3. All advertising materials mentioning features or use of this software
   21  *    must display the following acknowledgement:
   22  *      This product includes software developed by TooLs GmbH.
   23  * 4. The name of TooLs GmbH may not be used to endorse or promote products
   24  *    derived from this software without specific prior written permission.
   25  *
   26  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
   27  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   28  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   29  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   30  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   31  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
   32  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   33  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   34  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
   35  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   36  */
   37 /*-
   38  * Written by Paul Popelka (paulp@uts.amdahl.com)
   39  *
   40  * You can do anything you want with this software, just don't say you wrote
   41  * it, and don't remove this notice.
   42  *
   43  * This software is provided "as is".
   44  *
   45  * The author supplies this software to be publicly redistributed on the
   46  * understanding that the author is not responsible for the correct
   47  * functioning of this software in any circumstances and is not liable for
   48  * any damages caused by this software.
   49  *
   50  * October 1992
   51  */
   52 
   53 #include <sys/param.h>
   54 #include <sys/systm.h>
   55 #include <sys/bio.h>
   56 #include <sys/buf.h>
   57 #include <sys/clock.h>
   58 #include <sys/dirent.h>
   59 #include <sys/lock.h>
   60 #include <sys/lockf.h>
   61 #include <sys/malloc.h>
   62 #include <sys/mount.h>
   63 #include <sys/mutex.h>
   64 #include <sys/namei.h>
   65 #include <sys/priv.h>
   66 #include <sys/stat.h>
   67 #include <sys/sysctl.h>
   68 #include <sys/unistd.h>
   69 #include <sys/vmmeter.h>
   70 #include <sys/vnode.h>
   71 
   72 #include <vm/vm.h>
   73 #include <vm/vm_extern.h>
   74 #include <vm/vnode_pager.h>
   75 
   76 #include <fs/msdosfs/bpb.h>
   77 #include <fs/msdosfs/direntry.h>
   78 #include <fs/msdosfs/denode.h>
   79 #include <fs/msdosfs/fat.h>
   80 #include <fs/msdosfs/msdosfsmount.h>
   81 
   82 /*
   83  * Prototypes for MSDOSFS vnode operations
   84  */
   85 static vop_create_t     msdosfs_create;
   86 static vop_mknod_t      msdosfs_mknod;
   87 static vop_open_t       msdosfs_open;
   88 static vop_close_t      msdosfs_close;
   89 static vop_access_t     msdosfs_access;
   90 static vop_getattr_t    msdosfs_getattr;
   91 static vop_setattr_t    msdosfs_setattr;
   92 static vop_read_t       msdosfs_read;
   93 static vop_write_t      msdosfs_write;
   94 static vop_fsync_t      msdosfs_fsync;
   95 static vop_remove_t     msdosfs_remove;
   96 static vop_link_t       msdosfs_link;
   97 static vop_rename_t     msdosfs_rename;
   98 static vop_mkdir_t      msdosfs_mkdir;
   99 static vop_rmdir_t      msdosfs_rmdir;
  100 static vop_symlink_t    msdosfs_symlink;
  101 static vop_readdir_t    msdosfs_readdir;
  102 static vop_bmap_t       msdosfs_bmap;
  103 static vop_getpages_t   msdosfs_getpages;
  104 static vop_strategy_t   msdosfs_strategy;
  105 static vop_print_t      msdosfs_print;
  106 static vop_pathconf_t   msdosfs_pathconf;
  107 static vop_vptofh_t     msdosfs_vptofh;
  108 
  109 /*
  110  * Some general notes:
  111  *
  112  * In the ufs filesystem the inodes, superblocks, and indirect blocks are
  113  * read/written using the vnode for the filesystem. Blocks that represent
  114  * the contents of a file are read/written using the vnode for the file
  115  * (including directories when they are read/written as files). This
  116  * presents problems for the dos filesystem because data that should be in
  117  * an inode (if dos had them) resides in the directory itself.  Since we
  118  * must update directory entries without the benefit of having the vnode
  119  * for the directory we must use the vnode for the filesystem.  This means
  120  * that when a directory is actually read/written (via read, write, or
  121  * readdir, or seek) we must use the vnode for the filesystem instead of
  122  * the vnode for the directory as would happen in ufs. This is to insure we
  123  * retrieve the correct block from the buffer cache since the hash value is
  124  * based upon the vnode address and the desired block number.
  125  */
  126 
  127 /*
  128  * Create a regular file. On entry the directory to contain the file being
  129  * created is locked.  We must release before we return. We must also free
  130  * the pathname buffer pointed at by cnp->cn_pnbuf, always on error, or
  131  * only if the SAVESTART bit in cn_flags is clear on success.
  132  */
  133 static int
  134 msdosfs_create(struct vop_create_args *ap)
  135 {
  136         struct componentname *cnp = ap->a_cnp;
  137         struct denode ndirent;
  138         struct denode *dep;
  139         struct denode *pdep = VTODE(ap->a_dvp);
  140         struct timespec ts;
  141         int error;
  142 
  143 #ifdef MSDOSFS_DEBUG
  144         printf("msdosfs_create(cnp %p, vap %p\n", cnp, ap->a_vap);
  145 #endif
  146 
  147         /*
  148          * If this is the root directory and there is no space left we
  149          * can't do anything.  This is because the root directory can not
  150          * change size.
  151          */
  152         if (pdep->de_StartCluster == MSDOSFSROOT
  153             && pdep->de_fndoffset >= pdep->de_FileSize) {
  154                 error = ENOSPC;
  155                 goto bad;
  156         }
  157 
  158         /*
  159          * Create a directory entry for the file, then call createde() to
  160          * have it installed. NOTE: DOS files are always executable.  We
  161          * use the absence of the owner write bit to make the file
  162          * readonly.
  163          */
  164 #ifdef DIAGNOSTIC
  165         if ((cnp->cn_flags & HASBUF) == 0)
  166                 panic("msdosfs_create: no name");
  167 #endif
  168         memset(&ndirent, 0, sizeof(ndirent));
  169         error = uniqdosname(pdep, cnp, ndirent.de_Name);
  170         if (error)
  171                 goto bad;
  172 
  173         ndirent.de_Attributes = ATTR_ARCHIVE;
  174         ndirent.de_LowerCase = 0;
  175         ndirent.de_StartCluster = 0;
  176         ndirent.de_FileSize = 0;
  177         ndirent.de_pmp = pdep->de_pmp;
  178         ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE;
  179         vfs_timestamp(&ts);
  180         DETIMES(&ndirent, &ts, &ts, &ts);
  181         error = createde(&ndirent, pdep, &dep, cnp);
  182         if (error)
  183                 goto bad;
  184         *ap->a_vpp = DETOV(dep);
  185         if ((cnp->cn_flags & MAKEENTRY) != 0)
  186                 cache_enter(ap->a_dvp, *ap->a_vpp, cnp);
  187         return (0);
  188 
  189 bad:
  190         return (error);
  191 }
  192 
  193 static int
  194 msdosfs_mknod(struct vop_mknod_args *ap)
  195 {
  196 
  197     return (EINVAL);
  198 }
  199 
  200 static int
  201 msdosfs_open(struct vop_open_args *ap)
  202 {
  203         struct denode *dep = VTODE(ap->a_vp);
  204         vnode_create_vobject(ap->a_vp, dep->de_FileSize, ap->a_td);
  205         return 0;
  206 }
  207 
  208 static int
  209 msdosfs_close(struct vop_close_args *ap)
  210 {
  211         struct vnode *vp = ap->a_vp;
  212         struct denode *dep = VTODE(vp);
  213         struct timespec ts;
  214 
  215         VI_LOCK(vp);
  216         if (vp->v_usecount > 1) {
  217                 vfs_timestamp(&ts);
  218                 DETIMES(dep, &ts, &ts, &ts);
  219         }
  220         VI_UNLOCK(vp);
  221         return 0;
  222 }
  223 
  224 static int
  225 msdosfs_access(struct vop_access_args *ap)
  226 {
  227         struct vnode *vp = ap->a_vp;
  228         struct denode *dep = VTODE(ap->a_vp);
  229         struct msdosfsmount *pmp = dep->de_pmp;
  230         mode_t file_mode;
  231         accmode_t accmode = ap->a_accmode;
  232 
  233         file_mode = S_IRWXU|S_IRWXG|S_IRWXO;
  234         file_mode &= (vp->v_type == VDIR ? pmp->pm_dirmask : pmp->pm_mask);
  235 
  236         /*
  237          * Disallow writing to directories and regular files if the
  238          * filesystem is read-only.
  239          */
  240         if (accmode & VWRITE) {
  241                 switch (vp->v_type) {
  242                 case VREG:
  243                 case VDIR:
  244                         if (vp->v_mount->mnt_flag & MNT_RDONLY)
  245                                 return (EROFS);
  246                         break;
  247                 default:
  248                         break;
  249                 }
  250         }
  251 
  252         return (vaccess(vp->v_type, file_mode, pmp->pm_uid, pmp->pm_gid,
  253             ap->a_accmode, ap->a_cred));
  254 }
  255 
  256 static int
  257 msdosfs_getattr(struct vop_getattr_args *ap)
  258 {
  259         struct denode *dep = VTODE(ap->a_vp);
  260         struct msdosfsmount *pmp = dep->de_pmp;
  261         struct vattr *vap = ap->a_vap;
  262         mode_t mode;
  263         struct timespec ts;
  264         u_long dirsperblk = pmp->pm_BytesPerSec / sizeof(struct direntry);
  265         uint64_t fileid;
  266 
  267         vfs_timestamp(&ts);
  268         DETIMES(dep, &ts, &ts, &ts);
  269         vap->va_fsid = dev2udev(pmp->pm_dev);
  270         /*
  271          * The following computation of the fileid must be the same as that
  272          * used in msdosfs_readdir() to compute d_fileno. If not, pwd
  273          * doesn't work.
  274          */
  275         if (dep->de_Attributes & ATTR_DIRECTORY) {
  276                 fileid = (uint64_t)cntobn(pmp, dep->de_StartCluster) *
  277                     dirsperblk;
  278                 if (dep->de_StartCluster == MSDOSFSROOT)
  279                         fileid = 1;
  280         } else {
  281                 fileid = (uint64_t)cntobn(pmp, dep->de_dirclust) *
  282                     dirsperblk;
  283                 if (dep->de_dirclust == MSDOSFSROOT)
  284                         fileid = (uint64_t)roottobn(pmp, 0) * dirsperblk;
  285                 fileid += (uoff_t)dep->de_diroffset / sizeof(struct direntry);
  286         }
  287         vap->va_fileid = fileid;
  288 
  289         mode = S_IRWXU|S_IRWXG|S_IRWXO;
  290         if (dep->de_Attributes & ATTR_READONLY)
  291                 mode &= ~(S_IWUSR|S_IWGRP|S_IWOTH);
  292         vap->va_mode = mode &
  293             (ap->a_vp->v_type == VDIR ? pmp->pm_dirmask : pmp->pm_mask);
  294         vap->va_uid = pmp->pm_uid;
  295         vap->va_gid = pmp->pm_gid;
  296         vap->va_nlink = 1;
  297         vap->va_rdev = NODEV;
  298         vap->va_size = dep->de_FileSize;
  299         fattime2timespec(dep->de_MDate, dep->de_MTime, 0, 0, &vap->va_mtime);
  300         vap->va_ctime = vap->va_mtime;
  301         if (pmp->pm_flags & MSDOSFSMNT_LONGNAME) {
  302                 fattime2timespec(dep->de_ADate, 0, 0, 0, &vap->va_atime);
  303                 fattime2timespec(dep->de_CDate, dep->de_CTime, dep->de_CHun,
  304                     0, &vap->va_birthtime);
  305         } else {
  306                 vap->va_atime = vap->va_mtime;
  307                 vap->va_birthtime.tv_sec = -1;
  308                 vap->va_birthtime.tv_nsec = 0;
  309         }
  310         vap->va_flags = 0;
  311         if (dep->de_Attributes & ATTR_ARCHIVE)
  312                 vap->va_flags |= UF_ARCHIVE;
  313         if (dep->de_Attributes & ATTR_HIDDEN)
  314                 vap->va_flags |= UF_HIDDEN;
  315         if (dep->de_Attributes & ATTR_READONLY)
  316                 vap->va_flags |= UF_READONLY;
  317         if (dep->de_Attributes & ATTR_SYSTEM)
  318                 vap->va_flags |= UF_SYSTEM;
  319         vap->va_gen = 0;
  320         vap->va_blocksize = pmp->pm_bpcluster;
  321         vap->va_bytes =
  322             (dep->de_FileSize + pmp->pm_crbomask) & ~pmp->pm_crbomask;
  323         vap->va_type = ap->a_vp->v_type;
  324         vap->va_filerev = dep->de_modrev;
  325         return (0);
  326 }
  327 
  328 static int
  329 msdosfs_setattr(struct vop_setattr_args *ap)
  330 {
  331         struct vnode *vp = ap->a_vp;
  332         struct denode *dep = VTODE(ap->a_vp);
  333         struct msdosfsmount *pmp = dep->de_pmp;
  334         struct vattr *vap = ap->a_vap;
  335         struct ucred *cred = ap->a_cred;
  336         struct thread *td = curthread;
  337         int error = 0;
  338 
  339 #ifdef MSDOSFS_DEBUG
  340         printf("msdosfs_setattr(): vp %p, vap %p, cred %p\n",
  341             ap->a_vp, vap, cred);
  342 #endif
  343 
  344         /*
  345          * Check for unsettable attributes.
  346          */
  347         if ((vap->va_type != VNON) || (vap->va_nlink != VNOVAL) ||
  348             (vap->va_fsid != VNOVAL) || (vap->va_fileid != VNOVAL) ||
  349             (vap->va_blocksize != VNOVAL) || (vap->va_rdev != VNOVAL) ||
  350             (vap->va_bytes != VNOVAL) || (vap->va_gen != VNOVAL)) {
  351 #ifdef MSDOSFS_DEBUG
  352                 printf("msdosfs_setattr(): returning EINVAL\n");
  353                 printf("    va_type %d, va_nlink %llx, va_fsid %llx, va_fileid %llx\n",
  354                     vap->va_type, (unsigned long long)vap->va_nlink,
  355                     (unsigned long long)vap->va_fsid,
  356                     (unsigned long long)vap->va_fileid);
  357                 printf("    va_blocksize %lx, va_rdev %llx, va_bytes %llx, va_gen %lx\n",
  358                     vap->va_blocksize, (unsigned long long)vap->va_rdev,
  359                     (unsigned long long)vap->va_bytes, vap->va_gen);
  360                 printf("    va_uid %x, va_gid %x\n",
  361                     vap->va_uid, vap->va_gid);
  362 #endif
  363                 return (EINVAL);
  364         }
  365 
  366         /*
  367          * We don't allow setting attributes on the root directory.
  368          * The special case for the root directory is because before
  369          * FAT32, the root directory didn't have an entry for itself
  370          * (and was otherwise special).  With FAT32, the root
  371          * directory is not so special, but still doesn't have an
  372          * entry for itself.
  373          */
  374         if (vp->v_vflag & VV_ROOT)
  375                 return (EINVAL);
  376 
  377         if (vap->va_flags != VNOVAL) {
  378                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
  379                         return (EROFS);
  380                 if (cred->cr_uid != pmp->pm_uid) {
  381                         error = priv_check_cred(cred, PRIV_VFS_ADMIN);
  382                         if (error)
  383                                 return (error);
  384                 }
  385                 /*
  386                  * We are very inconsistent about handling unsupported
  387                  * attributes.  We ignored the access time and the
  388                  * read and execute bits.  We were strict for the other
  389                  * attributes.
  390                  */
  391                 if (vap->va_flags & ~(UF_ARCHIVE | UF_HIDDEN | UF_READONLY |
  392                     UF_SYSTEM))
  393                         return EOPNOTSUPP;
  394                 if (vap->va_flags & UF_ARCHIVE)
  395                         dep->de_Attributes |= ATTR_ARCHIVE;
  396                 else
  397                         dep->de_Attributes &= ~ATTR_ARCHIVE;
  398                 if (vap->va_flags & UF_HIDDEN)
  399                         dep->de_Attributes |= ATTR_HIDDEN;
  400                 else
  401                         dep->de_Attributes &= ~ATTR_HIDDEN;
  402                 /* We don't allow changing the readonly bit on directories. */
  403                 if (vp->v_type != VDIR) {
  404                         if (vap->va_flags & UF_READONLY)
  405                                 dep->de_Attributes |= ATTR_READONLY;
  406                         else
  407                                 dep->de_Attributes &= ~ATTR_READONLY;
  408                 }
  409                 if (vap->va_flags & UF_SYSTEM)
  410                         dep->de_Attributes |= ATTR_SYSTEM;
  411                 else
  412                         dep->de_Attributes &= ~ATTR_SYSTEM;
  413                 dep->de_flag |= DE_MODIFIED;
  414         }
  415 
  416         if (vap->va_uid != (uid_t)VNOVAL || vap->va_gid != (gid_t)VNOVAL) {
  417                 uid_t uid;
  418                 gid_t gid;
  419 
  420                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
  421                         return (EROFS);
  422                 uid = vap->va_uid;
  423                 if (uid == (uid_t)VNOVAL)
  424                         uid = pmp->pm_uid;
  425                 gid = vap->va_gid;
  426                 if (gid == (gid_t)VNOVAL)
  427                         gid = pmp->pm_gid;
  428                 if (cred->cr_uid != pmp->pm_uid || uid != pmp->pm_uid ||
  429                     (gid != pmp->pm_gid && !groupmember(gid, cred))) {
  430                         error = priv_check_cred(cred, PRIV_VFS_CHOWN);
  431                         if (error)
  432                                 return (error);
  433                 }
  434                 if (uid != pmp->pm_uid || gid != pmp->pm_gid)
  435                         return EINVAL;
  436         }
  437 
  438         if (vap->va_size != VNOVAL) {
  439                 switch (vp->v_type) {
  440                 case VDIR:
  441                         return (EISDIR);
  442                 case VREG:
  443                         /*
  444                          * Truncation is only supported for regular files,
  445                          * Disallow it if the filesystem is read-only.
  446                          */
  447                         if (vp->v_mount->mnt_flag & MNT_RDONLY)
  448                                 return (EROFS);
  449                         break;
  450                 default:
  451                         /*
  452                          * According to POSIX, the result is unspecified
  453                          * for file types other than regular files,
  454                          * directories and shared memory objects.  We
  455                          * don't support any file types except regular
  456                          * files and directories in this file system, so
  457                          * this (default) case is unreachable and can do
  458                          * anything.  Keep falling through to detrunc()
  459                          * for now.
  460                          */
  461                         break;
  462                 }
  463                 error = vn_rlimit_trunc(vap->va_size, td);
  464                 if (error != 0)
  465                         return (error);
  466                 error = detrunc(dep, vap->va_size, 0, cred);
  467                 if (error)
  468                         return error;
  469         }
  470         if (vap->va_atime.tv_sec != VNOVAL || vap->va_mtime.tv_sec != VNOVAL) {
  471                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
  472                         return (EROFS);
  473                 error = vn_utimes_perm(vp, vap, cred, td);
  474                 if (error != 0)
  475                         return (error);
  476                 if ((pmp->pm_flags & MSDOSFSMNT_NOWIN95) == 0 &&
  477                     vap->va_atime.tv_sec != VNOVAL) {
  478                         dep->de_flag &= ~DE_ACCESS;
  479                         timespec2fattime(&vap->va_atime, 0,
  480                             &dep->de_ADate, NULL, NULL);
  481                 }
  482                 if (vap->va_mtime.tv_sec != VNOVAL) {
  483                         dep->de_flag &= ~DE_UPDATE;
  484                         timespec2fattime(&vap->va_mtime, 0,
  485                             &dep->de_MDate, &dep->de_MTime, NULL);
  486                 }
  487                 /*
  488                  * We don't set the archive bit when modifying the time of
  489                  * a directory to emulate the Windows/DOS behavior.
  490                  */
  491                 if (vp->v_type != VDIR)
  492                         dep->de_Attributes |= ATTR_ARCHIVE;
  493                 dep->de_flag |= DE_MODIFIED;
  494         }
  495         /*
  496          * DOS files only have the ability to have their writability
  497          * attribute set, so we use the owner write bit to set the readonly
  498          * attribute.
  499          */
  500         if (vap->va_mode != (mode_t)VNOVAL) {
  501                 if (vp->v_mount->mnt_flag & MNT_RDONLY)
  502                         return (EROFS);
  503                 if (cred->cr_uid != pmp->pm_uid) {
  504                         error = priv_check_cred(cred, PRIV_VFS_ADMIN);
  505                         if (error)
  506                                 return (error);
  507                 }
  508                 if (vp->v_type != VDIR) {
  509                         /* We ignore the read and execute bits. */
  510                         if (vap->va_mode & S_IWUSR)
  511                                 dep->de_Attributes &= ~ATTR_READONLY;
  512                         else
  513                                 dep->de_Attributes |= ATTR_READONLY;
  514                         dep->de_Attributes |= ATTR_ARCHIVE;
  515                         dep->de_flag |= DE_MODIFIED;
  516                 }
  517         }
  518         return (deupdat(dep, 0));
  519 }
  520 
  521 static int
  522 msdosfs_read(struct vop_read_args *ap)
  523 {
  524         int error = 0;
  525         int blsize;
  526         int isadir;
  527         ssize_t orig_resid;
  528         u_int n;
  529         u_long diff;
  530         u_long on;
  531         daddr_t lbn;
  532         daddr_t rablock;
  533         int rasize;
  534         int seqcount;
  535         struct buf *bp;
  536         struct vnode *vp = ap->a_vp;
  537         struct denode *dep = VTODE(vp);
  538         struct msdosfsmount *pmp = dep->de_pmp;
  539         struct uio *uio = ap->a_uio;
  540 
  541         /*
  542          * If they didn't ask for any data, then we are done.
  543          */
  544         orig_resid = uio->uio_resid;
  545         if (orig_resid == 0)
  546                 return (0);
  547 
  548         /*
  549          * The caller is supposed to ensure that
  550          * uio->uio_offset >= 0 and uio->uio_resid >= 0.
  551          * We don't need to check for large offsets as in ffs because
  552          * dep->de_FileSize <= MSDOSFS_FILESIZE_MAX < OFF_MAX, so large
  553          * offsets cannot cause overflow even in theory.
  554          */
  555 
  556         seqcount = ap->a_ioflag >> IO_SEQSHIFT;
  557 
  558         isadir = dep->de_Attributes & ATTR_DIRECTORY;
  559         do {
  560                 if (uio->uio_offset >= dep->de_FileSize)
  561                         break;
  562                 lbn = de_cluster(pmp, uio->uio_offset);
  563                 rablock = lbn + 1;
  564                 blsize = pmp->pm_bpcluster;
  565                 on = uio->uio_offset & pmp->pm_crbomask;
  566                 /*
  567                  * If we are operating on a directory file then be sure to
  568                  * do i/o with the vnode for the filesystem instead of the
  569                  * vnode for the directory.
  570                  */
  571                 if (isadir) {
  572                         /* convert cluster # to block # */
  573                         error = pcbmap(dep, lbn, &lbn, 0, &blsize);
  574                         if (error == E2BIG) {
  575                                 error = EINVAL;
  576                                 break;
  577                         } else if (error)
  578                                 break;
  579                         error = bread(pmp->pm_devvp, lbn, blsize, NOCRED, &bp);
  580                 } else if (de_cn2off(pmp, rablock) >= dep->de_FileSize) {
  581                         error = bread(vp, lbn, blsize, NOCRED, &bp);
  582                 } else if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) {
  583                         error = cluster_read(vp, dep->de_FileSize, lbn, blsize,
  584                             NOCRED, on + uio->uio_resid, seqcount, 0, &bp);
  585                 } else if (seqcount > 1) {
  586                         rasize = blsize;
  587                         error = breadn(vp, lbn,
  588                             blsize, &rablock, &rasize, 1, NOCRED, &bp);
  589                 } else {
  590                         error = bread(vp, lbn, blsize, NOCRED, &bp);
  591                 }
  592                 if (error) {
  593                         brelse(bp);
  594                         break;
  595                 }
  596                 diff = pmp->pm_bpcluster - on;
  597                 n = diff > uio->uio_resid ? uio->uio_resid : diff;
  598                 diff = dep->de_FileSize - uio->uio_offset;
  599                 if (diff < n)
  600                         n = diff;
  601                 diff = blsize - bp->b_resid;
  602                 if (diff < n)
  603                         n = diff;
  604                 error = vn_io_fault_uiomove(bp->b_data + on, (int) n, uio);
  605                 brelse(bp);
  606         } while (error == 0 && uio->uio_resid > 0 && n != 0);
  607         if (!isadir && (error == 0 || uio->uio_resid != orig_resid) &&
  608             (vp->v_mount->mnt_flag & (MNT_NOATIME | MNT_RDONLY)) == 0)
  609                 dep->de_flag |= DE_ACCESS;
  610         return (error);
  611 }
  612 
  613 /*
  614  * Write data to a file or directory.
  615  */
  616 static int
  617 msdosfs_write(struct vop_write_args *ap)
  618 {
  619         int n;
  620         int croffset;
  621         ssize_t resid, r;
  622         u_long osize;
  623         int error = 0;
  624         u_long count;
  625         int seqcount;
  626         daddr_t bn, lastcn;
  627         struct buf *bp;
  628         int ioflag = ap->a_ioflag;
  629         struct uio *uio = ap->a_uio;
  630         struct vnode *vp = ap->a_vp;
  631         struct vnode *thisvp;
  632         struct denode *dep = VTODE(vp);
  633         struct msdosfsmount *pmp = dep->de_pmp;
  634         struct ucred *cred = ap->a_cred;
  635 
  636 #ifdef MSDOSFS_DEBUG
  637         printf("msdosfs_write(vp %p, uio %p, ioflag %x, cred %p\n",
  638             vp, uio, ioflag, cred);
  639         printf("msdosfs_write(): diroff %lu, dirclust %lu, startcluster %lu\n",
  640             dep->de_diroffset, dep->de_dirclust, dep->de_StartCluster);
  641 #endif
  642 
  643         switch (vp->v_type) {
  644         case VREG:
  645                 if (ioflag & IO_APPEND)
  646                         uio->uio_offset = dep->de_FileSize;
  647                 thisvp = vp;
  648                 break;
  649         case VDIR:
  650                 return EISDIR;
  651         default:
  652                 panic("msdosfs_write(): bad file type");
  653         }
  654 
  655         /*
  656          * This is needed (unlike in ffs_write()) because we extend the
  657          * file outside of the loop but we don't want to extend the file
  658          * for writes of 0 bytes.
  659          */
  660         if (uio->uio_resid == 0)
  661                 return (0);
  662 
  663         /*
  664          * The caller is supposed to ensure that
  665          * uio->uio_offset >= 0 and uio->uio_resid >= 0.
  666          *
  667          * If they've exceeded their filesize limit, tell them about it.
  668          */
  669         error = vn_rlimit_fsizex(vp, uio, MSDOSFS_FILESIZE_MAX, &r,
  670             uio->uio_td);
  671         if (error != 0) {
  672                 vn_rlimit_fsizex_res(uio, r);
  673                 return (error);
  674         }
  675 
  676         /*
  677          * If the offset we are starting the write at is beyond the end of
  678          * the file, then they've done a seek.  Unix filesystems allow
  679          * files with holes in them, DOS doesn't so we must fill the hole
  680          * with zeroed blocks.
  681          */
  682         if (uio->uio_offset > dep->de_FileSize) {
  683                 error = deextend(dep, uio->uio_offset, cred);
  684                 if (error != 0) {
  685                         vn_rlimit_fsizex_res(uio, r);
  686                         return (error);
  687                 }
  688         }
  689 
  690         /*
  691          * Remember some values in case the write fails.
  692          */
  693         resid = uio->uio_resid;
  694         osize = dep->de_FileSize;
  695 
  696         /*
  697          * If we write beyond the end of the file, extend it to its ultimate
  698          * size ahead of the time to hopefully get a contiguous area.
  699          */
  700         if (uio->uio_offset + resid > osize) {
  701                 count = de_clcount(pmp, uio->uio_offset + resid) -
  702                         de_clcount(pmp, osize);
  703                 error = extendfile(dep, count, NULL, NULL, 0);
  704                 if (error &&  (error != ENOSPC || (ioflag & IO_UNIT)))
  705                         goto errexit;
  706                 lastcn = dep->de_fc[FC_LASTFC].fc_frcn;
  707         } else
  708                 lastcn = de_clcount(pmp, osize) - 1;
  709 
  710         seqcount = ioflag >> IO_SEQSHIFT;
  711         do {
  712                 if (de_cluster(pmp, uio->uio_offset) > lastcn) {
  713                         error = ENOSPC;
  714                         break;
  715                 }
  716 
  717                 croffset = uio->uio_offset & pmp->pm_crbomask;
  718                 n = min(uio->uio_resid, pmp->pm_bpcluster - croffset);
  719                 if (uio->uio_offset + n > dep->de_FileSize) {
  720                         dep->de_FileSize = uio->uio_offset + n;
  721                         /* The object size needs to be set before buffer is allocated */
  722                         vnode_pager_setsize(vp, dep->de_FileSize);
  723                 }
  724 
  725                 bn = de_cluster(pmp, uio->uio_offset);
  726                 if ((uio->uio_offset & pmp->pm_crbomask) == 0
  727                     && (de_cluster(pmp, uio->uio_offset + uio->uio_resid)
  728                         > de_cluster(pmp, uio->uio_offset)
  729                         || uio->uio_offset + uio->uio_resid >= dep->de_FileSize)) {
  730                         /*
  731                          * If either the whole cluster gets written,
  732                          * or we write the cluster from its start beyond EOF,
  733                          * then no need to read data from disk.
  734                          */
  735                         bp = getblk(thisvp, bn, pmp->pm_bpcluster, 0, 0, 0);
  736                         /*
  737                          * This call to vfs_bio_clrbuf() ensures that
  738                          * even if vn_io_fault_uiomove() below faults,
  739                          * garbage from the newly instantiated buffer
  740                          * is not exposed to the userspace via mmap().
  741                          */
  742                         vfs_bio_clrbuf(bp);
  743                         /*
  744                          * Do the bmap now, since pcbmap needs buffers
  745                          * for the FAT table. (see msdosfs_strategy)
  746                          */
  747                         if (bp->b_blkno == bp->b_lblkno) {
  748                                 error = pcbmap(dep, bp->b_lblkno, &bn, 0, 0);
  749                                 if (error)
  750                                         bp->b_blkno = -1;
  751                                 else
  752                                         bp->b_blkno = bn;
  753                         }
  754                         if (bp->b_blkno == -1) {
  755                                 brelse(bp);
  756                                 if (!error)
  757                                         error = EIO;            /* XXX */
  758                                 break;
  759                         }
  760                 } else {
  761                         /*
  762                          * The block we need to write into exists, so read it in.
  763                          */
  764                         error = bread(thisvp, bn, pmp->pm_bpcluster, cred, &bp);
  765                         if (error) {
  766                                 break;
  767                         }
  768                 }
  769 
  770                 /*
  771                  * Should these vnode_pager_* functions be done on dir
  772                  * files?
  773                  */
  774 
  775                 /*
  776                  * Copy the data from user space into the buf header.
  777                  */
  778                 error = vn_io_fault_uiomove(bp->b_data + croffset, n, uio);
  779                 if (error) {
  780                         brelse(bp);
  781                         break;
  782                 }
  783 
  784                 /* Prepare for clustered writes in some else clauses. */
  785                 if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERW) == 0)
  786                         bp->b_flags |= B_CLUSTEROK;
  787 
  788                 /*
  789                  * If IO_SYNC, then each buffer is written synchronously.
  790                  * Otherwise, if we have a severe page deficiency then
  791                  * write the buffer asynchronously.  Otherwise, if on a
  792                  * cluster boundary then write the buffer asynchronously,
  793                  * combining it with contiguous clusters if permitted and
  794                  * possible, since we don't expect more writes into this
  795                  * buffer soon.  Otherwise, do a delayed write because we
  796                  * expect more writes into this buffer soon.
  797                  */
  798                 if (ioflag & IO_SYNC)
  799                         (void)bwrite(bp);
  800                 else if (vm_page_count_severe() || buf_dirty_count_severe())
  801                         bawrite(bp);
  802                 else if (n + croffset == pmp->pm_bpcluster) {
  803                         if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERW) == 0)
  804                                 cluster_write(vp, bp, dep->de_FileSize,
  805                                     seqcount, 0);
  806                         else
  807                                 bawrite(bp);
  808                 } else
  809                         bdwrite(bp);
  810                 dep->de_flag |= DE_UPDATE;
  811         } while (error == 0 && uio->uio_resid > 0);
  812 
  813         /*
  814          * If the write failed and they want us to, truncate the file back
  815          * to the size it was before the write was attempted.
  816          */
  817 errexit:
  818         if (error) {
  819                 if (ioflag & IO_UNIT) {
  820                         detrunc(dep, osize, ioflag & IO_SYNC, NOCRED);
  821                         uio->uio_offset -= resid - uio->uio_resid;
  822                         uio->uio_resid = resid;
  823                 } else {
  824                         detrunc(dep, dep->de_FileSize, ioflag & IO_SYNC, NOCRED);
  825                         if (uio->uio_resid != resid)
  826                                 error = 0;
  827                 }
  828         } else if (ioflag & IO_SYNC)
  829                 error = deupdat(dep, 1);
  830         vn_rlimit_fsizex_res(uio, r);
  831         return (error);
  832 }
  833 
  834 /*
  835  * Flush the blocks of a file to disk.
  836  */
  837 static int
  838 msdosfs_fsync(struct vop_fsync_args *ap)
  839 {
  840         struct vnode *devvp;
  841         int allerror, error;
  842 
  843         vop_stdfsync(ap);
  844 
  845         /*
  846         * If the syncing request comes from fsync(2), sync the entire
  847         * FAT and any other metadata that happens to be on devvp.  We
  848         * need this mainly for the FAT.  We write the FAT sloppily, and
  849         * syncing it all now is the best we can easily do to get all
  850         * directory entries associated with the file (not just the file)
  851         * fully synced.  The other metadata includes critical metadata
  852         * for all directory entries, but only in the MNT_ASYNC case.  We
  853         * will soon sync all metadata in the file's directory entry.
  854         * Non-critical metadata for associated directory entries only
  855         * gets synced accidentally, as in most file systems.
  856         */
  857         if (ap->a_waitfor != MNT_NOWAIT) {
  858                 devvp = VTODE(ap->a_vp)->de_pmp->pm_devvp;
  859                 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
  860                 allerror = VOP_FSYNC(devvp, MNT_WAIT, ap->a_td);
  861                 VOP_UNLOCK(devvp);
  862         } else
  863                 allerror = 0;
  864 
  865         error = deupdat(VTODE(ap->a_vp), ap->a_waitfor != MNT_NOWAIT);
  866         if (allerror == 0)
  867                 allerror = error;
  868         return (allerror);
  869 }
  870 
  871 static int
  872 msdosfs_remove(struct vop_remove_args *ap)
  873 {
  874         struct denode *dep = VTODE(ap->a_vp);
  875         struct denode *ddep = VTODE(ap->a_dvp);
  876         int error;
  877 
  878         if (ap->a_vp->v_type == VDIR)
  879                 error = EPERM;
  880         else
  881                 error = removede(ddep, dep);
  882 #ifdef MSDOSFS_DEBUG
  883         printf("msdosfs_remove(), dep %p, v_usecount %d\n", dep, ap->a_vp->v_usecount);
  884 #endif
  885         return (error);
  886 }
  887 
  888 /*
  889  * DOS filesystems don't know what links are.
  890  */
  891 static int
  892 msdosfs_link(struct vop_link_args *ap)
  893 {
  894         return (EOPNOTSUPP);
  895 }
  896 
  897 /*
  898  * Renames on files require moving the denode to a new hash queue since the
  899  * denode's location is used to compute which hash queue to put the file
  900  * in. Unless it is a rename in place.  For example "mv a b".
  901  *
  902  * What follows is the basic algorithm:
  903  *
  904  * if (file move) {
  905  *      if (dest file exists) {
  906  *              remove dest file
  907  *      }
  908  *      if (dest and src in same directory) {
  909  *              rewrite name in existing directory slot
  910  *      } else {
  911  *              write new entry in dest directory
  912  *              update offset and dirclust in denode
  913  *              move denode to new hash chain
  914  *              clear old directory entry
  915  *      }
  916  * } else {
  917  *      directory move
  918  *      if (dest directory exists) {
  919  *              if (dest is not empty) {
  920  *                      return ENOTEMPTY
  921  *              }
  922  *              remove dest directory
  923  *      }
  924  *      if (dest and src in same directory) {
  925  *              rewrite name in existing entry
  926  *      } else {
  927  *              be sure dest is not a child of src directory
  928  *              write entry in dest directory
  929  *              update "." and ".." in moved directory
  930  *              clear old directory entry for moved directory
  931  *      }
  932  * }
  933  *
  934  * On entry:
  935  *      source's parent directory is unlocked
  936  *      source file or directory is unlocked
  937  *      destination's parent directory is locked
  938  *      destination file or directory is locked if it exists
  939  *
  940  * On exit:
  941  *      all denodes should be released
  942  */
  943 static int
  944 msdosfs_rename(struct vop_rename_args *ap)
  945 {
  946         struct vnode *fdvp, *fvp, *tdvp, *tvp, *vp;
  947         struct componentname *fcnp, *tcnp;
  948         struct denode *fdip, *fip, *tdip, *tip, *nip;
  949         u_char toname[12], oldname[11];
  950         u_long to_diroffset;
  951         bool checkpath_locked, doingdirectory, newparent;
  952         int error;
  953         u_long cn, pcl, blkoff;
  954         daddr_t bn, wait_scn, scn;
  955         struct msdosfsmount *pmp;
  956         struct direntry *dotdotp;
  957         struct buf *bp;
  958 
  959         tdvp = ap->a_tdvp;
  960         fvp = ap->a_fvp;
  961         fdvp = ap->a_fdvp;
  962         tvp = ap->a_tvp;
  963         tcnp = ap->a_tcnp;
  964         fcnp = ap->a_fcnp;
  965         pmp = VFSTOMSDOSFS(fdvp->v_mount);
  966 
  967 #ifdef DIAGNOSTIC
  968         if ((tcnp->cn_flags & HASBUF) == 0 ||
  969             (fcnp->cn_flags & HASBUF) == 0)
  970                 panic("msdosfs_rename: no name");
  971 #endif
  972         /*
  973          * Check for cross-device rename.
  974          */
  975         if (fvp->v_mount != tdvp->v_mount ||
  976             (tvp != NULL && fvp->v_mount != tvp->v_mount)) {
  977                 error = EXDEV;
  978                 goto abortit;
  979         }
  980 
  981         /*
  982          * If source and dest are the same, do nothing.
  983          */
  984         if (tvp == fvp) {
  985                 error = 0;
  986                 goto abortit;
  987         }
  988 
  989         /*
  990          * When the target exists, both the directory
  991          * and target vnodes are passed locked.
  992          */
  993         VOP_UNLOCK(tdvp);
  994         if (tvp != NULL && tvp != tdvp)
  995                 VOP_UNLOCK(tvp);
  996 
  997         checkpath_locked = false;
  998 
  999 relock:
 1000         doingdirectory = newparent = false;
 1001 
 1002         error = vn_lock(fdvp, LK_EXCLUSIVE);
 1003         if (error != 0)
 1004                 goto releout;
 1005         if (vn_lock(tdvp, LK_EXCLUSIVE | LK_NOWAIT) != 0) {
 1006                 VOP_UNLOCK(fdvp);
 1007                 error = vn_lock(tdvp, LK_EXCLUSIVE);
 1008                 if (error != 0)
 1009                         goto releout;
 1010                 VOP_UNLOCK(tdvp);
 1011                 goto relock;
 1012         }
 1013 
 1014         error = msdosfs_lookup_ino(fdvp, NULL, fcnp, &scn, &blkoff);
 1015         if (error != 0) {
 1016                 VOP_UNLOCK(fdvp);
 1017                 VOP_UNLOCK(tdvp);
 1018                 goto releout;
 1019         }
 1020         error = deget(pmp, scn, blkoff, LK_EXCLUSIVE | LK_NOWAIT, &nip);
 1021         if (error != 0) {
 1022                 VOP_UNLOCK(fdvp);
 1023                 VOP_UNLOCK(tdvp);
 1024                 if (error != EBUSY)
 1025                         goto releout;
 1026                 error = deget(pmp, scn, blkoff, LK_EXCLUSIVE, &nip);
 1027                 if (error != 0)
 1028                         goto releout;
 1029                 vp = fvp;
 1030                 fvp = DETOV(nip);
 1031                 VOP_UNLOCK(fvp);
 1032                 vrele(vp);
 1033                 goto relock;
 1034         }
 1035         vrele(fvp);
 1036         fvp = DETOV(nip);
 1037 
 1038         error = msdosfs_lookup_ino(tdvp, NULL, tcnp, &scn, &blkoff);
 1039         if (error != 0 && error != EJUSTRETURN) {
 1040                 VOP_UNLOCK(fdvp);
 1041                 VOP_UNLOCK(tdvp);
 1042                 VOP_UNLOCK(fvp);
 1043                 goto releout;
 1044         }
 1045         if (error == EJUSTRETURN && tvp != NULL) {
 1046                 vrele(tvp);
 1047                 tvp = NULL;
 1048         }
 1049         if (error == 0) {
 1050                 nip = NULL;
 1051                 error = deget(pmp, scn, blkoff, LK_EXCLUSIVE | LK_NOWAIT,
 1052                     &nip);
 1053                 if (tvp != NULL) {
 1054                         vrele(tvp);
 1055                         tvp = NULL;
 1056                 }
 1057                 if (error != 0) {
 1058                         VOP_UNLOCK(fdvp);
 1059                         VOP_UNLOCK(tdvp);
 1060                         VOP_UNLOCK(fvp);
 1061                         if (error != EBUSY)
 1062                                 goto releout;
 1063                         error = deget(pmp, scn, blkoff, LK_EXCLUSIVE,
 1064                             &nip);
 1065                         if (error != 0)
 1066                                 goto releout;
 1067                         vput(DETOV(nip));
 1068                         goto relock;
 1069                 }
 1070                 tvp = DETOV(nip);
 1071         }
 1072 
 1073         fdip = VTODE(fdvp);
 1074         fip = VTODE(fvp);
 1075         tdip = VTODE(tdvp);
 1076         tip = tvp != NULL ? VTODE(tvp) : NULL;
 1077 
 1078         /*
 1079          * Remember direntry place to use for destination
 1080          */
 1081         to_diroffset = tdip->de_fndoffset;
 1082 
 1083         /*
 1084          * Be sure we are not renaming ".", "..", or an alias of ".". This
 1085          * leads to a crippled directory tree.  It's pretty tough to do a
 1086          * "ls" or "pwd" with the "." directory entry missing, and "cd .."
 1087          * doesn't work if the ".." entry is missing.
 1088          */
 1089         if ((fip->de_Attributes & ATTR_DIRECTORY) != 0) {
 1090                 /*
 1091                  * Avoid ".", "..", and aliases of "." for obvious reasons.
 1092                  */
 1093                 if ((fcnp->cn_namelen == 1 && fcnp->cn_nameptr[0] == '.') ||
 1094                     fdip == fip ||
 1095                     (fcnp->cn_flags & ISDOTDOT) != 0 ||
 1096                     (tcnp->cn_flags & ISDOTDOT) != 0) {
 1097                         error = EINVAL;
 1098                         goto unlock;
 1099                 }
 1100                 doingdirectory = true;
 1101         }
 1102 
 1103         /*
 1104          * If ".." must be changed (ie the directory gets a new
 1105          * parent) then the source directory must not be in the
 1106          * directory hierarchy above the target, as this would
 1107          * orphan everything below the source directory. Also
 1108          * the user must have write permission in the source so
 1109          * as to be able to change "..". We must repeat the call
 1110          * to namei, as the parent directory is unlocked by the
 1111          * call to doscheckpath().
 1112          */
 1113         error = VOP_ACCESS(fvp, VWRITE, tcnp->cn_cred, tcnp->cn_thread);
 1114         if (fdip->de_StartCluster != tdip->de_StartCluster)
 1115                 newparent = true;
 1116         if (doingdirectory && newparent) {
 1117                 if (error != 0) /* write access check above */
 1118                         goto unlock;
 1119                 lockmgr(&pmp->pm_checkpath_lock, LK_EXCLUSIVE, NULL);
 1120                 checkpath_locked = true;
 1121                 error = doscheckpath(fip, tdip, &wait_scn);
 1122                 if (wait_scn != 0) {
 1123                         lockmgr(&pmp->pm_checkpath_lock, LK_RELEASE, NULL);
 1124                         checkpath_locked = false;
 1125                         VOP_UNLOCK(fdvp);
 1126                         VOP_UNLOCK(tdvp);
 1127                         VOP_UNLOCK(fvp);
 1128                         if (tvp != NULL && tvp != tdvp)
 1129                                 VOP_UNLOCK(tvp);
 1130                         error = deget(pmp, wait_scn, 0, LK_EXCLUSIVE,
 1131                             &nip);
 1132                         if (error == 0) {
 1133                                 vput(DETOV(nip));
 1134                                 goto relock;
 1135                         }
 1136                 }
 1137                 if (error != 0)
 1138                         goto unlock;
 1139                 if ((tcnp->cn_flags & SAVESTART) == 0)
 1140                         panic("msdosfs_rename: lost to startdir");
 1141         }
 1142 
 1143         if (tip != NULL) {
 1144                 /*
 1145                  * Target must be empty if a directory and have no links
 1146                  * to it. Also, ensure source and target are compatible
 1147                  * (both directories, or both not directories).
 1148                  */
 1149                 if ((tip->de_Attributes & ATTR_DIRECTORY) != 0) {
 1150                         if (!dosdirempty(tip)) {
 1151                                 error = ENOTEMPTY;
 1152                                 goto unlock;
 1153                         }
 1154                         if (!doingdirectory) {
 1155                                 error = ENOTDIR;
 1156                                 goto unlock;
 1157                         }
 1158                         cache_purge(tdvp);
 1159                 } else if (doingdirectory) {
 1160                         error = EISDIR;
 1161                         goto unlock;
 1162                 }
 1163                 error = msdosfs_lookup_ino(tdvp, NULL, tcnp, &scn, &blkoff);
 1164                 MPASS(error == 0);
 1165                 error = removede(tdip, tip);
 1166                 if (error != 0)
 1167                         goto unlock;
 1168                 vput(tvp);
 1169                 tvp = NULL;
 1170                 tip = NULL;
 1171         }
 1172 
 1173         /*
 1174          * Convert the filename in tcnp into a dos filename. We copy this
 1175          * into the denode and directory entry for the destination
 1176          * file/directory.
 1177          */
 1178         error = uniqdosname(tdip, tcnp, toname);
 1179         if (error != 0)
 1180                 goto unlock;
 1181 
 1182         /*
 1183          * First write a new entry in the destination
 1184          * directory and mark the entry in the source directory
 1185          * as deleted.  Then move the denode to the correct hash
 1186          * chain for its new location in the filesystem.  And, if
 1187          * we moved a directory, then update its .. entry to point
 1188          * to the new parent directory.
 1189          */
 1190         memcpy(oldname, fip->de_Name, 11);
 1191         memcpy(fip->de_Name, toname, 11);       /* update denode */
 1192         error = msdosfs_lookup_ino(tdvp, NULL, tcnp, &scn, &blkoff);
 1193         MPASS(error == EJUSTRETURN);
 1194         error = createde(fip, tdip, NULL, tcnp);
 1195         if (error != 0) {
 1196                 memcpy(fip->de_Name, oldname, 11);
 1197                 goto unlock;
 1198         }
 1199 
 1200         /*
 1201          * If fip is for a directory, then its name should always
 1202          * be "." since it is for the directory entry in the
 1203          * directory itself (msdosfs_lookup() always translates
 1204          * to the "." entry so as to get a unique denode, except
 1205          * for the root directory there are different
 1206          * complications).  However, we just corrupted its name
 1207          * to pass the correct name to createde().  Undo this.
 1208          */
 1209         if ((fip->de_Attributes & ATTR_DIRECTORY) != 0)
 1210                 memcpy(fip->de_Name, oldname, 11);
 1211         fip->de_refcnt++;
 1212         error = msdosfs_lookup_ino(fdvp, NULL, fcnp, &scn, &blkoff);
 1213         MPASS(error == 0);
 1214         error = removede(fdip, fip);
 1215         if (error != 0) {
 1216                 /* XXX should downgrade to ro here, fs is corrupt */
 1217                 goto unlock;
 1218         }
 1219         if (!doingdirectory) {
 1220                 error = pcbmap(tdip, de_cluster(pmp, to_diroffset), 0,
 1221                     &fip->de_dirclust, 0);
 1222                 if (error != 0) {
 1223                         /*
 1224                          * XXX should downgrade to ro here,
 1225                          * fs is corrupt
 1226                          */
 1227                         goto unlock;
 1228                 }
 1229                 if (fip->de_dirclust == MSDOSFSROOT)
 1230                         fip->de_diroffset = to_diroffset;
 1231                 else
 1232                         fip->de_diroffset = to_diroffset & pmp->pm_crbomask;
 1233         }
 1234         reinsert(fip);
 1235 
 1236         /*
 1237          * If we moved a directory to a new parent directory, then we must
 1238          * fixup the ".." entry in the moved directory.
 1239          */
 1240         if (doingdirectory && newparent) {
 1241                 cn = fip->de_StartCluster;
 1242                 if (cn == MSDOSFSROOT) {
 1243                         /* this should never happen */
 1244                         panic("msdosfs_rename(): updating .. in root directory?");
 1245                 } else
 1246                         bn = cntobn(pmp, cn);
 1247                 error = bread(pmp->pm_devvp, bn, pmp->pm_bpcluster,
 1248                     NOCRED, &bp);
 1249                 if (error != 0) {
 1250                         /* XXX should downgrade to ro here, fs is corrupt */
 1251                         goto unlock;
 1252                 }
 1253                 dotdotp = (struct direntry *)bp->b_data + 1;
 1254                 pcl = tdip->de_StartCluster;
 1255                 if (FAT32(pmp) && pcl == pmp->pm_rootdirblk)
 1256                         pcl = MSDOSFSROOT;
 1257                 putushort(dotdotp->deStartCluster, pcl);
 1258                 if (FAT32(pmp))
 1259                         putushort(dotdotp->deHighClust, pcl >> 16);
 1260                 if (DOINGASYNC(fvp))
 1261                         bdwrite(bp);
 1262                 else if ((error = bwrite(bp)) != 0) {
 1263                         /* XXX should downgrade to ro here, fs is corrupt */
 1264                         goto unlock;
 1265                 }
 1266         }
 1267 
 1268         /*
 1269          * The msdosfs lookup is case insensitive. Several aliases may
 1270          * be inserted for a single directory entry. As a consequnce,
 1271          * name cache purge done by lookup for fvp when DELETE op for
 1272          * namei is specified, might be not enough to expunge all
 1273          * namecache entries that were installed for this direntry.
 1274          */
 1275         cache_purge(fvp);
 1276 
 1277 unlock:
 1278         if (checkpath_locked)
 1279                 lockmgr(&pmp->pm_checkpath_lock, LK_RELEASE, NULL);
 1280         vput(fdvp);
 1281         vput(fvp);
 1282         if (tvp != NULL) {
 1283                 if (tvp != tdvp)
 1284                         vput(tvp);
 1285                 else
 1286                         vrele(tvp);
 1287         }
 1288         vput(tdvp);
 1289         return (error);
 1290 releout:
 1291         MPASS(!checkpath_locked);
 1292         vrele(tdvp);
 1293         if (tvp != NULL)
 1294                 vrele(tvp);
 1295         vrele(fdvp);
 1296         vrele(fvp);
 1297         return (error);
 1298 abortit:
 1299         if (tdvp == tvp)
 1300                 vrele(tdvp);
 1301         else
 1302                 vput(tdvp);
 1303         if (tvp != NULL)
 1304                 vput(tvp);
 1305         vrele(fdvp);
 1306         vrele(fvp);
 1307         return (error);
 1308 }
 1309 
 1310 static struct {
 1311         struct direntry dot;
 1312         struct direntry dotdot;
 1313 } dosdirtemplate = {
 1314         {       ".          ",                          /* the . entry */
 1315                 ATTR_DIRECTORY,                         /* file attribute */
 1316                 0,                                      /* reserved */
 1317                 0, { 0, 0 }, { 0, 0 },                  /* create time & date */
 1318                 { 0, 0 },                               /* access date */
 1319                 { 0, 0 },                               /* high bits of start cluster */
 1320                 { 210, 4 }, { 210, 4 },                 /* modify time & date */
 1321                 { 0, 0 },                               /* startcluster */
 1322                 { 0, 0, 0, 0 }                          /* filesize */
 1323         },
 1324         {       "..         ",                          /* the .. entry */
 1325                 ATTR_DIRECTORY,                         /* file attribute */
 1326                 0,                                      /* reserved */
 1327                 0, { 0, 0 }, { 0, 0 },                  /* create time & date */
 1328                 { 0, 0 },                               /* access date */
 1329                 { 0, 0 },                               /* high bits of start cluster */
 1330                 { 210, 4 }, { 210, 4 },                 /* modify time & date */
 1331                 { 0, 0 },                               /* startcluster */
 1332                 { 0, 0, 0, 0 }                          /* filesize */
 1333         }
 1334 };
 1335 
 1336 static int
 1337 msdosfs_mkdir(struct vop_mkdir_args *ap)
 1338 {
 1339         struct componentname *cnp = ap->a_cnp;
 1340         struct denode *dep;
 1341         struct denode *pdep = VTODE(ap->a_dvp);
 1342         struct direntry *denp;
 1343         struct msdosfsmount *pmp = pdep->de_pmp;
 1344         struct buf *bp;
 1345         u_long newcluster, pcl;
 1346         int bn;
 1347         int error;
 1348         struct denode ndirent;
 1349         struct timespec ts;
 1350 
 1351         /*
 1352          * If this is the root directory and there is no space left we
 1353          * can't do anything.  This is because the root directory can not
 1354          * change size.
 1355          */
 1356         if (pdep->de_StartCluster == MSDOSFSROOT
 1357             && pdep->de_fndoffset >= pdep->de_FileSize) {
 1358                 error = ENOSPC;
 1359                 goto bad2;
 1360         }
 1361 
 1362         /*
 1363          * Allocate a cluster to hold the about to be created directory.
 1364          */
 1365         error = clusteralloc(pmp, 0, 1, CLUST_EOFE, &newcluster, NULL);
 1366         if (error)
 1367                 goto bad2;
 1368 
 1369         memset(&ndirent, 0, sizeof(ndirent));
 1370         ndirent.de_pmp = pmp;
 1371         ndirent.de_flag = DE_ACCESS | DE_CREATE | DE_UPDATE;
 1372         vfs_timestamp(&ts);
 1373         DETIMES(&ndirent, &ts, &ts, &ts);
 1374 
 1375         /*
 1376          * Now fill the cluster with the "." and ".." entries. And write
 1377          * the cluster to disk.  This way it is there for the parent
 1378          * directory to be pointing at if there were a crash.
 1379          */
 1380         bn = cntobn(pmp, newcluster);
 1381         /* always succeeds */
 1382         bp = getblk(pmp->pm_devvp, bn, pmp->pm_bpcluster, 0, 0, 0);
 1383         memset(bp->b_data, 0, pmp->pm_bpcluster);
 1384         memcpy(bp->b_data, &dosdirtemplate, sizeof dosdirtemplate);
 1385         denp = (struct direntry *)bp->b_data;
 1386         putushort(denp[0].deStartCluster, newcluster);
 1387         putushort(denp[0].deCDate, ndirent.de_CDate);
 1388         putushort(denp[0].deCTime, ndirent.de_CTime);
 1389         denp[0].deCHundredth = ndirent.de_CHun;
 1390         putushort(denp[0].deADate, ndirent.de_ADate);
 1391         putushort(denp[0].deMDate, ndirent.de_MDate);
 1392         putushort(denp[0].deMTime, ndirent.de_MTime);
 1393         pcl = pdep->de_StartCluster;
 1394         /*
 1395          * Although the root directory has a non-magic starting cluster
 1396          * number for FAT32, chkdsk and fsck_msdosfs still require
 1397          * references to it in dotdot entries to be magic.
 1398          */
 1399         if (FAT32(pmp) && pcl == pmp->pm_rootdirblk)
 1400                 pcl = MSDOSFSROOT;
 1401         putushort(denp[1].deStartCluster, pcl);
 1402         putushort(denp[1].deCDate, ndirent.de_CDate);
 1403         putushort(denp[1].deCTime, ndirent.de_CTime);
 1404         denp[1].deCHundredth = ndirent.de_CHun;
 1405         putushort(denp[1].deADate, ndirent.de_ADate);
 1406         putushort(denp[1].deMDate, ndirent.de_MDate);
 1407         putushort(denp[1].deMTime, ndirent.de_MTime);
 1408         if (FAT32(pmp)) {
 1409                 putushort(denp[0].deHighClust, newcluster >> 16);
 1410                 putushort(denp[1].deHighClust, pcl >> 16);
 1411         }
 1412 
 1413         if (DOINGASYNC(ap->a_dvp))
 1414                 bdwrite(bp);
 1415         else if ((error = bwrite(bp)) != 0)
 1416                 goto bad;
 1417 
 1418         /*
 1419          * Now build up a directory entry pointing to the newly allocated
 1420          * cluster.  This will be written to an empty slot in the parent
 1421          * directory.
 1422          */
 1423 #ifdef DIAGNOSTIC
 1424         if ((cnp->cn_flags & HASBUF) == 0)
 1425                 panic("msdosfs_mkdir: no name");
 1426 #endif
 1427         error = uniqdosname(pdep, cnp, ndirent.de_Name);
 1428         if (error)
 1429                 goto bad;
 1430 
 1431         ndirent.de_Attributes = ATTR_DIRECTORY;
 1432         ndirent.de_LowerCase = 0;
 1433         ndirent.de_StartCluster = newcluster;
 1434         ndirent.de_FileSize = 0;
 1435         error = createde(&ndirent, pdep, &dep, cnp);
 1436         if (error)
 1437                 goto bad;
 1438         *ap->a_vpp = DETOV(dep);
 1439         return (0);
 1440 
 1441 bad:
 1442         clusterfree(pmp, newcluster);
 1443 bad2:
 1444         return (error);
 1445 }
 1446 
 1447 static int
 1448 msdosfs_rmdir(struct vop_rmdir_args *ap)
 1449 {
 1450         struct vnode *vp = ap->a_vp;
 1451         struct vnode *dvp = ap->a_dvp;
 1452         struct componentname *cnp = ap->a_cnp;
 1453         struct denode *ip, *dp;
 1454         int error;
 1455 
 1456         ip = VTODE(vp);
 1457         dp = VTODE(dvp);
 1458 
 1459         /*
 1460          * Verify the directory is empty (and valid).
 1461          * (Rmdir ".." won't be valid since
 1462          *  ".." will contain a reference to
 1463          *  the current directory and thus be
 1464          *  non-empty.)
 1465          */
 1466         error = 0;
 1467         if (!dosdirempty(ip)) {
 1468                 error = ENOTEMPTY;
 1469                 goto out;
 1470         }
 1471         /*
 1472          * Delete the entry from the directory.  For dos filesystems this
 1473          * gets rid of the directory entry on disk, the in memory copy
 1474          * still exists but the de_refcnt is <= 0.  This prevents it from
 1475          * being found by deget().  When the vput() on dep is done we give
 1476          * up access and eventually msdosfs_reclaim() will be called which
 1477          * will remove it from the denode cache.
 1478          */
 1479         error = removede(dp, ip);
 1480         if (error)
 1481                 goto out;
 1482         /*
 1483          * This is where we decrement the link count in the parent
 1484          * directory.  Since dos filesystems don't do this we just purge
 1485          * the name cache.
 1486          */
 1487         cache_purge(dvp);
 1488         /*
 1489          * Truncate the directory that is being deleted.
 1490          */
 1491         error = detrunc(ip, (u_long)0, IO_SYNC, cnp->cn_cred);
 1492         cache_purge(vp);
 1493 
 1494 out:
 1495         return (error);
 1496 }
 1497 
 1498 /*
 1499  * DOS filesystems don't know what symlinks are.
 1500  */
 1501 static int
 1502 msdosfs_symlink(struct vop_symlink_args *ap)
 1503 {
 1504         return (EOPNOTSUPP);
 1505 }
 1506 
 1507 static int
 1508 msdosfs_readdir(struct vop_readdir_args *ap)
 1509 {
 1510         struct mbnambuf nb;
 1511         int error = 0;
 1512         int diff;
 1513         long n;
 1514         int blsize;
 1515         long on;
 1516         u_long cn;
 1517         u_long dirsperblk;
 1518         long bias = 0;
 1519         daddr_t bn, lbn;
 1520         struct buf *bp;
 1521         struct denode *dep = VTODE(ap->a_vp);
 1522         struct msdosfsmount *pmp = dep->de_pmp;
 1523         struct direntry *dentp;
 1524         struct dirent dirbuf;
 1525         struct uio *uio = ap->a_uio;
 1526         u_long *cookies = NULL;
 1527         int ncookies = 0;
 1528         off_t offset, off;
 1529         int chksum = -1;
 1530 
 1531 #ifdef MSDOSFS_DEBUG
 1532         printf("msdosfs_readdir(): vp %p, uio %p, cred %p, eofflagp %p\n",
 1533             ap->a_vp, uio, ap->a_cred, ap->a_eofflag);
 1534 #endif
 1535 
 1536         /*
 1537          * msdosfs_readdir() won't operate properly on regular files since
 1538          * it does i/o only with the filesystem vnode, and hence can
 1539          * retrieve the wrong block from the buffer cache for a plain file.
 1540          * So, fail attempts to readdir() on a plain file.
 1541          */
 1542         if ((dep->de_Attributes & ATTR_DIRECTORY) == 0)
 1543                 return (ENOTDIR);
 1544 
 1545         /*
 1546          * To be safe, initialize dirbuf
 1547          */
 1548         memset(dirbuf.d_name, 0, sizeof(dirbuf.d_name));
 1549 
 1550         /*
 1551          * If the user buffer is smaller than the size of one dos directory
 1552          * entry or the file offset is not a multiple of the size of a
 1553          * directory entry, then we fail the read.
 1554          */
 1555         off = offset = uio->uio_offset;
 1556         if (uio->uio_resid < sizeof(struct direntry) ||
 1557             (offset & (sizeof(struct direntry) - 1)))
 1558                 return (EINVAL);
 1559 
 1560         if (ap->a_ncookies) {
 1561                 ncookies = uio->uio_resid / 16;
 1562                 cookies = malloc(ncookies * sizeof(u_long), M_TEMP,
 1563                        M_WAITOK);
 1564                 *ap->a_cookies = cookies;
 1565                 *ap->a_ncookies = ncookies;
 1566         }
 1567 
 1568         dirsperblk = pmp->pm_BytesPerSec / sizeof(struct direntry);
 1569 
 1570         /*
 1571          * If they are reading from the root directory then, we simulate
 1572          * the . and .. entries since these don't exist in the root
 1573          * directory.  We also set the offset bias to make up for having to
 1574          * simulate these entries. By this I mean that at file offset 64 we
 1575          * read the first entry in the root directory that lives on disk.
 1576          */
 1577         if (dep->de_StartCluster == MSDOSFSROOT
 1578             || (FAT32(pmp) && dep->de_StartCluster == pmp->pm_rootdirblk)) {
 1579 #if 0
 1580                 printf("msdosfs_readdir(): going after . or .. in root dir, offset %d\n",
 1581                     offset);
 1582 #endif
 1583                 bias = 2 * sizeof(struct direntry);
 1584                 if (offset < bias) {
 1585                         for (n = (int)offset / sizeof(struct direntry);
 1586                              n < 2; n++) {
 1587                                 dirbuf.d_fileno = FAT32(pmp) ?
 1588                                     (uint64_t)cntobn(pmp, pmp->pm_rootdirblk) *
 1589                                     dirsperblk : 1;
 1590                                 dirbuf.d_type = DT_DIR;
 1591                                 switch (n) {
 1592                                 case 0:
 1593                                         dirbuf.d_namlen = 1;
 1594                                         dirbuf.d_name[0] = '.';
 1595                                         break;
 1596                                 case 1:
 1597                                         dirbuf.d_namlen = 2;
 1598                                         dirbuf.d_name[0] = '.';
 1599                                         dirbuf.d_name[1] = '.';
 1600                                         break;
 1601                                 }
 1602                                 dirbuf.d_reclen = GENERIC_DIRSIZ(&dirbuf);
 1603                                 /* NOTE: d_off is the offset of the *next* entry. */
 1604                                 dirbuf.d_off = offset + sizeof(struct direntry);
 1605                                 dirent_terminate(&dirbuf);
 1606                                 if (uio->uio_resid < dirbuf.d_reclen)
 1607                                         goto out;
 1608                                 error = uiomove(&dirbuf, dirbuf.d_reclen, uio);
 1609                                 if (error)
 1610                                         goto out;
 1611                                 offset += sizeof(struct direntry);
 1612                                 off = offset;
 1613                                 if (cookies) {
 1614                                         *cookies++ = offset;
 1615                                         if (--ncookies <= 0)
 1616                                                 goto out;
 1617                                 }
 1618                         }
 1619                 }
 1620         }
 1621 
 1622         mbnambuf_init(&nb);
 1623         off = offset;
 1624         while (uio->uio_resid > 0) {
 1625                 lbn = de_cluster(pmp, offset - bias);
 1626                 on = (offset - bias) & pmp->pm_crbomask;
 1627                 n = min(pmp->pm_bpcluster - on, uio->uio_resid);
 1628                 diff = dep->de_FileSize - (offset - bias);
 1629                 if (diff <= 0)
 1630                         break;
 1631                 n = min(n, diff);
 1632                 error = pcbmap(dep, lbn, &bn, &cn, &blsize);
 1633                 if (error)
 1634                         break;
 1635                 error = bread(pmp->pm_devvp, bn, blsize, NOCRED, &bp);
 1636                 if (error) {
 1637                         return (error);
 1638                 }
 1639                 n = min(n, blsize - bp->b_resid);
 1640                 if (n == 0) {
 1641                         brelse(bp);
 1642                         return (EIO);
 1643                 }
 1644 
 1645                 /*
 1646                  * Convert from dos directory entries to fs-independent
 1647                  * directory entries.
 1648                  */
 1649                 for (dentp = (struct direntry *)(bp->b_data + on);
 1650                      (char *)dentp < bp->b_data + on + n;
 1651                      dentp++, offset += sizeof(struct direntry)) {
 1652 #if 0
 1653                         printf("rd: dentp %08x prev %08x crnt %08x deName %02x attr %02x\n",
 1654                             dentp, prev, crnt, dentp->deName[0], dentp->deAttributes);
 1655 #endif
 1656                         /*
 1657                          * If this is an unused entry, we can stop.
 1658                          */
 1659                         if (dentp->deName[0] == SLOT_EMPTY) {
 1660                                 brelse(bp);
 1661                                 goto out;
 1662                         }
 1663                         /*
 1664                          * Skip deleted entries.
 1665                          */
 1666                         if (dentp->deName[0] == SLOT_DELETED) {
 1667                                 chksum = -1;
 1668                                 mbnambuf_init(&nb);
 1669                                 continue;
 1670                         }
 1671 
 1672                         /*
 1673                          * Handle Win95 long directory entries
 1674                          */
 1675                         if (dentp->deAttributes == ATTR_WIN95) {
 1676                                 if (pmp->pm_flags & MSDOSFSMNT_SHORTNAME)
 1677                                         continue;
 1678                                 chksum = win2unixfn(&nb,
 1679                                     (struct winentry *)dentp, chksum, pmp);
 1680                                 continue;
 1681                         }
 1682 
 1683                         /*
 1684                          * Skip volume labels
 1685                          */
 1686                         if (dentp->deAttributes & ATTR_VOLUME) {
 1687                                 chksum = -1;
 1688                                 mbnambuf_init(&nb);
 1689                                 continue;
 1690                         }
 1691                         /*
 1692                          * This computation of d_fileno must match
 1693                          * the computation of va_fileid in
 1694                          * msdosfs_getattr.
 1695                          */
 1696                         if (dentp->deAttributes & ATTR_DIRECTORY) {
 1697                                 cn = getushort(dentp->deStartCluster);
 1698                                 if (FAT32(pmp)) {
 1699                                         cn |= getushort(dentp->deHighClust) <<
 1700                                             16;
 1701                                         if (cn == MSDOSFSROOT)
 1702                                                 cn = pmp->pm_rootdirblk;
 1703                                 }
 1704                                 if (cn == MSDOSFSROOT && !FAT32(pmp))
 1705                                         dirbuf.d_fileno = 1;
 1706                                 else
 1707                                         dirbuf.d_fileno = cntobn(pmp, cn) *
 1708                                             dirsperblk;
 1709                                 dirbuf.d_type = DT_DIR;
 1710                         } else {
 1711                                 dirbuf.d_fileno = (uoff_t)offset /
 1712                                     sizeof(struct direntry);
 1713                                 dirbuf.d_type = DT_REG;
 1714                         }
 1715 
 1716                         if (chksum != winChksum(dentp->deName)) {
 1717                                 dirbuf.d_namlen = dos2unixfn(dentp->deName,
 1718                                     (u_char *)dirbuf.d_name,
 1719                                     dentp->deLowerCase |
 1720                                         ((pmp->pm_flags & MSDOSFSMNT_SHORTNAME) ?
 1721                                         (LCASE_BASE | LCASE_EXT) : 0),
 1722                                     pmp);
 1723                                 mbnambuf_init(&nb);
 1724                         } else
 1725                                 mbnambuf_flush(&nb, &dirbuf);
 1726                         chksum = -1;
 1727                         dirbuf.d_reclen = GENERIC_DIRSIZ(&dirbuf);
 1728                         /* NOTE: d_off is the offset of the *next* entry. */
 1729                         dirbuf.d_off = offset + sizeof(struct direntry);
 1730                         dirent_terminate(&dirbuf);
 1731                         if (uio->uio_resid < dirbuf.d_reclen) {
 1732                                 brelse(bp);
 1733                                 goto out;
 1734                         }
 1735                         error = uiomove(&dirbuf, dirbuf.d_reclen, uio);
 1736                         if (error) {
 1737                                 brelse(bp);
 1738                                 goto out;
 1739                         }
 1740                         if (cookies) {
 1741                                 *cookies++ = offset + sizeof(struct direntry);
 1742                                 if (--ncookies <= 0) {
 1743                                         brelse(bp);
 1744                                         goto out;
 1745                                 }
 1746                         }
 1747                         off = offset + sizeof(struct direntry);
 1748                 }
 1749                 brelse(bp);
 1750         }
 1751 out:
 1752         /* Subtract unused cookies */
 1753         if (ap->a_ncookies)
 1754                 *ap->a_ncookies -= ncookies;
 1755 
 1756         uio->uio_offset = off;
 1757 
 1758         /*
 1759          * Set the eofflag (NFS uses it)
 1760          */
 1761         if (ap->a_eofflag) {
 1762                 if (dep->de_FileSize - (offset - bias) <= 0)
 1763                         *ap->a_eofflag = 1;
 1764                 else
 1765                         *ap->a_eofflag = 0;
 1766         }
 1767         return (error);
 1768 }
 1769 
 1770 /*-
 1771  * a_vp   - pointer to the file's vnode
 1772  * a_bn   - logical block number within the file (cluster number for us)
 1773  * a_bop  - where to return the bufobj of the special file containing the fs
 1774  * a_bnp  - where to return the "physical" block number corresponding to a_bn
 1775  *          (relative to the special file; units are blocks of size DEV_BSIZE)
 1776  * a_runp - where to return the "run past" a_bn.  This is the count of logical
 1777  *          blocks whose physical blocks (together with a_bn's physical block)
 1778  *          are contiguous.
 1779  * a_runb - where to return the "run before" a_bn.
 1780  */
 1781 static int
 1782 msdosfs_bmap(struct vop_bmap_args *ap)
 1783 {
 1784         struct fatcache savefc;
 1785         struct denode *dep;
 1786         struct mount *mp;
 1787         struct msdosfsmount *pmp;
 1788         struct vnode *vp;
 1789         daddr_t runbn;
 1790         u_long cn;
 1791         int bnpercn, error, maxio, maxrun, run;
 1792 
 1793         vp = ap->a_vp;
 1794         dep = VTODE(vp);
 1795         pmp = dep->de_pmp;
 1796         if (ap->a_bop != NULL)
 1797                 *ap->a_bop = &pmp->pm_devvp->v_bufobj;
 1798         if (ap->a_bnp == NULL)
 1799                 return (0);
 1800         if (ap->a_runp != NULL)
 1801                 *ap->a_runp = 0;
 1802         if (ap->a_runb != NULL)
 1803                 *ap->a_runb = 0;
 1804         cn = ap->a_bn;
 1805         if (cn != ap->a_bn)
 1806                 return (EFBIG);
 1807         error = pcbmap(dep, cn, ap->a_bnp, NULL, NULL);
 1808         if (error != 0 || (ap->a_runp == NULL && ap->a_runb == NULL))
 1809                 return (error);
 1810 
 1811         /*
 1812          * Prepare to back out updates of the fatchain cache after the one
 1813          * for the first block done by pcbmap() above.  Without the backout,
 1814          * then whenever the caller doesn't do i/o to all of the blocks that
 1815          * we find, the single useful cache entry would be too far in advance
 1816          * of the actual i/o to work for the next sequential i/o.  Then the
 1817          * FAT would be searched from the beginning.  With the backout, the
 1818          * FAT is searched starting at most a few blocks early.  This wastes
 1819          * much less time.  Time is also wasted finding more blocks than the
 1820          * caller will do i/o to.  This is necessary because the runlength
 1821          * parameters are output-only.
 1822          */
 1823         savefc = dep->de_fc[FC_LASTMAP];
 1824 
 1825         mp = vp->v_mount;
 1826         maxio = mp->mnt_iosize_max / mp->mnt_stat.f_iosize;
 1827         bnpercn = de_cn2bn(pmp, 1);
 1828         if (ap->a_runp != NULL) {
 1829                 maxrun = ulmin(maxio - 1, pmp->pm_maxcluster - cn);
 1830                 for (run = 1; run <= maxrun; run++) {
 1831                         if (pcbmap(dep, cn + run, &runbn, NULL, NULL) != 0 ||
 1832                             runbn != *ap->a_bnp + run * bnpercn)
 1833                                 break;
 1834                 }
 1835                 *ap->a_runp = run - 1;
 1836         }
 1837         if (ap->a_runb != NULL) {
 1838                 maxrun = ulmin(maxio - 1, cn);
 1839                 for (run = 1; run < maxrun; run++) {
 1840                         if (pcbmap(dep, cn - run, &runbn, NULL, NULL) != 0 ||
 1841                             runbn != *ap->a_bnp - run * bnpercn)
 1842                                 break;
 1843                 }
 1844                 *ap->a_runb = run - 1;
 1845         }
 1846         dep->de_fc[FC_LASTMAP] = savefc;
 1847         return (0);
 1848 }
 1849 
 1850 SYSCTL_NODE(_vfs, OID_AUTO, msdosfs, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
 1851     "msdos filesystem");
 1852 static int use_buf_pager = 1;
 1853 SYSCTL_INT(_vfs_msdosfs, OID_AUTO, use_buf_pager, CTLFLAG_RWTUN,
 1854     &use_buf_pager, 0,
 1855     "Use buffer pager instead of bmap");
 1856 
 1857 static daddr_t
 1858 msdosfs_gbp_getblkno(struct vnode *vp, vm_ooffset_t off)
 1859 {
 1860 
 1861         return (de_cluster(VTODE(vp)->de_pmp, off));
 1862 }
 1863 
 1864 static int
 1865 msdosfs_gbp_getblksz(struct vnode *vp, daddr_t lbn, long *sz)
 1866 {
 1867 
 1868         *sz = VTODE(vp)->de_pmp->pm_bpcluster;
 1869         return (0);
 1870 }
 1871 
 1872 static int
 1873 msdosfs_getpages(struct vop_getpages_args *ap)
 1874 {
 1875 
 1876         if (use_buf_pager)
 1877                 return (vfs_bio_getpages(ap->a_vp, ap->a_m, ap->a_count,
 1878                     ap->a_rbehind, ap->a_rahead, msdosfs_gbp_getblkno,
 1879                     msdosfs_gbp_getblksz));
 1880         return (vnode_pager_generic_getpages(ap->a_vp, ap->a_m, ap->a_count,
 1881             ap->a_rbehind, ap->a_rahead, NULL, NULL));
 1882 }
 1883 
 1884 static int
 1885 msdosfs_strategy(struct vop_strategy_args *ap)
 1886 {
 1887         struct buf *bp = ap->a_bp;
 1888         struct denode *dep = VTODE(ap->a_vp);
 1889         struct bufobj *bo;
 1890         int error = 0;
 1891         daddr_t blkno;
 1892 
 1893         /*
 1894          * If we don't already know the filesystem relative block number
 1895          * then get it using pcbmap().  If pcbmap() returns the block
 1896          * number as -1 then we've got a hole in the file.  DOS filesystems
 1897          * don't allow files with holes, so we shouldn't ever see this.
 1898          */
 1899         if (bp->b_blkno == bp->b_lblkno) {
 1900                 error = pcbmap(dep, bp->b_lblkno, &blkno, 0, 0);
 1901                 bp->b_blkno = blkno;
 1902                 if (error) {
 1903                         bp->b_error = error;
 1904                         bp->b_ioflags |= BIO_ERROR;
 1905                         bufdone(bp);
 1906                         return (0);
 1907                 }
 1908                 if ((long)bp->b_blkno == -1)
 1909                         vfs_bio_clrbuf(bp);
 1910         }
 1911         if (bp->b_blkno == -1) {
 1912                 bufdone(bp);
 1913                 return (0);
 1914         }
 1915         /*
 1916          * Read/write the block from/to the disk that contains the desired
 1917          * file block.
 1918          */
 1919         bp->b_iooffset = dbtob(bp->b_blkno);
 1920         bo = dep->de_pmp->pm_bo;
 1921         BO_STRATEGY(bo, bp);
 1922         return (0);
 1923 }
 1924 
 1925 static int
 1926 msdosfs_print(struct vop_print_args *ap)
 1927 {
 1928         struct denode *dep = VTODE(ap->a_vp);
 1929 
 1930         printf("\tstartcluster %lu, dircluster %lu, diroffset %lu, ",
 1931                dep->de_StartCluster, dep->de_dirclust, dep->de_diroffset);
 1932         printf("on dev %s\n", devtoname(dep->de_pmp->pm_dev));
 1933         return (0);
 1934 }
 1935 
 1936 static int
 1937 msdosfs_pathconf(struct vop_pathconf_args *ap)
 1938 {
 1939         struct msdosfsmount *pmp = VTODE(ap->a_vp)->de_pmp;
 1940 
 1941         switch (ap->a_name) {
 1942         case _PC_FILESIZEBITS:
 1943                 *ap->a_retval = 32;
 1944                 return (0);
 1945         case _PC_LINK_MAX:
 1946                 *ap->a_retval = 1;
 1947                 return (0);
 1948         case _PC_NAME_MAX:
 1949                 *ap->a_retval = pmp->pm_flags & MSDOSFSMNT_LONGNAME ? WIN_MAXLEN : 12;
 1950                 return (0);
 1951         case _PC_CHOWN_RESTRICTED:
 1952                 *ap->a_retval = 1;
 1953                 return (0);
 1954         case _PC_NO_TRUNC:
 1955                 *ap->a_retval = 0;
 1956                 return (0);
 1957         default:
 1958                 return (vop_stdpathconf(ap));
 1959         }
 1960         /* NOTREACHED */
 1961 }
 1962 
 1963 static int
 1964 msdosfs_vptofh(struct vop_vptofh_args *ap)
 1965 {
 1966         struct denode *dep;
 1967         struct defid *defhp;
 1968 
 1969         dep = VTODE(ap->a_vp);
 1970         defhp = (struct defid *)ap->a_fhp;
 1971         defhp->defid_len = sizeof(struct defid);
 1972         defhp->defid_dirclust = dep->de_dirclust;
 1973         defhp->defid_dirofs = dep->de_diroffset;
 1974         /* defhp->defid_gen = dep->de_gen; */
 1975         return (0);
 1976 }
 1977 
 1978 /* Global vfs data structures for msdosfs */
 1979 struct vop_vector msdosfs_vnodeops = {
 1980         .vop_default =          &default_vnodeops,
 1981 
 1982         .vop_access =           msdosfs_access,
 1983         .vop_bmap =             msdosfs_bmap,
 1984         .vop_getpages =         msdosfs_getpages,
 1985         .vop_cachedlookup =     msdosfs_lookup,
 1986         .vop_open =             msdosfs_open,
 1987         .vop_close =            msdosfs_close,
 1988         .vop_create =           msdosfs_create,
 1989         .vop_fsync =            msdosfs_fsync,
 1990         .vop_fdatasync =        vop_stdfdatasync_buf,
 1991         .vop_getattr =          msdosfs_getattr,
 1992         .vop_inactive =         msdosfs_inactive,
 1993         .vop_link =             msdosfs_link,
 1994         .vop_lookup =           vfs_cache_lookup,
 1995         .vop_mkdir =            msdosfs_mkdir,
 1996         .vop_mknod =            msdosfs_mknod,
 1997         .vop_pathconf =         msdosfs_pathconf,
 1998         .vop_print =            msdosfs_print,
 1999         .vop_read =             msdosfs_read,
 2000         .vop_readdir =          msdosfs_readdir,
 2001         .vop_reclaim =          msdosfs_reclaim,
 2002         .vop_remove =           msdosfs_remove,
 2003         .vop_rename =           msdosfs_rename,
 2004         .vop_rmdir =            msdosfs_rmdir,
 2005         .vop_setattr =          msdosfs_setattr,
 2006         .vop_strategy =         msdosfs_strategy,
 2007         .vop_symlink =          msdosfs_symlink,
 2008         .vop_write =            msdosfs_write,
 2009         .vop_vptofh =           msdosfs_vptofh,
 2010 };
 2011 VFS_VOP_VECTOR_REGISTER(msdosfs_vnodeops);

Cache object: 38778ae7295f1a0cfe632a2a02bebbee


[ 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.