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_vfsops.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 /*      $NetBSD: msdosfs_vfsops.c,v 1.40.2.1 2007/02/27 23:11:36 riz Exp $      */
    2 
    3 /*-
    4  * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank.
    5  * Copyright (C) 1994, 1995, 1997 TooLs GmbH.
    6  * All rights reserved.
    7  * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below).
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  * 3. All advertising materials mentioning features or use of this software
   18  *    must display the following acknowledgement:
   19  *      This product includes software developed by TooLs GmbH.
   20  * 4. The name of TooLs GmbH may not be used to endorse or promote products
   21  *    derived from this software without specific prior written permission.
   22  *
   23  * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR
   24  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   25  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   26  * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   27  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   28  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
   29  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   30  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
   31  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
   32  * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   33  */
   34 /*
   35  * Written by Paul Popelka (paulp@uts.amdahl.com)
   36  *
   37  * You can do anything you want with this software, just don't say you wrote
   38  * it, and don't remove this notice.
   39  *
   40  * This software is provided "as is".
   41  *
   42  * The author supplies this software to be publicly redistributed on the
   43  * understanding that the author is not responsible for the correct
   44  * functioning of this software in any circumstances and is not liable for
   45  * any damages caused by this software.
   46  *
   47  * October 1992
   48  */
   49 
   50 #include <sys/cdefs.h>
   51 __KERNEL_RCSID(0, "$NetBSD: msdosfs_vfsops.c,v 1.40.2.1 2007/02/27 23:11:36 riz Exp $");
   52 
   53 #if defined(_KERNEL_OPT)
   54 #include "opt_quota.h"
   55 #include "opt_compat_netbsd.h"
   56 #endif
   57 
   58 #include <sys/param.h>
   59 #include <sys/systm.h>
   60 #include <sys/sysctl.h>
   61 #include <sys/namei.h>
   62 #include <sys/proc.h>
   63 #include <sys/kernel.h>
   64 #include <sys/vnode.h>
   65 #include <miscfs/specfs/specdev.h> /* XXX */    /* defines v_rdev */
   66 #include <sys/mount.h>
   67 #include <sys/buf.h>
   68 #include <sys/file.h>
   69 #include <sys/device.h>
   70 #include <sys/disklabel.h>
   71 #include <sys/disk.h>
   72 #include <sys/ioctl.h>
   73 #include <sys/malloc.h>
   74 #include <sys/dirent.h>
   75 #include <sys/stat.h>
   76 #include <sys/conf.h>
   77 #include <sys/kauth.h>
   78 
   79 #include <fs/msdosfs/bpb.h>
   80 #include <fs/msdosfs/bootsect.h>
   81 #include <fs/msdosfs/direntry.h>
   82 #include <fs/msdosfs/denode.h>
   83 #include <fs/msdosfs/msdosfsmount.h>
   84 #include <fs/msdosfs/fat.h>
   85 
   86 #define MSDOSFS_NAMEMAX(pmp) \
   87         (pmp)->pm_flags & MSDOSFSMNT_LONGNAME ? WIN_MAXLEN : 12
   88 
   89 int msdosfs_mountroot(void);
   90 int msdosfs_mount(struct mount *, const char *, void *,
   91     struct nameidata *, struct lwp *);
   92 int msdosfs_start(struct mount *, int, struct lwp *);
   93 int msdosfs_unmount(struct mount *, int, struct lwp *);
   94 int msdosfs_root(struct mount *, struct vnode **);
   95 int msdosfs_quotactl(struct mount *, int, uid_t, void *, struct lwp *);
   96 int msdosfs_statvfs(struct mount *, struct statvfs *, struct lwp *);
   97 int msdosfs_sync(struct mount *, int, kauth_cred_t, struct lwp *);
   98 int msdosfs_vget(struct mount *, ino_t, struct vnode **);
   99 int msdosfs_fhtovp(struct mount *, struct fid *, struct vnode **);
  100 int msdosfs_vptofh(struct vnode *, struct fid *, size_t *fh_size);
  101 
  102 int msdosfs_mountfs(struct vnode *, struct mount *, struct lwp *,
  103     struct msdosfs_args *);
  104 
  105 static int update_mp(struct mount *, struct msdosfs_args *);
  106 
  107 MALLOC_DEFINE(M_MSDOSFSMNT, "MSDOSFS mount", "MSDOS FS mount structure");
  108 MALLOC_DEFINE(M_MSDOSFSFAT, "MSDOSFS fat", "MSDOS FS fat table");
  109 
  110 #define ROOTNAME "root_device"
  111 
  112 extern const struct vnodeopv_desc msdosfs_vnodeop_opv_desc;
  113 
  114 const struct vnodeopv_desc * const msdosfs_vnodeopv_descs[] = {
  115         &msdosfs_vnodeop_opv_desc,
  116         NULL,
  117 };
  118 
  119 struct vfsops msdosfs_vfsops = {
  120         MOUNT_MSDOS,
  121         msdosfs_mount,
  122         msdosfs_start,
  123         msdosfs_unmount,
  124         msdosfs_root,
  125         msdosfs_quotactl,
  126         msdosfs_statvfs,
  127         msdosfs_sync,
  128         msdosfs_vget,
  129         msdosfs_fhtovp,
  130         msdosfs_vptofh,
  131         msdosfs_init,
  132         msdosfs_reinit,
  133         msdosfs_done,
  134         msdosfs_mountroot,
  135         (int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp,
  136         vfs_stdextattrctl,
  137         msdosfs_vnodeopv_descs,
  138         0,
  139         { NULL, NULL },
  140 };
  141 VFS_ATTACH(msdosfs_vfsops);
  142 
  143 static int
  144 update_mp(mp, argp)
  145         struct mount *mp;
  146         struct msdosfs_args *argp;
  147 {
  148         struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
  149         int error;
  150 
  151         pmp->pm_gid = argp->gid;
  152         pmp->pm_uid = argp->uid;
  153         pmp->pm_mask = argp->mask & ALLPERMS;
  154         pmp->pm_dirmask = argp->dirmask & ALLPERMS;
  155         pmp->pm_gmtoff = argp->gmtoff;
  156         pmp->pm_flags |= argp->flags & MSDOSFSMNT_MNTOPT;
  157 
  158         /*
  159          * GEMDOS knows nothing (yet) about win95
  160          */
  161         if (pmp->pm_flags & MSDOSFSMNT_GEMDOSFS)
  162                 pmp->pm_flags |= MSDOSFSMNT_NOWIN95;
  163 
  164         if (pmp->pm_flags & MSDOSFSMNT_NOWIN95)
  165                 pmp->pm_flags |= MSDOSFSMNT_SHORTNAME;
  166         else if (!(pmp->pm_flags &
  167             (MSDOSFSMNT_SHORTNAME | MSDOSFSMNT_LONGNAME))) {
  168                 struct vnode *rtvp;
  169 
  170                 /*
  171                  * Try to divine whether to support Win'95 long filenames
  172                  */
  173                 if (FAT32(pmp))
  174                         pmp->pm_flags |= MSDOSFSMNT_LONGNAME;
  175                 else {
  176                         if ((error = msdosfs_root(mp, &rtvp)) != 0)
  177                                 return error;
  178                         pmp->pm_flags |= findwin95(VTODE(rtvp))
  179                                 ? MSDOSFSMNT_LONGNAME
  180                                         : MSDOSFSMNT_SHORTNAME;
  181                         vput(rtvp);
  182                 }
  183         }
  184 
  185         mp->mnt_stat.f_namemax = MSDOSFS_NAMEMAX(pmp);
  186 
  187         return 0;
  188 }
  189 
  190 int
  191 msdosfs_mountroot()
  192 {
  193         struct mount *mp;
  194         struct lwp *l = curlwp; /* XXX */
  195         int error;
  196         struct msdosfs_args args;
  197 
  198         if (device_class(root_device) != DV_DISK)
  199                 return (ENODEV);
  200 
  201         if ((error = vfs_rootmountalloc(MOUNT_MSDOS, "root_device", &mp))) {
  202                 vrele(rootvp);
  203                 return (error);
  204         }
  205 
  206         args.flags = MSDOSFSMNT_VERSIONED;
  207         args.uid = 0;
  208         args.gid = 0;
  209         args.mask = 0777;
  210         args.version = MSDOSFSMNT_VERSION;
  211         args.dirmask = 0777;
  212 
  213         if ((error = msdosfs_mountfs(rootvp, mp, l, &args)) != 0) {
  214                 mp->mnt_op->vfs_refcount--;
  215                 vfs_unbusy(mp);
  216                 free(mp, M_MOUNT);
  217                 return (error);
  218         }
  219 
  220         if ((error = update_mp(mp, &args)) != 0) {
  221                 (void)msdosfs_unmount(mp, 0, l);
  222                 vfs_unbusy(mp);
  223                 free(mp, M_MOUNT);
  224                 vrele(rootvp);
  225                 return (error);
  226         }
  227 
  228         simple_lock(&mountlist_slock);
  229         CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
  230         simple_unlock(&mountlist_slock);
  231         (void)msdosfs_statvfs(mp, &mp->mnt_stat, l);
  232         vfs_unbusy(mp);
  233         return (0);
  234 }
  235 
  236 /*
  237  * mp - path - addr in user space of mount point (ie /usr or whatever)
  238  * data - addr in user space of mount params including the name of the block
  239  * special file to treat as a filesystem.
  240  */
  241 int
  242 msdosfs_mount(mp, path, data, ndp, l)
  243         struct mount *mp;
  244         const char *path;
  245         void *data;
  246         struct nameidata *ndp;
  247         struct lwp *l;
  248 {
  249         struct vnode *devvp;      /* vnode for blk device to mount */
  250         struct msdosfs_args args; /* will hold data from mount request */
  251         /* msdosfs specific mount control block */
  252         struct msdosfsmount *pmp = NULL;
  253         int error, flags;
  254         mode_t accessmode;
  255 
  256         if (mp->mnt_flag & MNT_GETARGS) {
  257                 pmp = VFSTOMSDOSFS(mp);
  258                 if (pmp == NULL)
  259                         return EIO;
  260                 args.fspec = NULL;
  261                 args.uid = pmp->pm_uid;
  262                 args.gid = pmp->pm_gid;
  263                 args.mask = pmp->pm_mask;
  264                 args.flags = pmp->pm_flags;
  265                 args.version = MSDOSFSMNT_VERSION;
  266                 args.dirmask = pmp->pm_dirmask;
  267                 args.gmtoff = pmp->pm_gmtoff;
  268                 return copyout(&args, data, sizeof(args));
  269         }
  270         error = copyin(data, &args, sizeof(struct msdosfs_args));
  271         if (error)
  272                 return (error);
  273 
  274         /*
  275          * If not versioned (i.e. using old mount_msdos(8)), fill in
  276          * the additional structure items with suitable defaults.
  277          */
  278         if ((args.flags & MSDOSFSMNT_VERSIONED) == 0) {
  279                 args.version = 1;
  280                 args.dirmask = args.mask;
  281         }
  282 
  283         /*
  284          * Reset GMT offset for pre-v3 mount structure args.
  285          */
  286         if (args.version < 3)
  287                 args.gmtoff = 0;
  288 
  289         /*
  290          * If updating, check whether changing from read-only to
  291          * read/write; if there is no device name, that's all we do.
  292          */
  293         if (mp->mnt_flag & MNT_UPDATE) {
  294                 pmp = VFSTOMSDOSFS(mp);
  295                 error = 0;
  296                 if (!(pmp->pm_flags & MSDOSFSMNT_RONLY) && (mp->mnt_flag & MNT_RDONLY)) {
  297                         flags = WRITECLOSE;
  298                         if (mp->mnt_flag & MNT_FORCE)
  299                                 flags |= FORCECLOSE;
  300                         error = vflush(mp, NULLVP, flags);
  301                 }
  302                 if (!error && (mp->mnt_flag & MNT_RELOAD))
  303                         /* not yet implemented */
  304                         error = EOPNOTSUPP;
  305                 if (error)
  306                         return (error);
  307                 if ((pmp->pm_flags & MSDOSFSMNT_RONLY) && (mp->mnt_iflag & IMNT_WANTRDWR)) {
  308                         /*
  309                          * If upgrade to read-write by non-root, then verify
  310                          * that user has necessary permissions on the device.
  311                          */
  312                         if (kauth_authorize_generic(l->l_cred,
  313                             KAUTH_GENERIC_ISSUSER, NULL) != 0) {
  314                                 devvp = pmp->pm_devvp;
  315                                 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
  316                                 error = VOP_ACCESS(devvp, VREAD | VWRITE,
  317                                                    l->l_cred, l);
  318                                 VOP_UNLOCK(devvp, 0);
  319                                 if (error)
  320                                         return (error);
  321                         }
  322                         pmp->pm_flags &= ~MSDOSFSMNT_RONLY;
  323                 }
  324                 if (args.fspec == NULL)
  325                         return EINVAL;
  326         }
  327         /*
  328          * Not an update, or updating the name: look up the name
  329          * and verify that it refers to a sensible block device.
  330          */
  331         NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, l);
  332         if ((error = namei(ndp)) != 0)
  333                 return (error);
  334         devvp = ndp->ni_vp;
  335 
  336         if (devvp->v_type != VBLK) {
  337                 vrele(devvp);
  338                 return (ENOTBLK);
  339         }
  340         if (bdevsw_lookup(devvp->v_rdev) == NULL) {
  341                 vrele(devvp);
  342                 return (ENXIO);
  343         }
  344         /*
  345          * If mount by non-root, then verify that user has necessary
  346          * permissions on the device.
  347          */
  348         if (kauth_authorize_generic(l->l_cred, KAUTH_GENERIC_ISSUSER, NULL) != 0) {
  349                 accessmode = VREAD;
  350                 if ((mp->mnt_flag & MNT_RDONLY) == 0)
  351                         accessmode |= VWRITE;
  352                 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
  353                 error = VOP_ACCESS(devvp, accessmode, l->l_cred, l);
  354                 VOP_UNLOCK(devvp, 0);
  355                 if (error) {
  356                         vrele(devvp);
  357                         return (error);
  358                 }
  359         }
  360         if ((mp->mnt_flag & MNT_UPDATE) == 0) {
  361                 int xflags;
  362 
  363                 /*
  364                  * Disallow multiple mounts of the same device.
  365                  * Disallow mounting of a device that is currently in use
  366                  * (except for root, which might share swap device for
  367                  * miniroot).
  368                  */
  369                 error = vfs_mountedon(devvp);
  370                 if (error)
  371                         goto fail;
  372                 if (vcount(devvp) > 1 && devvp != rootvp) {
  373                         error = EBUSY;
  374                         goto fail;
  375                 }
  376                 if (mp->mnt_flag & MNT_RDONLY)
  377                         xflags = FREAD;
  378                 else
  379                         xflags = FREAD|FWRITE;
  380                 error = VOP_OPEN(devvp, xflags, FSCRED, l);
  381                 if (error)
  382                         goto fail;
  383                 error = msdosfs_mountfs(devvp, mp, l, &args);
  384                 if (error) {
  385                         vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
  386                         (void) VOP_CLOSE(devvp, xflags, NOCRED, l);
  387                         VOP_UNLOCK(devvp, 0);
  388                         goto fail;
  389                 }
  390 #ifdef MSDOSFS_DEBUG            /* only needed for the printf below */
  391                 pmp = VFSTOMSDOSFS(mp);
  392 #endif
  393         } else {
  394                 vrele(devvp);
  395                 if (devvp != pmp->pm_devvp)
  396                         return (EINVAL);        /* needs translation */
  397         }
  398         if ((error = update_mp(mp, &args)) != 0) {
  399                 msdosfs_unmount(mp, MNT_FORCE, l);
  400                 return error;
  401         }
  402 
  403 #ifdef MSDOSFS_DEBUG
  404         printf("msdosfs_mount(): mp %p, pmp %p, inusemap %p\n", mp, pmp, pmp->pm_inusemap);
  405 #endif
  406         return set_statvfs_info(path, UIO_USERSPACE, args.fspec, UIO_USERSPACE,
  407             mp, l);
  408 
  409 fail:
  410         vrele(devvp);
  411         return (error);
  412 }
  413 
  414 int
  415 msdosfs_mountfs(devvp, mp, l, argp)
  416         struct vnode *devvp;
  417         struct mount *mp;
  418         struct lwp *l;
  419         struct msdosfs_args *argp;
  420 {
  421         struct msdosfsmount *pmp;
  422         struct buf *bp;
  423         dev_t dev = devvp->v_rdev;
  424         struct partinfo dpart;
  425         union bootsector *bsp;
  426         struct byte_bpb33 *b33;
  427         struct byte_bpb50 *b50;
  428         struct byte_bpb710 *b710;
  429         u_int8_t SecPerClust;
  430         int     ronly, error, tmp;
  431         int     bsize, dtype, fstype, secsize;
  432         u_int64_t psize;
  433 
  434         /* Flush out any old buffers remaining from a previous use. */
  435         if ((error = vinvalbuf(devvp, V_SAVE, l->l_cred, l, 0, 0)) != 0)
  436                 return (error);
  437 
  438         ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
  439 
  440         bp  = NULL; /* both used in error_exit */
  441         pmp = NULL;
  442 
  443         /*
  444          * We need the disklabel to calculate the size of a FAT entry
  445          * later on. Also make sure the partition contains a filesystem
  446          * of type FS_MSDOS. This doesn't work for floppies, so we have
  447          * to check for them too.
  448          *
  449          * There might still be parts of the msdos fs driver which assume
  450          * that the size of a disk block will always be 512 bytes.
  451          * Let's root them out...
  452          */
  453         error = VOP_IOCTL(devvp, DIOCGPART, &dpart, FREAD, NOCRED, l);
  454         if (error == 0) {
  455                 secsize = dpart.disklab->d_secsize;
  456                 dtype = dpart.disklab->d_type;
  457                 fstype = dpart.part->p_fstype;
  458                 psize = dpart.part->p_size;
  459         } else {
  460                 struct dkwedge_info dkw;
  461                 error = VOP_IOCTL(devvp, DIOCGWEDGEINFO, &dkw, FREAD,
  462                     NOCRED, l);
  463                 secsize = 512;  /* XXX */
  464                 dtype = DTYPE_FLOPPY; /* XXX */
  465                 fstype = FS_MSDOS;
  466                 psize = -1;
  467                 if (error) {
  468                         if (error != ENOTTY)
  469                                 goto error_exit;
  470                 } else {
  471                         fstype = strcmp(dkw.dkw_ptype, DKW_PTYPE_FAT) == 0 ?
  472                             FS_MSDOS : -1;
  473                         psize = dkw.dkw_size;
  474                 }
  475         }
  476         if (argp->flags & MSDOSFSMNT_GEMDOSFS) {
  477                 bsize = secsize;
  478                 if (bsize != 512 ||
  479                     (dtype != DTYPE_FLOPPY && fstype != FS_MSDOS)) {
  480                         error = EINVAL;
  481                         goto error_exit;
  482                 }
  483         } else
  484                 bsize = 0;
  485 
  486         /*
  487          * Read the boot sector of the filesystem, and then check the
  488          * boot signature.  If not a dos boot sector then error out.
  489          */
  490         if ((error = bread(devvp, 0, secsize, NOCRED, &bp)) != 0)
  491                 goto error_exit;
  492         bp->b_flags |= B_AGE;
  493         bsp = (union bootsector *)bp->b_data;
  494         b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB;
  495         b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB;
  496         b710 = (struct byte_bpb710 *)bsp->bs710.bsBPB;
  497 
  498         if (!(argp->flags & MSDOSFSMNT_GEMDOSFS)) {
  499                 if (bsp->bs50.bsBootSectSig0 != BOOTSIG0
  500                     || bsp->bs50.bsBootSectSig1 != BOOTSIG1) {
  501                         error = EINVAL;
  502                         goto error_exit;
  503                 }
  504         }
  505 
  506         pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK);
  507         memset(pmp, 0, sizeof *pmp);
  508         pmp->pm_mountp = mp;
  509 
  510         /*
  511          * Compute several useful quantities from the bpb in the
  512          * bootsector.  Copy in the dos 5 variant of the bpb then fix up
  513          * the fields that are different between dos 5 and dos 3.3.
  514          */
  515         SecPerClust = b50->bpbSecPerClust;
  516         pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec);
  517         pmp->pm_ResSectors = getushort(b50->bpbResSectors);
  518         pmp->pm_FATs = b50->bpbFATs;
  519         pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts);
  520         pmp->pm_Sectors = getushort(b50->bpbSectors);
  521         pmp->pm_FATsecs = getushort(b50->bpbFATsecs);
  522         pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack);
  523         pmp->pm_Heads = getushort(b50->bpbHeads);
  524         pmp->pm_Media = b50->bpbMedia;
  525 
  526         if (!(argp->flags & MSDOSFSMNT_GEMDOSFS)) {
  527                 /* XXX - We should probably check more values here */
  528                 if (!pmp->pm_BytesPerSec || !SecPerClust
  529                         || pmp->pm_Heads > 255 || pmp->pm_SecPerTrack > 63) {
  530                         error = EINVAL;
  531                         goto error_exit;
  532                 }
  533         }
  534 
  535         if (pmp->pm_Sectors == 0) {
  536                 pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs);
  537                 pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors);
  538         } else {
  539                 pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs);
  540                 pmp->pm_HugeSectors = pmp->pm_Sectors;
  541         }
  542 
  543         if (pmp->pm_RootDirEnts == 0) {
  544                 unsigned short vers = getushort(b710->bpbFSVers);
  545                 /*
  546                  * Some say that bsBootSectSig[23] must be zero, but
  547                  * Windows does not require this and some digital cameras
  548                  * do not set these to zero.  Therefore, do not insist.
  549                  */
  550                 if (pmp->pm_Sectors || pmp->pm_FATsecs || vers) {
  551                         error = EINVAL;
  552                         goto error_exit;
  553                 }
  554                 pmp->pm_fatmask = FAT32_MASK;
  555                 pmp->pm_fatmult = 4;
  556                 pmp->pm_fatdiv = 1;
  557                 pmp->pm_FATsecs = getulong(b710->bpbBigFATsecs);
  558 
  559                 /* mirrorring is enabled if the FATMIRROR bit is not set */
  560                 if ((getushort(b710->bpbExtFlags) & FATMIRROR) == 0)
  561                         pmp->pm_flags |= MSDOSFS_FATMIRROR;
  562                 else
  563                         pmp->pm_curfat = getushort(b710->bpbExtFlags) & FATNUM;
  564         } else
  565                 pmp->pm_flags |= MSDOSFS_FATMIRROR;
  566 
  567         if (argp->flags & MSDOSFSMNT_GEMDOSFS) {
  568                 if (FAT32(pmp)) {
  569                         /*
  570                          * GEMDOS doesn't know fat32.
  571                          */
  572                         error = EINVAL;
  573                         goto error_exit;
  574                 }
  575 
  576                 /*
  577                  * Check a few values (could do some more):
  578                  * - logical sector size: power of 2, >= block size
  579                  * - sectors per cluster: power of 2, >= 1
  580                  * - number of sectors:   >= 1, <= size of partition
  581                  */
  582                 if ( (SecPerClust == 0)
  583                   || (SecPerClust & (SecPerClust - 1))
  584                   || (pmp->pm_BytesPerSec < bsize)
  585                   || (pmp->pm_BytesPerSec & (pmp->pm_BytesPerSec - 1))
  586                   || (pmp->pm_HugeSectors == 0)
  587                   || (pmp->pm_HugeSectors * (pmp->pm_BytesPerSec / bsize)
  588                       > psize)) {
  589                         error = EINVAL;
  590                         goto error_exit;
  591                 }
  592                 /*
  593                  * XXX - Many parts of the msdos fs driver seem to assume that
  594                  * the number of bytes per logical sector (BytesPerSec) will
  595                  * always be the same as the number of bytes per disk block
  596                  * Let's pretend it is.
  597                  */
  598                 tmp = pmp->pm_BytesPerSec / bsize;
  599                 pmp->pm_BytesPerSec  = bsize;
  600                 pmp->pm_HugeSectors *= tmp;
  601                 pmp->pm_HiddenSects *= tmp;
  602                 pmp->pm_ResSectors  *= tmp;
  603                 pmp->pm_Sectors     *= tmp;
  604                 pmp->pm_FATsecs     *= tmp;
  605                 SecPerClust         *= tmp;
  606         }
  607         pmp->pm_fatblk = pmp->pm_ResSectors;
  608         if (FAT32(pmp)) {
  609                 pmp->pm_rootdirblk = getulong(b710->bpbRootClust);
  610                 pmp->pm_firstcluster = pmp->pm_fatblk
  611                         + (pmp->pm_FATs * pmp->pm_FATsecs);
  612                 pmp->pm_fsinfo = getushort(b710->bpbFSInfo);
  613         } else {
  614                 pmp->pm_rootdirblk = pmp->pm_fatblk +
  615                         (pmp->pm_FATs * pmp->pm_FATsecs);
  616                 pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry)
  617                                        + pmp->pm_BytesPerSec - 1)
  618                         / pmp->pm_BytesPerSec;/* in sectors */
  619                 pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize;
  620         }
  621 
  622         pmp->pm_nmbrofclusters = (pmp->pm_HugeSectors - pmp->pm_firstcluster) /
  623             SecPerClust;
  624         pmp->pm_maxcluster = pmp->pm_nmbrofclusters + 1;
  625         pmp->pm_fatsize = pmp->pm_FATsecs * pmp->pm_BytesPerSec;
  626 
  627         if (argp->flags & MSDOSFSMNT_GEMDOSFS) {
  628                 if (pmp->pm_nmbrofclusters <= (0xff0 - 2)
  629                       && (dtype == DTYPE_FLOPPY
  630                           || (dtype == DTYPE_VND
  631                                 && (pmp->pm_Heads == 1 || pmp->pm_Heads == 2)))
  632                     ) {
  633                         pmp->pm_fatmask = FAT12_MASK;
  634                         pmp->pm_fatmult = 3;
  635                         pmp->pm_fatdiv = 2;
  636                 } else {
  637                         pmp->pm_fatmask = FAT16_MASK;
  638                         pmp->pm_fatmult = 2;
  639                         pmp->pm_fatdiv = 1;
  640                 }
  641         } else if (pmp->pm_fatmask == 0) {
  642                 if (pmp->pm_maxcluster
  643                     <= ((CLUST_RSRVD - CLUST_FIRST) & FAT12_MASK)) {
  644                         /*
  645                          * This will usually be a floppy disk. This size makes
  646                          * sure that one fat entry will not be split across
  647                          * multiple blocks.
  648                          */
  649                         pmp->pm_fatmask = FAT12_MASK;
  650                         pmp->pm_fatmult = 3;
  651                         pmp->pm_fatdiv = 2;
  652                 } else {
  653                         pmp->pm_fatmask = FAT16_MASK;
  654                         pmp->pm_fatmult = 2;
  655                         pmp->pm_fatdiv = 1;
  656                 }
  657         }
  658         if (FAT12(pmp))
  659                 pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec;
  660         else
  661                 pmp->pm_fatblocksize = MAXBSIZE;
  662 
  663         pmp->pm_fatblocksec = pmp->pm_fatblocksize / pmp->pm_BytesPerSec;
  664         pmp->pm_bnshift = ffs(pmp->pm_BytesPerSec) - 1;
  665 
  666         /*
  667          * Compute mask and shift value for isolating cluster relative byte
  668          * offsets and cluster numbers from a file offset.
  669          */
  670         pmp->pm_bpcluster = SecPerClust * pmp->pm_BytesPerSec;
  671         pmp->pm_crbomask = pmp->pm_bpcluster - 1;
  672         pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1;
  673 
  674         /*
  675          * Check for valid cluster size
  676          * must be a power of 2
  677          */
  678         if (pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) {
  679                 error = EINVAL;
  680                 goto error_exit;
  681         }
  682 
  683         /*
  684          * Release the bootsector buffer.
  685          */
  686         brelse(bp);
  687         bp = NULL;
  688 
  689         /*
  690          * Check FSInfo.
  691          */
  692         if (pmp->pm_fsinfo) {
  693                 struct fsinfo *fp;
  694 
  695                 /*
  696                  * XXX  If the fsinfo block is stored on media with
  697                  *      2KB or larger sectors, is the fsinfo structure
  698                  *      padded at the end or in the middle?
  699                  */
  700                 if ((error = bread(devvp, de_bn2kb(pmp, pmp->pm_fsinfo),
  701                     pmp->pm_BytesPerSec, NOCRED, &bp)) != 0)
  702                         goto error_exit;
  703                 fp = (struct fsinfo *)bp->b_data;
  704                 if (!memcmp(fp->fsisig1, "RRaA", 4)
  705                     && !memcmp(fp->fsisig2, "rrAa", 4)
  706                     && !memcmp(fp->fsisig3, "\0\0\125\252", 4)
  707                     && !memcmp(fp->fsisig4, "\0\0\125\252", 4))
  708                         pmp->pm_nxtfree = getulong(fp->fsinxtfree);
  709                 else
  710                         pmp->pm_fsinfo = 0;
  711                 brelse(bp);
  712                 bp = NULL;
  713         }
  714 
  715         /*
  716          * Check and validate (or perhaps invalidate?) the fsinfo structure?
  717          * XXX
  718          */
  719         if (pmp->pm_fsinfo) {
  720                 if (pmp->pm_nxtfree == (u_long)-1)
  721                         pmp->pm_fsinfo = 0;
  722         }
  723 
  724         /*
  725          * Allocate memory for the bitmap of allocated clusters, and then
  726          * fill it in.
  727          */
  728         pmp->pm_inusemap = malloc(((pmp->pm_maxcluster + N_INUSEBITS - 1)
  729                                    / N_INUSEBITS)
  730                                   * sizeof(*pmp->pm_inusemap),
  731                                   M_MSDOSFSFAT, M_WAITOK);
  732 
  733         /*
  734          * fillinusemap() needs pm_devvp.
  735          */
  736         pmp->pm_dev = dev;
  737         pmp->pm_devvp = devvp;
  738 
  739         /*
  740          * Have the inuse map filled in.
  741          */
  742         if ((error = fillinusemap(pmp)) != 0)
  743                 goto error_exit;
  744 
  745         /*
  746          * If they want fat updates to be synchronous then let them suffer
  747          * the performance degradation in exchange for the on disk copy of
  748          * the fat being correct just about all the time.  I suppose this
  749          * would be a good thing to turn on if the kernel is still flakey.
  750          */
  751         if (mp->mnt_flag & MNT_SYNCHRONOUS)
  752                 pmp->pm_flags |= MSDOSFSMNT_WAITONFAT;
  753 
  754         /*
  755          * Finish up.
  756          */
  757         if (ronly)
  758                 pmp->pm_flags |= MSDOSFSMNT_RONLY;
  759         else
  760                 pmp->pm_fmod = 1;
  761         mp->mnt_data = pmp;
  762         mp->mnt_stat.f_fsidx.__fsid_val[0] = (long)dev;
  763         mp->mnt_stat.f_fsidx.__fsid_val[1] = makefstype(MOUNT_MSDOS);
  764         mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0];
  765         mp->mnt_stat.f_namemax = MSDOSFS_NAMEMAX(pmp);
  766         mp->mnt_flag |= MNT_LOCAL;
  767         mp->mnt_dev_bshift = pmp->pm_bnshift;
  768         mp->mnt_fs_bshift = pmp->pm_cnshift;
  769 
  770 #ifdef QUOTA
  771         /*
  772          * If we ever do quotas for DOS filesystems this would be a place
  773          * to fill in the info in the msdosfsmount structure. You dolt,
  774          * quotas on dos filesystems make no sense because files have no
  775          * owners on dos filesystems. of course there is some empty space
  776          * in the directory entry where we could put uid's and gid's.
  777          */
  778 #endif
  779         devvp->v_specmountpoint = mp;
  780 
  781         return (0);
  782 
  783 error_exit:;
  784         if (bp)
  785                 brelse(bp);
  786         if (pmp) {
  787                 if (pmp->pm_inusemap)
  788                         free(pmp->pm_inusemap, M_MSDOSFSFAT);
  789                 free(pmp, M_MSDOSFSMNT);
  790                 mp->mnt_data = NULL;
  791         }
  792         return (error);
  793 }
  794 
  795 int
  796 msdosfs_start(struct mount *mp, int flags,
  797     struct lwp *l)
  798 {
  799 
  800         return (0);
  801 }
  802 
  803 /*
  804  * Unmount the filesystem described by mp.
  805  */
  806 int
  807 msdosfs_unmount(mp, mntflags, l)
  808         struct mount *mp;
  809         int mntflags;
  810         struct lwp *l;
  811 {
  812         struct msdosfsmount *pmp;
  813         int error, flags;
  814 
  815         flags = 0;
  816         if (mntflags & MNT_FORCE)
  817                 flags |= FORCECLOSE;
  818 #ifdef QUOTA
  819 #endif
  820         if ((error = vflush(mp, NULLVP, flags)) != 0)
  821                 return (error);
  822         pmp = VFSTOMSDOSFS(mp);
  823         if (pmp->pm_devvp->v_type != VBAD)
  824                 pmp->pm_devvp->v_specmountpoint = NULL;
  825 #ifdef MSDOSFS_DEBUG
  826         {
  827                 struct vnode *vp = pmp->pm_devvp;
  828 
  829                 printf("msdosfs_umount(): just before calling VOP_CLOSE()\n");
  830                 printf("flag %08x, usecount %d, writecount %ld, holdcnt %ld\n",
  831                     vp->v_flag, vp->v_usecount, vp->v_writecount, vp->v_holdcnt);
  832                 printf("mount %p, op %p\n",
  833                     vp->v_mount, vp->v_op);
  834                 printf("freef %p, freeb %p, mount %p\n",
  835                     vp->v_freelist.tqe_next, vp->v_freelist.tqe_prev,
  836                     vp->v_mount);
  837                 printf("cleanblkhd %p, dirtyblkhd %p, numoutput %d, type %d\n",
  838                     vp->v_cleanblkhd.lh_first,
  839                     vp->v_dirtyblkhd.lh_first,
  840                     vp->v_numoutput, vp->v_type);
  841                 printf("union %p, tag %d, data[0] %08x, data[1] %08x\n",
  842                     vp->v_socket, vp->v_tag,
  843                     ((u_int *)vp->v_data)[0],
  844                     ((u_int *)vp->v_data)[1]);
  845         }
  846 #endif
  847         vn_lock(pmp->pm_devvp, LK_EXCLUSIVE | LK_RETRY);
  848         error = VOP_CLOSE(pmp->pm_devvp,
  849             pmp->pm_flags & MSDOSFSMNT_RONLY ? FREAD : FREAD|FWRITE, NOCRED, l);
  850         vput(pmp->pm_devvp);
  851         free(pmp->pm_inusemap, M_MSDOSFSFAT);
  852         free(pmp, M_MSDOSFSMNT);
  853         mp->mnt_data = NULL;
  854         mp->mnt_flag &= ~MNT_LOCAL;
  855         return (error);
  856 }
  857 
  858 int
  859 msdosfs_root(mp, vpp)
  860         struct mount *mp;
  861         struct vnode **vpp;
  862 {
  863         struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
  864         struct denode *ndep;
  865         int error;
  866 
  867 #ifdef MSDOSFS_DEBUG
  868         printf("msdosfs_root(); mp %p, pmp %p\n", mp, pmp);
  869 #endif
  870         if ((error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, &ndep)) != 0)
  871                 return (error);
  872         *vpp = DETOV(ndep);
  873         return (0);
  874 }
  875 
  876 int
  877 msdosfs_quotactl(struct mount *mp, int cmds,
  878     uid_t uid, void *arg, struct lwp *l)
  879 {
  880 
  881         return (EOPNOTSUPP);
  882 }
  883 
  884 int
  885 msdosfs_statvfs(struct mount *mp, struct statvfs *sbp, struct lwp *l)
  886 {
  887         struct msdosfsmount *pmp;
  888 
  889         pmp = VFSTOMSDOSFS(mp);
  890         sbp->f_bsize = pmp->pm_bpcluster;
  891         sbp->f_frsize = sbp->f_bsize;
  892         sbp->f_iosize = pmp->pm_bpcluster;
  893         sbp->f_blocks = pmp->pm_nmbrofclusters;
  894         sbp->f_bfree = pmp->pm_freeclustercount;
  895         sbp->f_bavail = pmp->pm_freeclustercount;
  896         sbp->f_bresvd = 0;
  897         sbp->f_files = pmp->pm_RootDirEnts;                     /* XXX */
  898         sbp->f_ffree = 0;       /* what to put in here? */
  899         sbp->f_favail = 0;      /* what to put in here? */
  900         sbp->f_fresvd = 0;
  901         copy_statvfs_info(sbp, mp);
  902         return (0);
  903 }
  904 
  905 int
  906 msdosfs_sync(mp, waitfor, cred, l)
  907         struct mount *mp;
  908         int waitfor;
  909         kauth_cred_t cred;
  910         struct lwp *l;
  911 {
  912         struct vnode *vp, *nvp;
  913         struct denode *dep;
  914         struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
  915         int error, allerror = 0;
  916 
  917         /*
  918          * If we ever switch to not updating all of the fats all the time,
  919          * this would be the place to update them from the first one.
  920          */
  921         if (pmp->pm_fmod != 0) {
  922                 if (pmp->pm_flags & MSDOSFSMNT_RONLY)
  923                         panic("msdosfs_sync: rofs mod");
  924                 else {
  925                         /* update fats here */
  926                 }
  927         }
  928         /*
  929          * Write back each (modified) denode.
  930          */
  931         simple_lock(&mntvnode_slock);
  932 loop:
  933         for (vp = TAILQ_FIRST(&mp->mnt_vnodelist); vp; vp = nvp) {
  934                 /*
  935                  * If the vnode that we are about to sync is no longer
  936                  * assoicated with this mount point, start over.
  937                  */
  938                 if (vp->v_mount != mp)
  939                         goto loop;
  940                 simple_lock(&vp->v_interlock);
  941                 nvp = TAILQ_NEXT(vp, v_mntvnodes);
  942                 dep = VTODE(vp);
  943                 if (waitfor == MNT_LAZY || vp->v_type == VNON ||
  944                     (((dep->de_flag &
  945                     (DE_ACCESS | DE_CREATE | DE_UPDATE | DE_MODIFIED)) == 0) &&
  946                      (LIST_EMPTY(&vp->v_dirtyblkhd) &&
  947                       vp->v_uobj.uo_npages == 0))) {
  948                         simple_unlock(&vp->v_interlock);
  949                         continue;
  950                 }
  951                 simple_unlock(&mntvnode_slock);
  952                 error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK);
  953                 if (error) {
  954                         simple_lock(&mntvnode_slock);
  955                         if (error == ENOENT)
  956                                 goto loop;
  957                         continue;
  958                 }
  959                 if ((error = VOP_FSYNC(vp, cred,
  960                     waitfor == MNT_WAIT ? FSYNC_WAIT : 0, 0, 0, l)) != 0)
  961                         allerror = error;
  962                 vput(vp);
  963                 simple_lock(&mntvnode_slock);
  964         }
  965         simple_unlock(&mntvnode_slock);
  966         /*
  967          * Force stale file system control information to be flushed.
  968          */
  969         if ((error = VOP_FSYNC(pmp->pm_devvp, cred,
  970             waitfor == MNT_WAIT ? FSYNC_WAIT : 0, 0, 0, l)) != 0)
  971                 allerror = error;
  972 #ifdef QUOTA
  973         /* qsync(mp); */
  974 #endif
  975         return (allerror);
  976 }
  977 
  978 int
  979 msdosfs_fhtovp(mp, fhp, vpp)
  980         struct mount *mp;
  981         struct fid *fhp;
  982         struct vnode **vpp;
  983 {
  984         struct msdosfsmount *pmp = VFSTOMSDOSFS(mp);
  985         struct defid defh;
  986         struct denode *dep;
  987         int error;
  988 
  989         if (fhp->fid_len != sizeof(struct defid))
  990                 return EINVAL;
  991 
  992         memcpy(&defh, fhp, sizeof(defh));
  993         error = deget(pmp, defh.defid_dirclust, defh.defid_dirofs, &dep);
  994         if (error) {
  995                 *vpp = NULLVP;
  996                 return (error);
  997         }
  998         *vpp = DETOV(dep);
  999         return (0);
 1000 }
 1001 
 1002 int
 1003 msdosfs_vptofh(vp, fhp, fh_size)
 1004         struct vnode *vp;
 1005         struct fid *fhp;
 1006         size_t *fh_size;
 1007 {
 1008         struct denode *dep;
 1009         struct defid defh;
 1010 
 1011         if (*fh_size < sizeof(struct defid)) {
 1012                 *fh_size = sizeof(struct defid);
 1013                 return E2BIG;
 1014         }
 1015         *fh_size = sizeof(struct defid);
 1016         dep = VTODE(vp);
 1017         memset(&defh, 0, sizeof(defh));
 1018         defh.defid_len = sizeof(struct defid);
 1019         defh.defid_dirclust = dep->de_dirclust;
 1020         defh.defid_dirofs = dep->de_diroffset;
 1021         /* defh.defid_gen = dep->de_gen; */
 1022         memcpy(fhp, &defh, sizeof(defh));
 1023         return (0);
 1024 }
 1025 
 1026 int
 1027 msdosfs_vget(struct mount *mp, ino_t ino,
 1028     struct vnode **vpp)
 1029 {
 1030 
 1031         return (EOPNOTSUPP);
 1032 }
 1033 
 1034 SYSCTL_SETUP(sysctl_vfs_msdosfs_setup, "sysctl vfs.msdosfs subtree setup")
 1035 {
 1036 
 1037         sysctl_createv(clog, 0, NULL, NULL,
 1038                        CTLFLAG_PERMANENT,
 1039                        CTLTYPE_NODE, "vfs", NULL,
 1040                        NULL, 0, NULL, 0,
 1041                        CTL_VFS, CTL_EOL);
 1042         sysctl_createv(clog, 0, NULL, NULL,
 1043                        CTLFLAG_PERMANENT,
 1044                        CTLTYPE_NODE, "msdosfs",
 1045                        SYSCTL_DESCR("MS-DOS file system"),
 1046                        NULL, 0, NULL, 0,
 1047                        CTL_VFS, 4, CTL_EOL);
 1048         /*
 1049          * XXX the "4" above could be dynamic, thereby eliminating one
 1050          * more instance of the "number to vfs" mapping problem, but
 1051          * "4" is the order as taken from sys/mount.h
 1052          */
 1053 }

Cache object: 1299ad3bd533a8e5e43a61a5adc8d36a


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