msdosfs_vfsops.c revision 33548
133548Sjkh/* $Id: msdosfs_vfsops.c,v 1.23 1997/11/12 05:42:19 julian Exp $ */ 233548Sjkh/* $NetBSD: msdosfs_vfsops.c,v 1.51 1997/11/17 15:36:58 ws Exp $ */ 32893Sdfr 42893Sdfr/*- 533548Sjkh * Copyright (C) 1994, 1995, 1997 Wolfgang Solfrank. 633548Sjkh * Copyright (C) 1994, 1995, 1997 TooLs GmbH. 72893Sdfr * All rights reserved. 82893Sdfr * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). 92893Sdfr * 102893Sdfr * Redistribution and use in source and binary forms, with or without 112893Sdfr * modification, are permitted provided that the following conditions 122893Sdfr * are met: 132893Sdfr * 1. Redistributions of source code must retain the above copyright 142893Sdfr * notice, this list of conditions and the following disclaimer. 152893Sdfr * 2. Redistributions in binary form must reproduce the above copyright 162893Sdfr * notice, this list of conditions and the following disclaimer in the 172893Sdfr * documentation and/or other materials provided with the distribution. 182893Sdfr * 3. All advertising materials mentioning features or use of this software 192893Sdfr * must display the following acknowledgement: 202893Sdfr * This product includes software developed by TooLs GmbH. 212893Sdfr * 4. The name of TooLs GmbH may not be used to endorse or promote products 222893Sdfr * derived from this software without specific prior written permission. 232893Sdfr * 242893Sdfr * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 252893Sdfr * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 262893Sdfr * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 272893Sdfr * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 282893Sdfr * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 292893Sdfr * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 302893Sdfr * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 312893Sdfr * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 322893Sdfr * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 332893Sdfr * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 342893Sdfr */ 352893Sdfr/* 362893Sdfr * Written by Paul Popelka (paulp@uts.amdahl.com) 378876Srgrimes * 382893Sdfr * You can do anything you want with this software, just don't say you wrote 392893Sdfr * it, and don't remove this notice. 408876Srgrimes * 412893Sdfr * This software is provided "as is". 428876Srgrimes * 432893Sdfr * The author supplies this software to be publicly redistributed on the 442893Sdfr * understanding that the author is not responsible for the correct 452893Sdfr * functioning of this software in any circumstances and is not liable for 462893Sdfr * any damages caused by this software. 478876Srgrimes * 482893Sdfr * October 1992 492893Sdfr */ 502893Sdfr 512893Sdfr#include <sys/param.h> 522893Sdfr#include <sys/systm.h> 532893Sdfr#include <sys/namei.h> 542893Sdfr#include <sys/proc.h> 552893Sdfr#include <sys/kernel.h> 562893Sdfr#include <sys/vnode.h> 572893Sdfr#include <miscfs/specfs/specdev.h> /* XXX */ /* defines v_rdev */ 582893Sdfr#include <sys/mount.h> 592893Sdfr#include <sys/buf.h> 6024131Sbde#include <sys/fcntl.h> 612893Sdfr#include <sys/malloc.h> 6233548Sjkh#include <sys/stat.h> /* defines ALLPERMS */ 632893Sdfr 642893Sdfr#include <msdosfs/bpb.h> 652893Sdfr#include <msdosfs/bootsect.h> 662893Sdfr#include <msdosfs/direntry.h> 672893Sdfr#include <msdosfs/denode.h> 682893Sdfr#include <msdosfs/msdosfsmount.h> 692893Sdfr#include <msdosfs/fat.h> 702893Sdfr 7130354SphkMALLOC_DEFINE(M_MSDOSFSMNT, "MSDOSFS mount", "MSDOSFS mount structure"); 7230354Sphkstatic MALLOC_DEFINE(M_MSDOSFSFAT, "MSDOSFS FAT", "MSDOSFS file allocation table"); 7330309Sphk 7433548Sjkhstatic int update_mp __P((struct mount *mp, struct msdosfs_args *argp)); 7512338Sbdestatic int mountmsdosfs __P((struct vnode *devvp, struct mount *mp, 7633548Sjkh struct proc *p, struct msdosfs_args *argp)); 7712338Sbdestatic int msdosfs_fhtovp __P((struct mount *, struct fid *, 7828270Swollman struct sockaddr *, struct vnode **, int *, 7912338Sbde struct ucred **)); 8012338Sbdestatic int msdosfs_mount __P((struct mount *, char *, caddr_t, 8112338Sbde struct nameidata *, struct proc *)); 8212338Sbdestatic int msdosfs_quotactl __P((struct mount *, int, uid_t, caddr_t, 8312338Sbde struct proc *)); 8412338Sbdestatic int msdosfs_root __P((struct mount *, struct vnode **)); 8512338Sbdestatic int msdosfs_start __P((struct mount *, int, struct proc *)); 8612338Sbdestatic int msdosfs_statfs __P((struct mount *, struct statfs *, 8712338Sbde struct proc *)); 8812338Sbdestatic int msdosfs_sync __P((struct mount *, int, struct ucred *, 8912338Sbde struct proc *)); 9012338Sbdestatic int msdosfs_unmount __P((struct mount *, int, struct proc *)); 9112338Sbdestatic int msdosfs_vget __P((struct mount *mp, ino_t ino, 9212338Sbde struct vnode **vpp)); 9312338Sbdestatic int msdosfs_vptofh __P((struct vnode *, struct fid *)); 9412338Sbde 9533548Sjkhstatic int 9633548Sjkhupdate_mp(mp, argp) 9733548Sjkh struct mount *mp; 9833548Sjkh struct msdosfs_args *argp; 9933548Sjkh{ 10033548Sjkh struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 10133548Sjkh int error; 10233548Sjkh 10333548Sjkh pmp->pm_gid = argp->gid; 10433548Sjkh pmp->pm_uid = argp->uid; 10533548Sjkh pmp->pm_mask = argp->mask & ALLPERMS; 10633548Sjkh pmp->pm_flags |= argp->flags & MSDOSFSMNT_MNTOPT; 10733548Sjkh 10833548Sjkh#ifndef __FreeBSD__ 10933548Sjkh /* 11033548Sjkh * GEMDOS knows nothing (yet) about win95 11133548Sjkh */ 11233548Sjkh if (pmp->pm_flags & MSDOSFSMNT_GEMDOSFS) 11333548Sjkh pmp->pm_flags |= MSDOSFSMNT_NOWIN95; 11433548Sjkh#endif 11533548Sjkh 11633548Sjkh if (pmp->pm_flags & MSDOSFSMNT_NOWIN95) 11733548Sjkh pmp->pm_flags |= MSDOSFSMNT_SHORTNAME; 11833548Sjkh else if (!(pmp->pm_flags & 11933548Sjkh (MSDOSFSMNT_SHORTNAME | MSDOSFSMNT_LONGNAME))) { 12033548Sjkh struct vnode *rootvp; 12133548Sjkh 12233548Sjkh /* 12333548Sjkh * Try to divine whether to support Win'95 long filenames 12433548Sjkh */ 12533548Sjkh if (FAT32(pmp)) 12633548Sjkh pmp->pm_flags |= MSDOSFSMNT_LONGNAME; 12733548Sjkh else { 12833548Sjkh if ((error = msdosfs_root(mp, &rootvp)) != 0) 12933548Sjkh return error; 13033548Sjkh pmp->pm_flags |= findwin95(VTODE(rootvp)) 13133548Sjkh ? MSDOSFSMNT_LONGNAME 13233548Sjkh : MSDOSFSMNT_SHORTNAME; 13333548Sjkh vput(rootvp); 13433548Sjkh } 13533548Sjkh } 13633548Sjkh return 0; 13733548Sjkh} 13833548Sjkh 13933548Sjkh#ifndef __FreeBSD__ 14033548Sjkhint 14133548Sjkhmsdosfs_mountroot() 14233548Sjkh{ 14333548Sjkh register struct mount *mp; 14433548Sjkh struct proc *p = curproc; /* XXX */ 14533548Sjkh size_t size; 14633548Sjkh int error; 14733548Sjkh struct msdosfs_args args; 14833548Sjkh 14933548Sjkh if (root_device->dv_class != DV_DISK) 15033548Sjkh return (ENODEV); 15133548Sjkh 15233548Sjkh /* 15333548Sjkh * Get vnodes for swapdev and rootdev. 15433548Sjkh */ 15533548Sjkh if (bdevvp(rootdev, &rootvp)) 15633548Sjkh panic("msdosfs_mountroot: can't setup rootvp"); 15733548Sjkh 15833548Sjkh mp = malloc((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK); 15933548Sjkh bzero((char *)mp, (u_long)sizeof(struct mount)); 16033548Sjkh mp->mnt_op = &msdosfs_vfsops; 16133548Sjkh mp->mnt_flag = 0; 16233548Sjkh LIST_INIT(&mp->mnt_vnodelist); 16333548Sjkh 16433548Sjkh args.flags = 0; 16533548Sjkh args.uid = 0; 16633548Sjkh args.gid = 0; 16733548Sjkh args.mask = 0777; 16833548Sjkh 16933548Sjkh if ((error = mountmsdosfs(rootvp, mp, p, &args)) != 0) { 17033548Sjkh free(mp, M_MOUNT); 17133548Sjkh return (error); 17233548Sjkh } 17333548Sjkh 17433548Sjkh if ((error = update_mp(mp, &args)) != 0) { 17533548Sjkh (void)msdosfs_unmount(mp, 0, p); 17633548Sjkh free(mp, M_MOUNT); 17733548Sjkh return (error); 17833548Sjkh } 17933548Sjkh 18033548Sjkh if ((error = vfs_lock(mp)) != 0) { 18133548Sjkh (void)msdosfs_unmount(mp, 0, p); 18233548Sjkh free(mp, M_MOUNT); 18333548Sjkh return (error); 18433548Sjkh } 18533548Sjkh 18633548Sjkh CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); 18733548Sjkh mp->mnt_vnodecovered = NULLVP; 18833548Sjkh (void) copystr("/", mp->mnt_stat.f_mntonname, MNAMELEN - 1, 18933548Sjkh &size); 19033548Sjkh bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); 19133548Sjkh (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 19233548Sjkh &size); 19333548Sjkh bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 19433548Sjkh (void)msdosfs_statfs(mp, &mp->mnt_stat, p); 19533548Sjkh vfs_unlock(mp); 19633548Sjkh return (0); 19733548Sjkh} 19833548Sjkh#endif 19933548Sjkh 2002893Sdfr/* 2018876Srgrimes * mp - path - addr in user space of mount point (ie /usr or whatever) 2022893Sdfr * data - addr in user space of mount params including the name of the block 2038876Srgrimes * special file to treat as a filesystem. 2042893Sdfr */ 20512144Sphkstatic int 2062893Sdfrmsdosfs_mount(mp, path, data, ndp, p) 2072893Sdfr struct mount *mp; 2082893Sdfr char *path; 2092893Sdfr caddr_t data; 2102893Sdfr struct nameidata *ndp; 2112893Sdfr struct proc *p; 2122893Sdfr{ 2132893Sdfr struct vnode *devvp; /* vnode for blk device to mount */ 2142893Sdfr struct msdosfs_args args; /* will hold data from mount request */ 21533548Sjkh /* msdosfs specific mount control block */ 21633548Sjkh struct msdosfsmount *pmp = NULL; 21733548Sjkh size_t size; 2182893Sdfr int error, flags; 21933548Sjkh mode_t accessmode; 2202893Sdfr 22133548Sjkh error = copyin(data, (caddr_t)&args, sizeof(struct msdosfs_args)); 2223152Sphk if (error) 22333548Sjkh return (error); 22433548Sjkh if (args.magic != MSDOSFS_ARGSMAGIC) { 22533548Sjkh printf("Old mount_msdosfs, flags=%d\n", args.flags); 22633548Sjkh args.flags = 0; 22733548Sjkh } 2282893Sdfr /* 22933548Sjkh * If updating, check whether changing from read-only to 23033548Sjkh * read/write; if there is no device name, that's all we do. 2312893Sdfr */ 2322893Sdfr if (mp->mnt_flag & MNT_UPDATE) { 23333548Sjkh pmp = VFSTOMSDOSFS(mp); 2342893Sdfr error = 0; 23533548Sjkh if (!(pmp->pm_flags & MSDOSFSMNT_RONLY) && (mp->mnt_flag & MNT_RDONLY)) { 2362893Sdfr flags = WRITECLOSE; 2372893Sdfr if (mp->mnt_flag & MNT_FORCE) 2382893Sdfr flags |= FORCECLOSE; 2392893Sdfr error = vflush(mp, NULLVP, flags); 2402893Sdfr } 2412893Sdfr if (!error && (mp->mnt_flag & MNT_RELOAD)) 2422893Sdfr /* not yet implemented */ 24333548Sjkh error = EOPNOTSUPP; 2442893Sdfr if (error) 24533548Sjkh return (error); 24633548Sjkh if ((pmp->pm_flags & MSDOSFSMNT_RONLY) && (mp->mnt_kern_flag & MNTK_WANTRDWR)) { 24733548Sjkh /* 24833548Sjkh * If upgrade to read-write by non-root, then verify 24933548Sjkh * that user has necessary permissions on the device. 25033548Sjkh */ 25133548Sjkh if (p->p_ucred->cr_uid != 0) { 25233548Sjkh devvp = pmp->pm_devvp; 25333548Sjkh vn_lock(devvp, LK_EXCLUSIVE, p); 25433548Sjkh error = VOP_ACCESS(devvp, VREAD | VWRITE, 25533548Sjkh p->p_ucred, p); 25633548Sjkh if (error) { 25733548Sjkh VOP_UNLOCK(devvp, 0, p); 25833548Sjkh return (error); 25933548Sjkh } 26033548Sjkh VOP_UNLOCK(devvp, 0, p); 26133548Sjkh } 26233548Sjkh pmp->pm_flags &= ~MSDOSFSMNT_RONLY; 26333548Sjkh } 2642893Sdfr if (args.fspec == 0) { 26533548Sjkh#ifdef __notyet__ /* doesn't work correctly with current mountd XXX */ 26633548Sjkh if (args.flags & MSDOSFSMNT_MNTOPT) { 26733548Sjkh pmp->pm_flags &= ~MSDOSFSMNT_MNTOPT; 26833548Sjkh pmp->pm_flags |= args.flags & MSDOSFSMNT_MNTOPT; 26933548Sjkh if (pmp->pm_flags & MSDOSFSMNT_NOWIN95) 27033548Sjkh pmp->pm_flags |= MSDOSFSMNT_SHORTNAME; 27133548Sjkh } 27233548Sjkh#endif 2732893Sdfr /* 2742893Sdfr * Process export requests. 2752893Sdfr */ 27633548Sjkh return (vfs_export(mp, &pmp->pm_export, &args.export)); 2772893Sdfr } 2782893Sdfr } 2792893Sdfr /* 28033548Sjkh * Not an update, or updating the name: look up the name 28133548Sjkh * and verify that it refers to a sensible block device. 2822893Sdfr */ 2832893Sdfr NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p); 2842893Sdfr error = namei(ndp); 28533548Sjkh if (error) 28633548Sjkh return (error); 28733548Sjkh devvp = ndp->ni_vp; 2888876Srgrimes 2892893Sdfr if (devvp->v_type != VBLK) { 2902893Sdfr vrele(devvp); 29133548Sjkh return (ENOTBLK); 2922893Sdfr } 2932893Sdfr if (major(devvp->v_rdev) >= nblkdev) { 2942893Sdfr vrele(devvp); 29533548Sjkh return (ENXIO); 2962893Sdfr } 2972893Sdfr /* 29833548Sjkh * If mount by non-root, then verify that user has necessary 29933548Sjkh * permissions on the device. 3002893Sdfr */ 30133548Sjkh if (p->p_ucred->cr_uid != 0) { 30233548Sjkh accessmode = VREAD; 30333548Sjkh if ((mp->mnt_flag & MNT_RDONLY) == 0) 30433548Sjkh accessmode |= VWRITE; 30533548Sjkh vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); 30633548Sjkh error = VOP_ACCESS(devvp, accessmode, p->p_ucred, p); 30733548Sjkh if (error) { 30833548Sjkh vput(devvp); 30933548Sjkh return (error); 31033548Sjkh } 31133548Sjkh VOP_UNLOCK(devvp, 0, p); 31233548Sjkh } 31333548Sjkh if ((mp->mnt_flag & MNT_UPDATE) == 0) { 31433548Sjkh error = mountmsdosfs(devvp, mp, p, &args); 31533548Sjkh#ifdef MSDOSFS_DEBUG /* only needed for the printf below */ 31633548Sjkh pmp = VFSTOMSDOSFS(mp); 31733548Sjkh#endif 31833548Sjkh } else { 3192893Sdfr if (devvp != pmp->pm_devvp) 32033548Sjkh error = EINVAL; /* XXX needs translation */ 3212893Sdfr else 3222893Sdfr vrele(devvp); 3232893Sdfr } 3242893Sdfr if (error) { 3252893Sdfr vrele(devvp); 32633548Sjkh return (error); 32733548Sjkh } 32833548Sjkh 32933548Sjkh error = update_mp(mp, &args); 33033548Sjkh if (error) { 33133548Sjkh msdosfs_unmount(mp, MNT_FORCE, p); 3322893Sdfr return error; 3332893Sdfr } 3342893Sdfr 33533548Sjkh (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size); 33633548Sjkh bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size); 33733548Sjkh (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 33833548Sjkh &size); 33933548Sjkh bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 3402893Sdfr (void) msdosfs_statfs(mp, &mp->mnt_stat, p); 3412893Sdfr#ifdef MSDOSFS_DEBUG 3423311Sphk printf("msdosfs_mount(): mp %p, pmp %p, inusemap %p\n", mp, pmp, pmp->pm_inusemap); 3432893Sdfr#endif 34433548Sjkh return (0); 3452893Sdfr} 3462893Sdfr 34712144Sphkstatic int 34833548Sjkhmountmsdosfs(devvp, mp, p, argp) 3492893Sdfr struct vnode *devvp; 3502893Sdfr struct mount *mp; 3512893Sdfr struct proc *p; 35233548Sjkh struct msdosfs_args *argp; 3532893Sdfr{ 35433548Sjkh struct msdosfsmount *pmp; 35533548Sjkh struct buf *bp; 3562893Sdfr dev_t dev = devvp->v_rdev; 35733548Sjkh#ifndef __FreeBSD__ 35833548Sjkh struct partinfo dpart; 35933548Sjkh#endif 3602893Sdfr union bootsector *bsp; 3612893Sdfr struct byte_bpb33 *b33; 3622893Sdfr struct byte_bpb50 *b50; 36316363Sasami#ifdef PC98 36416363Sasami u_int pc98_wrk; 36516363Sasami u_int Phy_Sector_Size; 36616363Sasami#endif 36733548Sjkh struct byte_bpb710 *b710; 36833548Sjkh u_int8_t SecPerClust; 36933548Sjkh int ronly, error; 37033548Sjkh int bsize = 0, dtype = 0, tmp; 3712893Sdfr 3722893Sdfr /* 37333548Sjkh * Disallow multiple mounts of the same device. 37433548Sjkh * Disallow mounting of a device that is currently in use 37533548Sjkh * (except for root, which might share swap device for miniroot). 37633548Sjkh * Flush out any old buffers remaining from a previous use. 3772893Sdfr */ 3783152Sphk error = vfs_mountedon(devvp); 3793152Sphk if (error) 38033548Sjkh return (error); 38133548Sjkh if (vcount(devvp) > 1 && devvp != rootvp) 38233548Sjkh return (EBUSY); 38333548Sjkh vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); 3843152Sphk error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0); 38533548Sjkh VOP_UNLOCK(devvp, 0, p); 3863152Sphk if (error) 38733548Sjkh return (error); 3882893Sdfr 38933548Sjkh ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 39033548Sjkh error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p); 3913152Sphk if (error) 39233548Sjkh return (error); 39333548Sjkh 39433548Sjkh bp = NULL; /* both used in error_exit */ 39533548Sjkh pmp = NULL; 39633548Sjkh 39733548Sjkh#ifndef __FreeBSD__ 39833548Sjkh if (argp->flags & MSDOSFSMNT_GEMDOSFS) { 39933548Sjkh /* 40033548Sjkh * We need the disklabel to calculate the size of a FAT entry 40133548Sjkh * later on. Also make sure the partition contains a filesystem 40233548Sjkh * of type FS_MSDOS. This doesn't work for floppies, so we have 40333548Sjkh * to check for them too. 40433548Sjkh * 40533548Sjkh * At least some parts of the msdos fs driver seem to assume 40633548Sjkh * that the size of a disk block will always be 512 bytes. 40733548Sjkh * Let's check it... 40833548Sjkh */ 40933548Sjkh error = VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, 41033548Sjkh FREAD, NOCRED, p); 41133548Sjkh if (error) 41233548Sjkh goto error_exit; 41333548Sjkh tmp = dpart.part->p_fstype; 41433548Sjkh dtype = dpart.disklab->d_type; 41533548Sjkh bsize = dpart.disklab->d_secsize; 41633548Sjkh if (bsize != 512 || (dtype!=DTYPE_FLOPPY && tmp!=FS_MSDOS)) { 41733548Sjkh error = EINVAL; 41833548Sjkh goto error_exit; 41933548Sjkh } 4202893Sdfr } 4212893Sdfr#endif 4222893Sdfr 4232893Sdfr /* 42433548Sjkh * Read the boot sector of the filesystem, and then check the 42533548Sjkh * boot signature. If not a dos boot sector then error out. 4262893Sdfr */ 42716363Sasami#ifdef PC98 42816363Sasami devvp->v_flag &= 0xffff; 42933548Sjkh error = bread(devvp, 0, 1024, NOCRED, &bp); 43016363Sasami#else 43133548Sjkh error = bread(devvp, 0, 512, NOCRED, &bp); 43216363Sasami#endif 4333152Sphk if (error) 4342893Sdfr goto error_exit; 43533548Sjkh bp->b_flags |= B_AGE; 43633548Sjkh bsp = (union bootsector *)bp->b_data; 43733548Sjkh b33 = (struct byte_bpb33 *)bsp->bs33.bsBPB; 43833548Sjkh b50 = (struct byte_bpb50 *)bsp->bs50.bsBPB; 43933548Sjkh b710 = (struct byte_bpb710 *)bsp->bs710.bsPBP; 44033548Sjkh 44133548Sjkh#ifndef __FreeBSD__ 44233548Sjkh if (!(argp->flags & MSDOSFSMNT_GEMDOSFS)) { 44333548Sjkh#endif 44433548Sjkh#ifdef PC98 44533548Sjkh if (bsp->bs50.bsBootSectSig0 != BOOTSIG0 44633548Sjkh || bsp->bs50.bsBootSectSig1 != BOOTSIG1 44733548Sjkh && bsp->bs50.bsBootSectSig0 != 0 /* PC98 DOS 3.3x */ 44833548Sjkh || bsp->bs50.bsBootSectSig1 != 0 44933548Sjkh && bsp->bs50.bsBootSectSig0 != 0x90 /* PC98 DOS 5.0 */ 45033548Sjkh || bsp->bs50.bsBootSectSig1 != 0x3d 45133548Sjkh && bsp->bs50.bsBootSectSig0 != 0x46 /* PC98 DOS 3.3B */ 45233548Sjkh || bsp->bs50.bsBootSectSig1 != 0xfa) { 45316363Sasami#else 45433548Sjkh if (bsp->bs50.bsBootSectSig0 != BOOTSIG0 45533548Sjkh || bsp->bs50.bsBootSectSig1 != BOOTSIG1) { 45616363Sasami#endif 45733548Sjkh error = EINVAL; 45833548Sjkh goto error_exit; 45933548Sjkh } 46033548Sjkh#ifndef __FreeBSD__ 4612893Sdfr } 4622893Sdfr#endif 4632893Sdfr 4642893Sdfr pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK); 4652893Sdfr bzero((caddr_t)pmp, sizeof *pmp); 4662893Sdfr pmp->pm_mountp = mp; 4672893Sdfr 4682893Sdfr /* 4692893Sdfr * Compute several useful quantities from the bpb in the 4702893Sdfr * bootsector. Copy in the dos 5 variant of the bpb then fix up 4712893Sdfr * the fields that are different between dos 5 and dos 3.3. 4722893Sdfr */ 47333548Sjkh SecPerClust = b50->bpbSecPerClust; 4742893Sdfr pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec); 4752893Sdfr pmp->pm_ResSectors = getushort(b50->bpbResSectors); 4762893Sdfr pmp->pm_FATs = b50->bpbFATs; 4772893Sdfr pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts); 4782893Sdfr pmp->pm_Sectors = getushort(b50->bpbSectors); 4792893Sdfr pmp->pm_FATsecs = getushort(b50->bpbFATsecs); 4802893Sdfr pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack); 4812893Sdfr pmp->pm_Heads = getushort(b50->bpbHeads); 48233548Sjkh pmp->pm_Media = b50->bpbMedia; 4832893Sdfr 48433548Sjkh#ifndef __FreeBSD__ 48533548Sjkh if (!(argp->flags & MSDOSFSMNT_GEMDOSFS)) { 48633548Sjkh#endif 48733548Sjkh /* XXX - We should probably check more values here */ 48833548Sjkh if (!pmp->pm_BytesPerSec || !SecPerClust 48933548Sjkh || !pmp->pm_Heads || pmp->pm_Heads > 255 49016363Sasami#ifdef PC98 49133548Sjkh || !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 255) { 49216363Sasami#else 49333548Sjkh || !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 63) { 49416363Sasami#endif 49533548Sjkh error = EINVAL; 49633548Sjkh goto error_exit; 49733548Sjkh } 49833548Sjkh#ifndef __FreeBSD__ 4992893Sdfr } 50033548Sjkh#endif 5012893Sdfr 5022893Sdfr if (pmp->pm_Sectors == 0) { 5032893Sdfr pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs); 5042893Sdfr pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors); 5052893Sdfr } else { 5062893Sdfr pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs); 5072893Sdfr pmp->pm_HugeSectors = pmp->pm_Sectors; 5082893Sdfr } 50916363Sasami#ifdef PC98 /* for PC98 added Satoshi Yasuda */ 51016363Sasami Phy_Sector_Size = 512; 51116363Sasami if ((devvp->v_rdev>>8) == 2) { /* floppy check */ 51216363Sasami if (((devvp->v_rdev&077) == 2) && (pmp->pm_HugeSectors == 1232)) { 51316363Sasami Phy_Sector_Size = 1024; /* 2HD */ 51416363Sasami /* 51516363Sasami * 1024byte/sector support 51616363Sasami */ 51716363Sasami devvp->v_flag |= 0x10000; 51816363Sasami } else { 51916363Sasami if ((((devvp->v_rdev&077) == 3) /* 2DD 8 or 9 sector */ 52016363Sasami && (pmp->pm_HugeSectors == 1440)) /* 9 sector */ 52116363Sasami || (((devvp->v_rdev&077) == 4) 52216363Sasami && (pmp->pm_HugeSectors == 1280)) /* 8 sector */ 52316363Sasami || (((devvp->v_rdev&077) == 5) 52416363Sasami && (pmp->pm_HugeSectors == 2880))) { /* 1.44M */ 52516363Sasami Phy_Sector_Size = 512; 52616363Sasami } else { 52716363Sasami if (((devvp->v_rdev&077) != 1) 52816363Sasami && ((devvp->v_rdev&077) != 0)) { /* 2HC */ 52916363Sasami error = EINVAL; 53016363Sasami goto error_exit; 53116363Sasami } 53216363Sasami } 53316363Sasami } 53416363Sasami } 53516363Sasami pc98_wrk = pmp->pm_BytesPerSec / Phy_Sector_Size; 53616363Sasami pmp->pm_BytesPerSec = Phy_Sector_Size; 53733548Sjkh SecPerClust = SecPerClust * pc98_wrk; 53816363Sasami pmp->pm_HugeSectors = pmp->pm_HugeSectors * pc98_wrk; 53916363Sasami pmp->pm_ResSectors = pmp->pm_ResSectors * pc98_wrk; 54016363Sasami pmp->pm_FATsecs = pmp->pm_FATsecs * pc98_wrk; 54116363Sasami pmp->pm_SecPerTrack = pmp->pm_SecPerTrack * pc98_wrk; 54216363Sasami pmp->pm_HiddenSects = pmp->pm_HiddenSects * pc98_wrk; 54316363Sasami#endif /* */ 54433548Sjkh if (pmp->pm_HugeSectors > 0xffffffff / pmp->pm_BytesPerSec + 1) { 54533548Sjkh /* 54633548Sjkh * We cannot deal currently with this size of disk 54733548Sjkh * due to fileid limitations (see msdosfs_getattr and 54833548Sjkh * msdosfs_readdir) 54933548Sjkh */ 55033548Sjkh error = EINVAL; 55133548Sjkh goto error_exit; 55233548Sjkh } 55333548Sjkh 55433548Sjkh if (pmp->pm_RootDirEnts == 0) { 55533548Sjkh if (bsp->bs710.bsBootSectSig2 != BOOTSIG2 55633548Sjkh || bsp->bs710.bsBootSectSig3 != BOOTSIG3 55733548Sjkh || pmp->pm_Sectors 55833548Sjkh || pmp->pm_FATsecs 55933548Sjkh || getushort(b710->bpbFSVers)) { 56033548Sjkh error = EINVAL; 56133548Sjkh goto error_exit; 56233548Sjkh } 56333548Sjkh pmp->pm_fatmask = FAT32_MASK; 56433548Sjkh pmp->pm_fatmult = 4; 56533548Sjkh pmp->pm_fatdiv = 1; 56633548Sjkh pmp->pm_FATsecs = getulong(b710->bpbBigFATsecs); 56733548Sjkh if (getushort(b710->bpbExtFlags) & FATMIRROR) 56833548Sjkh pmp->pm_curfat = getushort(b710->bpbExtFlags) & FATNUM; 56933548Sjkh else 57033548Sjkh pmp->pm_flags |= MSDOSFS_FATMIRROR; 57133548Sjkh } else 57233548Sjkh pmp->pm_flags |= MSDOSFS_FATMIRROR; 57333548Sjkh 57433548Sjkh#ifndef __FreeBSD__ 57533548Sjkh if (argp->flags & MSDOSFSMNT_GEMDOSFS) { 57633548Sjkh if (FAT32(pmp)) { 57733548Sjkh /* 57833548Sjkh * GEMDOS doesn't know fat32. 57933548Sjkh */ 58033548Sjkh error = EINVAL; 58133548Sjkh goto error_exit; 58233548Sjkh } 58333548Sjkh 58433548Sjkh /* 58533548Sjkh * Check a few values (could do some more): 58633548Sjkh * - logical sector size: power of 2, >= block size 58733548Sjkh * - sectors per cluster: power of 2, >= 1 58833548Sjkh * - number of sectors: >= 1, <= size of partition 58933548Sjkh */ 59033548Sjkh if ( (SecPerClust == 0) 59133548Sjkh || (SecPerClust & (SecPerClust - 1)) 59233548Sjkh || (pmp->pm_BytesPerSec < bsize) 59333548Sjkh || (pmp->pm_BytesPerSec & (pmp->pm_BytesPerSec - 1)) 59433548Sjkh || (pmp->pm_HugeSectors == 0) 59533548Sjkh || (pmp->pm_HugeSectors * (pmp->pm_BytesPerSec / bsize) 59633548Sjkh > dpart.part->p_size) 59733548Sjkh ) { 59833548Sjkh error = EINVAL; 59933548Sjkh goto error_exit; 60033548Sjkh } 60133548Sjkh /* 60233548Sjkh * XXX - Many parts of the msdos fs driver seem to assume that 60333548Sjkh * the number of bytes per logical sector (BytesPerSec) will 60433548Sjkh * always be the same as the number of bytes per disk block 60533548Sjkh * Let's pretend it is. 60633548Sjkh */ 60733548Sjkh tmp = pmp->pm_BytesPerSec / bsize; 60833548Sjkh pmp->pm_BytesPerSec = bsize; 60933548Sjkh pmp->pm_HugeSectors *= tmp; 61033548Sjkh pmp->pm_HiddenSects *= tmp; 61133548Sjkh pmp->pm_ResSectors *= tmp; 61233548Sjkh pmp->pm_Sectors *= tmp; 61333548Sjkh pmp->pm_FATsecs *= tmp; 61433548Sjkh SecPerClust *= tmp; 61533548Sjkh } 61633548Sjkh#endif 6172893Sdfr pmp->pm_fatblk = pmp->pm_ResSectors; 61833548Sjkh if (FAT32(pmp)) { 61933548Sjkh pmp->pm_rootdirblk = getulong(b710->bpbRootClust); 62033548Sjkh pmp->pm_firstcluster = pmp->pm_fatblk 62133548Sjkh + (pmp->pm_FATs * pmp->pm_FATsecs); 62233548Sjkh pmp->pm_fsinfo = getushort(b710->bpbFSInfo); 62333548Sjkh } else { 62433548Sjkh pmp->pm_rootdirblk = pmp->pm_fatblk + 62533548Sjkh (pmp->pm_FATs * pmp->pm_FATsecs); 62633548Sjkh pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry) 62733548Sjkh + pmp->pm_BytesPerSec - 1) 62833548Sjkh / pmp->pm_BytesPerSec;/* in sectors */ 62933548Sjkh pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize; 63033548Sjkh } 63133548Sjkh 6322893Sdfr pmp->pm_nmbrofclusters = (pmp->pm_HugeSectors - pmp->pm_firstcluster) / 63333548Sjkh SecPerClust; 6342893Sdfr pmp->pm_maxcluster = pmp->pm_nmbrofclusters + 1; 6352893Sdfr pmp->pm_fatsize = pmp->pm_FATsecs * pmp->pm_BytesPerSec; 63633548Sjkh 63733548Sjkh#ifndef __FreeBSD__ 63833548Sjkh if (argp->flags & MSDOSFSMNT_GEMDOSFS) { 63933548Sjkh if ((pmp->pm_nmbrofclusters <= (0xff0 - 2)) 64033548Sjkh && ((dtype == DTYPE_FLOPPY) || ((dtype == DTYPE_VNODE) 64133548Sjkh && ((pmp->pm_Heads == 1) || (pmp->pm_Heads == 2)))) 64233548Sjkh ) { 64333548Sjkh pmp->pm_fatmask = FAT12_MASK; 64433548Sjkh pmp->pm_fatmult = 3; 64533548Sjkh pmp->pm_fatdiv = 2; 64633548Sjkh } else { 64733548Sjkh pmp->pm_fatmask = FAT16_MASK; 64833548Sjkh pmp->pm_fatmult = 2; 64933548Sjkh pmp->pm_fatdiv = 1; 65033548Sjkh } 65133548Sjkh } else 65233548Sjkh#endif 65333548Sjkh if (pmp->pm_fatmask == 0) { 65433548Sjkh if (pmp->pm_maxcluster 65533548Sjkh <= ((CLUST_RSRVD - CLUST_FIRST) & FAT12_MASK)) { 65633548Sjkh /* 65733548Sjkh * This will usually be a floppy disk. This size makes 65833548Sjkh * sure that one fat entry will not be split across 65933548Sjkh * multiple blocks. 66033548Sjkh */ 66133548Sjkh pmp->pm_fatmask = FAT12_MASK; 66233548Sjkh pmp->pm_fatmult = 3; 66333548Sjkh pmp->pm_fatdiv = 2; 66433548Sjkh } else { 66533548Sjkh pmp->pm_fatmask = FAT16_MASK; 66633548Sjkh pmp->pm_fatmult = 2; 66733548Sjkh pmp->pm_fatdiv = 1; 66833548Sjkh } 66933548Sjkh } 6702893Sdfr if (FAT12(pmp)) 6712893Sdfr pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec; 6722893Sdfr else 6732893Sdfr pmp->pm_fatblocksize = MAXBSIZE; 67433548Sjkh 6752893Sdfr pmp->pm_fatblocksec = pmp->pm_fatblocksize / pmp->pm_BytesPerSec; 67633548Sjkh pmp->pm_bnshift = ffs(pmp->pm_BytesPerSec) - 1; 6772893Sdfr 6782893Sdfr /* 6792893Sdfr * Compute mask and shift value for isolating cluster relative byte 6802893Sdfr * offsets and cluster numbers from a file offset. 6812893Sdfr */ 68233548Sjkh pmp->pm_bpcluster = SecPerClust * pmp->pm_BytesPerSec; 68333548Sjkh pmp->pm_crbomask = pmp->pm_bpcluster - 1; 68433548Sjkh pmp->pm_cnshift = ffs(pmp->pm_bpcluster) - 1; 68533548Sjkh 68633548Sjkh /* 68733548Sjkh * Check for valid cluster size 68833548Sjkh * must be a power of 2 68933548Sjkh */ 69033548Sjkh if (pmp->pm_bpcluster ^ (1 << pmp->pm_cnshift)) { 6912893Sdfr error = EINVAL; 6922893Sdfr goto error_exit; 6932893Sdfr } 6942893Sdfr 69533548Sjkh /* 69633548Sjkh * Release the bootsector buffer. 69733548Sjkh */ 69833548Sjkh brelse(bp); 69933548Sjkh bp = NULL; 70033548Sjkh 70133548Sjkh /* 70233548Sjkh * Check FSInfo. 70333548Sjkh */ 70433548Sjkh if (pmp->pm_fsinfo) { 70533548Sjkh struct fsinfo *fp; 70633548Sjkh 70733548Sjkh if ((error = bread(devvp, pmp->pm_fsinfo, 1024, NOCRED, &bp)) != 0) 70833548Sjkh goto error_exit; 70933548Sjkh fp = (struct fsinfo *)bp->b_data; 71033548Sjkh if (!bcmp(fp->fsisig1, "RRaA", 4) 71133548Sjkh && !bcmp(fp->fsisig2, "rrAa", 4) 71233548Sjkh && !bcmp(fp->fsisig3, "\0\0\125\252", 4) 71333548Sjkh && !bcmp(fp->fsisig4, "\0\0\125\252", 4)) 71433548Sjkh pmp->pm_nxtfree = getulong(fp->fsinxtfree); 71533548Sjkh else 71633548Sjkh pmp->pm_fsinfo = 0; 71733548Sjkh brelse(bp); 71833548Sjkh bp = NULL; 71916363Sasami } 7202893Sdfr 7212893Sdfr /* 72233548Sjkh * Check and validate (or perhaps invalidate?) the fsinfo structure? XXX 7232893Sdfr */ 7242893Sdfr 7252893Sdfr /* 7262893Sdfr * Allocate memory for the bitmap of allocated clusters, and then 7272893Sdfr * fill it in. 7282893Sdfr */ 7292893Sdfr pmp->pm_inusemap = malloc(((pmp->pm_maxcluster + N_INUSEBITS - 1) 7302893Sdfr / N_INUSEBITS) 7312893Sdfr * sizeof(*pmp->pm_inusemap), 7322893Sdfr M_MSDOSFSFAT, M_WAITOK); 7332893Sdfr 7342893Sdfr /* 7352893Sdfr * fillinusemap() needs pm_devvp. 7362893Sdfr */ 7372893Sdfr pmp->pm_dev = dev; 7382893Sdfr pmp->pm_devvp = devvp; 7392893Sdfr 7402893Sdfr /* 7412893Sdfr * Have the inuse map filled in. 7422893Sdfr */ 74333548Sjkh if ((error = fillinusemap(pmp)) != 0) 7442893Sdfr goto error_exit; 7452893Sdfr 7462893Sdfr /* 7472893Sdfr * If they want fat updates to be synchronous then let them suffer 7482893Sdfr * the performance degradation in exchange for the on disk copy of 7492893Sdfr * the fat being correct just about all the time. I suppose this 7502893Sdfr * would be a good thing to turn on if the kernel is still flakey. 7512893Sdfr */ 75233548Sjkh if (mp->mnt_flag & MNT_SYNCHRONOUS) 75333548Sjkh pmp->pm_flags |= MSDOSFSMNT_WAITONFAT; 7542893Sdfr 7552893Sdfr /* 7562893Sdfr * Finish up. 7572893Sdfr */ 75833548Sjkh if (ronly) 75933548Sjkh pmp->pm_flags |= MSDOSFSMNT_RONLY; 76033548Sjkh else 7612893Sdfr pmp->pm_fmod = 1; 7622893Sdfr mp->mnt_data = (qaddr_t) pmp; 76323134Sbde mp->mnt_stat.f_fsid.val[0] = (long)dev; 76423134Sbde mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; 76523997Speter mp->mnt_flag |= MNT_LOCAL; 7662893Sdfr devvp->v_specflags |= SI_MOUNTEDON; 7672893Sdfr 7682893Sdfr return 0; 7692893Sdfr 77033548Sjkherror_exit: 77133548Sjkh if (bp) 77233548Sjkh brelse(bp); 77333548Sjkh (void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD | FWRITE, NOCRED, p); 7742893Sdfr if (pmp) { 7752893Sdfr if (pmp->pm_inusemap) 77633548Sjkh free(pmp->pm_inusemap, M_MSDOSFSFAT); 77733548Sjkh free(pmp, M_MSDOSFSMNT); 77833548Sjkh mp->mnt_data = (qaddr_t)0; 7792893Sdfr } 78033548Sjkh return (error); 7812893Sdfr} 7822893Sdfr 78312144Sphkstatic int 7842893Sdfrmsdosfs_start(mp, flags, p) 7852893Sdfr struct mount *mp; 7862893Sdfr int flags; 7872893Sdfr struct proc *p; 7882893Sdfr{ 78933548Sjkh 79033548Sjkh return (0); 7912893Sdfr} 7922893Sdfr 7932893Sdfr/* 7942893Sdfr * Unmount the filesystem described by mp. 7952893Sdfr */ 79612144Sphkstatic int 7972893Sdfrmsdosfs_unmount(mp, mntflags, p) 7982893Sdfr struct mount *mp; 7992893Sdfr int mntflags; 8002893Sdfr struct proc *p; 8012893Sdfr{ 80233548Sjkh struct msdosfsmount *pmp; 80333548Sjkh int error, flags; 8042893Sdfr 80533548Sjkh flags = 0; 80633548Sjkh if (mntflags & MNT_FORCE) 8072893Sdfr flags |= FORCECLOSE; 8083152Sphk error = vflush(mp, NULLVP, flags); 8093152Sphk if (error) 8102893Sdfr return error; 81133548Sjkh pmp = VFSTOMSDOSFS(mp); 8122893Sdfr pmp->pm_devvp->v_specflags &= ~SI_MOUNTEDON; 81333548Sjkh#ifdef MSDOSFS_DEBUG 81433548Sjkh { 81533548Sjkh struct vnode *vp = pmp->pm_devvp; 81633548Sjkh 81733548Sjkh printf("msdosfs_umount(): just before calling VOP_CLOSE()\n"); 81833548Sjkh printf("flag %08lx, usecount %d, writecount %d, holdcnt %ld\n", 81933548Sjkh vp->v_flag, vp->v_usecount, vp->v_writecount, vp->v_holdcnt); 82033548Sjkh printf("lastr %d, id %lu, mount %p, op %p\n", 82133548Sjkh vp->v_lastr, vp->v_id, vp->v_mount, vp->v_op); 82233548Sjkh printf("freef %p, freeb %p, mount %p\n", 82333548Sjkh vp->v_freelist.tqe_next, vp->v_freelist.tqe_prev, 82433548Sjkh vp->v_mount); 82533548Sjkh printf("cleanblkhd %p, dirtyblkhd %p, numoutput %ld, type %d\n", 82633548Sjkh vp->v_cleanblkhd.lh_first, 82733548Sjkh vp->v_dirtyblkhd.lh_first, 82833548Sjkh vp->v_numoutput, vp->v_type); 82933548Sjkh printf("union %p, tag %d, data[0] %08x, data[1] %08x\n", 83033548Sjkh vp->v_socket, vp->v_tag, 83133548Sjkh ((u_int *)vp->v_data)[0], 83233548Sjkh ((u_int *)vp->v_data)[1]); 83333548Sjkh } 83433548Sjkh#endif 83533548Sjkh error = VOP_CLOSE(pmp->pm_devvp, (pmp->pm_flags&MSDOSFSMNT_RONLY) ? FREAD : FREAD | FWRITE, 8362893Sdfr NOCRED, p); 8372893Sdfr vrele(pmp->pm_devvp); 83833548Sjkh free(pmp->pm_inusemap, M_MSDOSFSFAT); 83933548Sjkh free(pmp, M_MSDOSFSMNT); 84033548Sjkh mp->mnt_data = (qaddr_t)0; 84123997Speter mp->mnt_flag &= ~MNT_LOCAL; 84233548Sjkh return (error); 8432893Sdfr} 8442893Sdfr 84512144Sphkstatic int 8462893Sdfrmsdosfs_root(mp, vpp) 8472893Sdfr struct mount *mp; 8482893Sdfr struct vnode **vpp; 8492893Sdfr{ 85033548Sjkh struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 8512893Sdfr struct denode *ndep; 8522893Sdfr int error; 8532893Sdfr 8542893Sdfr#ifdef MSDOSFS_DEBUG 85533548Sjkh printf("msdosfs_root(); mp %p, pmp %p\n", mp, pmp); 8562893Sdfr#endif 85733548Sjkh error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, &ndep); 85833548Sjkh if (error) 85933548Sjkh return (error); 86033548Sjkh *vpp = DETOV(ndep); 86133548Sjkh return (0); 8622893Sdfr} 8632893Sdfr 86412144Sphkstatic int 8652893Sdfrmsdosfs_quotactl(mp, cmds, uid, arg, p) 8662893Sdfr struct mount *mp; 8672893Sdfr int cmds; 8682893Sdfr uid_t uid; 8692893Sdfr caddr_t arg; 8702893Sdfr struct proc *p; 8712893Sdfr{ 8723152Sphk return EOPNOTSUPP; 8732893Sdfr} 8742893Sdfr 87512144Sphkstatic int 8762893Sdfrmsdosfs_statfs(mp, sbp, p) 8772893Sdfr struct mount *mp; 8782893Sdfr struct statfs *sbp; 8792893Sdfr struct proc *p; 8802893Sdfr{ 88133548Sjkh struct msdosfsmount *pmp; 8822893Sdfr 88333548Sjkh pmp = VFSTOMSDOSFS(mp); 8842893Sdfr sbp->f_bsize = pmp->pm_bpcluster; 8852893Sdfr sbp->f_iosize = pmp->pm_bpcluster; 8862893Sdfr sbp->f_blocks = pmp->pm_nmbrofclusters; 8872893Sdfr sbp->f_bfree = pmp->pm_freeclustercount; 8882893Sdfr sbp->f_bavail = pmp->pm_freeclustercount; 8892893Sdfr sbp->f_files = pmp->pm_RootDirEnts; /* XXX */ 8902893Sdfr sbp->f_ffree = 0; /* what to put in here? */ 8912893Sdfr if (sbp != &mp->mnt_stat) { 89223134Sbde sbp->f_type = mp->mnt_vfc->vfc_typenum; 89333548Sjkh bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 89433548Sjkh bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 8952893Sdfr } 89633548Sjkh strncpy(sbp->f_fstypename, mp->mnt_vfc->vfc_name, MFSNAMELEN); 89733548Sjkh return (0); 8982893Sdfr} 8992893Sdfr 90012144Sphkstatic int 9012893Sdfrmsdosfs_sync(mp, waitfor, cred, p) 9022893Sdfr struct mount *mp; 9032893Sdfr int waitfor; 9042893Sdfr struct ucred *cred; 9052893Sdfr struct proc *p; 9062893Sdfr{ 90733548Sjkh struct vnode *vp, *nvp; 9082893Sdfr struct denode *dep; 90933548Sjkh struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 91033548Sjkh int error, allerror = 0; 9112893Sdfr 9122893Sdfr /* 9132893Sdfr * If we ever switch to not updating all of the fats all the time, 9142893Sdfr * this would be the place to update them from the first one. 9152893Sdfr */ 91633548Sjkh if (pmp->pm_fmod != 0) 91733548Sjkh if (pmp->pm_flags & MSDOSFSMNT_RONLY) 9182893Sdfr panic("msdosfs_sync: rofs mod"); 9192893Sdfr else { 9202893Sdfr /* update fats here */ 9212893Sdfr } 9222893Sdfr /* 92333548Sjkh * Write back each (modified) denode. 9242893Sdfr */ 92523134Sbde simple_lock(&mntvnode_slock); 9262893Sdfrloop: 92733548Sjkh for (vp = mp->mnt_vnodelist.lh_first; 92833548Sjkh vp != NULL; 92933548Sjkh vp = nvp) { 93033548Sjkh /* 93133548Sjkh * If the vnode that we are about to sync is no longer 93233548Sjkh * assoicated with this mount point, start over. 93333548Sjkh */ 93433548Sjkh if (vp->v_mount != mp) 9352893Sdfr goto loop; 93633548Sjkh 93723134Sbde simple_lock(&vp->v_interlock); 93833548Sjkh nvp = vp->v_mntvnodes.le_next; 9392893Sdfr dep = VTODE(vp); 94033548Sjkh if (vp->v_type == VNON || ((dep->de_flag & 94133548Sjkh (DE_ACCESS | DE_CREATE | DE_UPDATE | DE_MODIFIED)) == 0) 94233548Sjkh && vp->v_dirtyblkhd.lh_first == NULL) { 94323134Sbde simple_unlock(&vp->v_interlock); 9442893Sdfr continue; 94523134Sbde } 94623134Sbde simple_unlock(&mntvnode_slock); 94723134Sbde error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p); 94823134Sbde if (error) { 94923134Sbde simple_lock(&mntvnode_slock); 95023134Sbde if (error == ENOENT) 95123134Sbde goto loop; 95223134Sbde continue; 95323134Sbde } 9543152Sphk error = VOP_FSYNC(vp, cred, waitfor, p); 9553152Sphk if (error) 9562893Sdfr allerror = error; 95723134Sbde VOP_UNLOCK(vp, 0, p); 95823134Sbde vrele(vp); /* done with this one */ 95923134Sbde simple_lock(&mntvnode_slock); 9602893Sdfr } 96123134Sbde simple_unlock(&mntvnode_slock); 9622893Sdfr 9632893Sdfr /* 9642893Sdfr * Flush filesystem control info. 9652893Sdfr */ 9663152Sphk error = VOP_FSYNC(pmp->pm_devvp, cred, waitfor, p); 9673152Sphk if (error) 9682893Sdfr allerror = error; 96933548Sjkh return (allerror); 9702893Sdfr} 9712893Sdfr 97212144Sphkstatic int 9732893Sdfrmsdosfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp) 9742893Sdfr struct mount *mp; 9752893Sdfr struct fid *fhp; 97628270Swollman struct sockaddr *nam; 9772893Sdfr struct vnode **vpp; 9782893Sdfr int *exflagsp; 9792893Sdfr struct ucred **credanonp; 9802893Sdfr{ 98133548Sjkh struct msdosfsmount *pmp = VFSTOMSDOSFS(mp); 9822893Sdfr struct defid *defhp = (struct defid *) fhp; 9832893Sdfr struct denode *dep; 9842893Sdfr struct netcred *np; 9852893Sdfr int error; 9862893Sdfr 9872893Sdfr np = vfs_export_lookup(mp, &pmp->pm_export, nam); 9882893Sdfr if (np == NULL) 98933548Sjkh return (EACCES); 99033548Sjkh error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs, &dep); 9912893Sdfr if (error) { 9922893Sdfr *vpp = NULLVP; 99333548Sjkh return (error); 9942893Sdfr } 9952893Sdfr *vpp = DETOV(dep); 9962893Sdfr *exflagsp = np->netc_exflags; 9972893Sdfr *credanonp = &np->netc_anon; 99833548Sjkh return (0); 9992893Sdfr} 10002893Sdfr 100112144Sphkstatic int 10022893Sdfrmsdosfs_vptofh(vp, fhp) 10032893Sdfr struct vnode *vp; 10042893Sdfr struct fid *fhp; 10052893Sdfr{ 100633548Sjkh struct denode *dep; 100733548Sjkh struct defid *defhp; 10082893Sdfr 100933548Sjkh dep = VTODE(vp); 101033548Sjkh defhp = (struct defid *)fhp; 10112893Sdfr defhp->defid_len = sizeof(struct defid); 10122893Sdfr defhp->defid_dirclust = dep->de_dirclust; 10132893Sdfr defhp->defid_dirofs = dep->de_diroffset; 101433548Sjkh /* defhp->defid_gen = dep->de_gen; */ 101533548Sjkh return (0); 10162893Sdfr} 10172893Sdfr 101812144Sphkstatic int 10192893Sdfrmsdosfs_vget(mp, ino, vpp) 10202893Sdfr struct mount *mp; 10212893Sdfr ino_t ino; 10222893Sdfr struct vnode **vpp; 10232893Sdfr{ 10242893Sdfr return EOPNOTSUPP; 10252893Sdfr} 10262893Sdfr 102712145Sphkstatic struct vfsops msdosfs_vfsops = { 10282893Sdfr msdosfs_mount, 10292893Sdfr msdosfs_start, 10302893Sdfr msdosfs_unmount, 10312893Sdfr msdosfs_root, 10322893Sdfr msdosfs_quotactl, 10332893Sdfr msdosfs_statfs, 10342893Sdfr msdosfs_sync, 10352893Sdfr msdosfs_vget, 10362893Sdfr msdosfs_fhtovp, 10372893Sdfr msdosfs_vptofh, 10382893Sdfr msdosfs_init 10392893Sdfr}; 10402946Swollman 10412946SwollmanVFS_SET(msdosfs_vfsops, msdos, MOUNT_MSDOS, 0); 1042