msdosfs_vfsops.c revision 16363
118316Swollman/* $Id: msdosfs_vfsops.c,v 1.12 1996/04/03 23:05:40 gpalmer Exp $ */ 218316Swollman/* $NetBSD: msdosfs_vfsops.c,v 1.19 1994/08/21 18:44:10 ws Exp $ */ 318316Swollman 418316Swollman/*- 518316Swollman * Copyright (C) 1994 Wolfgang Solfrank. 618316Swollman * Copyright (C) 1994 TooLs GmbH. 718316Swollman * All rights reserved. 818316Swollman * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). 918316Swollman * 1018316Swollman * Redistribution and use in source and binary forms, with or without 1118316Swollman * modification, are permitted provided that the following conditions 1218316Swollman * are met: 1318316Swollman * 1. Redistributions of source code must retain the above copyright 1418316Swollman * notice, this list of conditions and the following disclaimer. 1518316Swollman * 2. Redistributions in binary form must reproduce the above copyright 1618316Swollman * notice, this list of conditions and the following disclaimer in the 1718316Swollman * documentation and/or other materials provided with the distribution. 1818316Swollman * 3. All advertising materials mentioning features or use of this software 1918316Swollman * must display the following acknowledgement: 2018316Swollman * This product includes software developed by TooLs GmbH. 2118316Swollman * 4. The name of TooLs GmbH may not be used to endorse or promote products 2218316Swollman * derived from this software without specific prior written permission. 2318316Swollman * 2418316Swollman * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 2518316Swollman * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2618316Swollman * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2718316Swollman * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 2818316Swollman * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 2918316Swollman * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 3018316Swollman * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 3118316Swollman * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 3218316Swollman * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 3318316Swollman * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3418316Swollman */ 3518316Swollman/* 3618316Swollman * Written by Paul Popelka (paulp@uts.amdahl.com) 3718316Swollman * 3818316Swollman * You can do anything you want with this software, just don't say you wrote 3918316Swollman * it, and don't remove this notice. 4018316Swollman * 4118316Swollman * This software is provided "as is". 4218316Swollman * 4318316Swollman * The author supplies this software to be publicly redistributed on the 4418316Swollman * understanding that the author is not responsible for the correct 4518316Swollman * functioning of this software in any circumstances and is not liable for 4618316Swollman * any damages caused by this software. 4718316Swollman * 4818316Swollman * October 1992 4918316Swollman */ 5018316Swollman 5118316Swollman#include <sys/param.h> 5218316Swollman#include <sys/systm.h> 5318316Swollman#include <sys/namei.h> 5418316Swollman#include <sys/proc.h> 5518316Swollman#include <sys/kernel.h> 5618316Swollman#include <sys/vnode.h> 5718316Swollman#include <miscfs/specfs/specdev.h> /* XXX */ /* defines v_rdev */ 5818316Swollman#include <sys/mount.h> 5918316Swollman#include <sys/buf.h> 6018316Swollman#include <sys/file.h> 6118316Swollman#include <sys/malloc.h> 6218316Swollman 6318316Swollman#include <msdosfs/bpb.h> 6418316Swollman#include <msdosfs/bootsect.h> 6518316Swollman#include <msdosfs/direntry.h> 6618316Swollman#include <msdosfs/denode.h> 6718316Swollman#include <msdosfs/msdosfsmount.h> 6818316Swollman#include <msdosfs/fat.h> 6918316Swollman 7018316Swollmanstatic int msdosfsdoforce = 1; /* 1 = force unmount */ 7118316Swollman 7218316Swollmanstatic int mountmsdosfs __P((struct vnode *devvp, struct mount *mp, 7318316Swollman struct proc *p)); 7418316Swollmanstatic int msdosfs_fhtovp __P((struct mount *, struct fid *, 7518316Swollman struct mbuf *, struct vnode **, int *, 7618316Swollman struct ucred **)); 7718316Swollmanstatic int msdosfs_mount __P((struct mount *, char *, caddr_t, 7818316Swollman struct nameidata *, struct proc *)); 7918316Swollmanstatic int msdosfs_quotactl __P((struct mount *, int, uid_t, caddr_t, 8018316Swollman struct proc *)); 8118316Swollmanstatic int msdosfs_root __P((struct mount *, struct vnode **)); 8218316Swollmanstatic int msdosfs_start __P((struct mount *, int, struct proc *)); 8318316Swollmanstatic int msdosfs_statfs __P((struct mount *, struct statfs *, 8418316Swollman struct proc *)); 8518316Swollmanstatic int msdosfs_sync __P((struct mount *, int, struct ucred *, 8618316Swollman struct proc *)); 8718316Swollmanstatic int msdosfs_unmount __P((struct mount *, int, struct proc *)); 8818316Swollmanstatic int msdosfs_vget __P((struct mount *mp, ino_t ino, 8918316Swollman struct vnode **vpp)); 9018316Swollmanstatic int msdosfs_vptofh __P((struct vnode *, struct fid *)); 9118316Swollman 9218316Swollman/* 9318316Swollman * mp - path - addr in user space of mount point (ie /usr or whatever) 9418316Swollman * data - addr in user space of mount params including the name of the block 9518316Swollman * special file to treat as a filesystem. 9618316Swollman */ 9718316Swollmanstatic int 9818316Swollmanmsdosfs_mount(mp, path, data, ndp, p) 9918316Swollman struct mount *mp; 10018316Swollman char *path; 10118316Swollman caddr_t data; 10218316Swollman struct nameidata *ndp; 10318316Swollman struct proc *p; 10418316Swollman{ 10518316Swollman struct vnode *devvp; /* vnode for blk device to mount */ 10618316Swollman struct msdosfs_args args; /* will hold data from mount request */ 10718316Swollman struct msdosfsmount *pmp; /* msdosfs specific mount control block */ 10818316Swollman int error, flags; 10918316Swollman u_int size; 11018316Swollman struct ucred *cred, *scred; 11118316Swollman struct vattr va; 11218316Swollman 11318316Swollman /* 11418316Swollman * Copy in the args for the mount request. 11518316Swollman */ 11618316Swollman error = copyin(data, (caddr_t) & args, sizeof(struct msdosfs_args)); 11718316Swollman if (error) 11818316Swollman return error; 11918316Swollman 12018316Swollman /* 12118316Swollman * If they just want to update then be sure we can do what is 12218316Swollman * asked. Can't change a filesystem from read/write to read only. 12318316Swollman * Why? And if they've supplied a new device file name then we 12418316Swollman * continue, otherwise return. 12518316Swollman */ 12618316Swollman if (mp->mnt_flag & MNT_UPDATE) { 12718316Swollman pmp = (struct msdosfsmount *) mp->mnt_data; 12818316Swollman error = 0; 12918316Swollman if (pmp->pm_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) { 13018316Swollman flags = WRITECLOSE; 13118316Swollman if (mp->mnt_flag & MNT_FORCE) 13218316Swollman flags |= FORCECLOSE; 13318316Swollman if (vfs_busy(mp)) 13418316Swollman return EBUSY; 13518316Swollman error = vflush(mp, NULLVP, flags); 13618316Swollman vfs_unbusy(mp); 13718316Swollman } 13818316Swollman if (!error && (mp->mnt_flag & MNT_RELOAD)) 13918316Swollman /* not yet implemented */ 14018316Swollman error = EINVAL; 14118316Swollman if (error) 14218316Swollman return error; 14318316Swollman if (pmp->pm_ronly && (mp->mnt_flag & MNT_RDONLY) == 0) 14418316Swollman pmp->pm_ronly = 0; 14518316Swollman if (args.fspec == 0) { 14618316Swollman /* 14718316Swollman * Process export requests. 14818316Swollman */ 14918316Swollman return vfs_export(mp, &pmp->pm_export, &args.export); 15018316Swollman } 15118316Swollman } else 15218316Swollman pmp = NULL; 15318316Swollman 15418316Swollman /* 15518316Swollman * check to see that the user in owns the target directory. 15618316Swollman * Note the very XXX trick to make sure we're checking as the 15718316Swollman * real user -- were mount() executable by anyone, this wouldn't 15818316Swollman * be a problem. 15918316Swollman * 16018316Swollman * XXX there should be one consistent error out. 16118316Swollman */ 16218316Swollman cred = crdup(p->p_ucred); /* XXX */ 16318316Swollman cred->cr_uid = p->p_cred->p_ruid; /* XXX */ 16418316Swollman error = VOP_GETATTR(mp->mnt_vnodecovered, &va, cred, p); 16518316Swollman if (error) { 16618316Swollman crfree(cred); /* XXX */ 16718316Swollman return error; 16818316Swollman } 16918316Swollman if (cred->cr_uid != 0) { 17018316Swollman if (va.va_uid != cred->cr_uid) { 17118316Swollman error = EACCES; 17218316Swollman crfree(cred); /* XXX */ 17318316Swollman return error; 17418316Swollman } 17518316Swollman 17618316Swollman /* a user mounted it; we'll verify permissions when unmounting */ 17718316Swollman mp->mnt_flag |= MNT_USER; 17818316Swollman } 17918316Swollman 18018316Swollman /* 18118316Swollman * Now, lookup the name of the block device this mount or name 18218316Swollman * update request is to apply to. 18318316Swollman */ 18418316Swollman NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p); 18518316Swollman scred = p->p_ucred; /* XXX */ 18618316Swollman p->p_ucred = cred; /* XXX */ 18718316Swollman error = namei(ndp); 18818316Swollman p->p_ucred = scred; /* XXX */ 18918316Swollman crfree(cred); /* XXX */ 19018316Swollman if (error != 0) 19118316Swollman return error; 19218316Swollman 19318316Swollman /* 19418316Swollman * Be sure they've given us a block device to treat as a 19518316Swollman * filesystem. And, that its major number is within the bdevsw 19618316Swollman * table. 19718316Swollman */ 19818316Swollman devvp = ndp->ni_vp; 19918316Swollman if (devvp->v_type != VBLK) { 20018316Swollman vrele(devvp); 20118316Swollman return ENOTBLK; 20218316Swollman } 20318316Swollman if (major(devvp->v_rdev) >= nblkdev) { 20418316Swollman vrele(devvp); 20518316Swollman return ENXIO; 20618316Swollman } 20718316Swollman 20818316Swollman /* 20918316Swollman * If this is an update, then make sure the vnode for the block 21018316Swollman * special device is the same as the one our filesystem is in. 21118316Swollman */ 21218316Swollman if (mp->mnt_flag & MNT_UPDATE) { 21318316Swollman if (devvp != pmp->pm_devvp) 21418316Swollman error = EINVAL; 21518316Swollman else 21618316Swollman vrele(devvp); 21718316Swollman } else { 21818316Swollman 21918316Swollman /* 22018316Swollman * Well, it's not an update, it's a real mount request. 22118316Swollman * Time to get dirty. 22218316Swollman */ 22318316Swollman error = mountmsdosfs(devvp, mp, p); 22418316Swollman } 22518316Swollman if (error) { 22618316Swollman vrele(devvp); 22718316Swollman return error; 22818316Swollman } 22918316Swollman 23018316Swollman /* 23118316Swollman * Copy in the name of the directory the filesystem is to be 23218316Swollman * mounted on. Then copy in the name of the block special file 23318316Swollman * representing the filesystem being mounted. And we clear the 23418316Swollman * remainder of the character strings to be tidy. Set up the 23518316Swollman * user id/group id/mask as specified by the user. Then, we try to 23618316Swollman * fill in the filesystem stats structure as best we can with 23718316Swollman * whatever applies from a dos file system. 23818316Swollman */ 23918316Swollman pmp = (struct msdosfsmount *) mp->mnt_data; 24018316Swollman copyinstr(path, (caddr_t) mp->mnt_stat.f_mntonname, 24118316Swollman sizeof(mp->mnt_stat.f_mntonname) - 1, &size); 24218316Swollman bzero(mp->mnt_stat.f_mntonname + size, 24318316Swollman sizeof(mp->mnt_stat.f_mntonname) - size); 24418316Swollman copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size); 24518316Swollman bzero(mp->mnt_stat.f_mntfromname + size, 24618316Swollman MNAMELEN - size); 24718316Swollman pmp->pm_mounter = p->p_cred->p_ruid; 24818316Swollman pmp->pm_gid = args.gid; 24918316Swollman pmp->pm_uid = args.uid; 25018316Swollman pmp->pm_mask = args.mask; 25118316Swollman (void) msdosfs_statfs(mp, &mp->mnt_stat, p); 25218316Swollman#ifdef MSDOSFS_DEBUG 25318316Swollman printf("msdosfs_mount(): mp %p, pmp %p, inusemap %p\n", mp, pmp, pmp->pm_inusemap); 25418316Swollman#endif 25518316Swollman return 0; 25618316Swollman} 25718316Swollman 25818316Swollmanstatic int 25918316Swollmanmountmsdosfs(devvp, mp, p) 26018316Swollman struct vnode *devvp; 26118316Swollman struct mount *mp; 26218316Swollman struct proc *p; 26318316Swollman{ 26418316Swollman int i; 26518316Swollman int bpc; 26618316Swollman int bit; 26718316Swollman int error; 26818316Swollman int needclose; 26918316Swollman int ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 27018316Swollman dev_t dev = devvp->v_rdev; 27118316Swollman union bootsector *bsp; 27218316Swollman struct msdosfsmount *pmp = NULL; 27318316Swollman struct buf *bp0 = NULL; 27418316Swollman struct byte_bpb33 *b33; 27518316Swollman struct byte_bpb50 *b50; 27618316Swollman#ifdef PC98 27718316Swollman u_int pc98_wrk; 27818316Swollman u_int Phy_Sector_Size; 27918316Swollman#endif 28018316Swollman 28118316Swollman /* 28218316Swollman * Multiple mounts of the same block special file aren't allowed. 28318316Swollman * Make sure no one else has the special file open. And flush any 28418316Swollman * old buffers from this filesystem. Presumably this prevents us 28518316Swollman * from running into buffers that are the wrong blocksize. 28618316Swollman */ 28718316Swollman error = vfs_mountedon(devvp); 28818316Swollman if (error) 28918316Swollman return error; 29018316Swollman if (vcount(devvp) > 1) 29118316Swollman return EBUSY; 29218316Swollman error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0); 29318316Swollman if (error) 29418316Swollman return error; 29518316Swollman 29618316Swollman /* 29718316Swollman * Now open the block special file. 29818316Swollman */ 29918316Swollman error = VOP_OPEN(devvp, ronly ? FREAD : FREAD | FWRITE, FSCRED, p); 30018316Swollman if (error) 30118316Swollman return error; 30218316Swollman needclose = 1; 30318316Swollman#ifdef HDSUPPORT 30418316Swollman /* 30518316Swollman * Put this in when we support reading dos filesystems from 30618316Swollman * partitioned harddisks. 30718316Swollman */ 30818316Swollman if (VOP_IOCTL(devvp, DIOCGPART, &msdosfspart, FREAD, NOCRED, p) == 0) { 30918316Swollman } 31018316Swollman#endif 31118316Swollman 31218316Swollman /* 31318316Swollman * Read the boot sector of the filesystem, and then check the boot 31418316Swollman * signature. If not a dos boot sector then error out. We could 31518316Swollman * also add some checking on the bsOemName field. So far I've seen 31618316Swollman * the following values: "IBM 3.3" "MSDOS3.3" "MSDOS5.0" 31718316Swollman */ 31818316Swollman#ifdef PC98 31918316Swollman devvp->v_flag &= 0xffff; 32018316Swollman error = bread(devvp, 0, 1024, NOCRED, &bp0); 32118316Swollman#else 32218316Swollman error = bread(devvp, 0, 512, NOCRED, &bp0); 32318316Swollman#endif 32418316Swollman if (error) 32518316Swollman goto error_exit; 32618316Swollman bp0->b_flags |= B_AGE; 32718316Swollman bsp = (union bootsector *) bp0->b_data; 32818316Swollman b33 = (struct byte_bpb33 *) bsp->bs33.bsBPB; 32918316Swollman b50 = (struct byte_bpb50 *) bsp->bs50.bsBPB; 33018316Swollman#ifdef MSDOSFS_CHECKSIG 33118316Swollman#ifdef PC98 33218316Swollman if (bsp->bs50.bsBootSectSig != BOOTSIG && 33318316Swollman bsp->bs50.bsBootSectSig != 0 && /* PC98 DOS 3.3x */ 33418316Swollman bsp->bs50.bsBootSectSig != 15760 && /* PC98 DOS 5.0 */ 33518316Swollman bsp->bs50.bsBootSectSig != 64070) { /* PC98 DOS 3.3B */ 33618316Swollman#else 33718316Swollman if (bsp->bs50.bsBootSectSig != BOOTSIG) { 33818316Swollman#endif 33918316Swollman error = EINVAL; 34018316Swollman goto error_exit; 34118316Swollman } 34218316Swollman#endif 34318316Swollman if ( bsp->bs50.bsJump[0] != 0xe9 && 34418316Swollman (bsp->bs50.bsJump[0] != 0xeb || bsp->bs50.bsJump[2] != 0x90)) { 34518316Swollman error = EINVAL; 34618316Swollman goto error_exit; 34718316Swollman } 34818316Swollman 34918316Swollman pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK); 35018316Swollman bzero((caddr_t)pmp, sizeof *pmp); 35118316Swollman pmp->pm_mountp = mp; 35218316Swollman 35318316Swollman /* 35418316Swollman * Compute several useful quantities from the bpb in the 35518316Swollman * bootsector. Copy in the dos 5 variant of the bpb then fix up 35618316Swollman * the fields that are different between dos 5 and dos 3.3. 35718316Swollman */ 35818316Swollman pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec); 35918316Swollman pmp->pm_SectPerClust = b50->bpbSecPerClust; 36018316Swollman pmp->pm_ResSectors = getushort(b50->bpbResSectors); 36118316Swollman pmp->pm_FATs = b50->bpbFATs; 36218316Swollman pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts); 36318316Swollman pmp->pm_Sectors = getushort(b50->bpbSectors); 36418316Swollman pmp->pm_Media = b50->bpbMedia; 36518316Swollman pmp->pm_FATsecs = getushort(b50->bpbFATsecs); 36618316Swollman pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack); 36718316Swollman pmp->pm_Heads = getushort(b50->bpbHeads); 36818316Swollman 36918316Swollman /* XXX - We should probably check more values here */ 37018316Swollman if (!pmp->pm_BytesPerSec || !pmp->pm_SectPerClust || 37118316Swollman !pmp->pm_Heads || pmp->pm_Heads > 255 || 37218316Swollman#ifdef PC98 37318316Swollman !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 255) { 37418316Swollman#else 37518316Swollman !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 63) { 37618316Swollman#endif 37718316Swollman error = EINVAL; 37818316Swollman goto error_exit; 37918316Swollman } 38018316Swollman 38118316Swollman if (pmp->pm_Sectors == 0) { 38218316Swollman pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs); 38318316Swollman pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors); 38418316Swollman } else { 38518316Swollman pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs); 38618316Swollman pmp->pm_HugeSectors = pmp->pm_Sectors; 38718316Swollman } 38818316Swollman#ifdef PC98 /* for PC98 added Satoshi Yasuda */ 38918316Swollman Phy_Sector_Size = 512; 39018316Swollman if ((devvp->v_rdev>>8) == 2) { /* floppy check */ 39118316Swollman if (((devvp->v_rdev&077) == 2) && (pmp->pm_HugeSectors == 1232)) { 39218316Swollman Phy_Sector_Size = 1024; /* 2HD */ 39318316Swollman /* 39418316Swollman * 1024byte/sector support 39518316Swollman */ 39618316Swollman devvp->v_flag |= 0x10000; 39718316Swollman } else { 39818316Swollman if ((((devvp->v_rdev&077) == 3) /* 2DD 8 or 9 sector */ 39918316Swollman && (pmp->pm_HugeSectors == 1440)) /* 9 sector */ 40018316Swollman || (((devvp->v_rdev&077) == 4) 40118316Swollman && (pmp->pm_HugeSectors == 1280)) /* 8 sector */ 40218316Swollman || (((devvp->v_rdev&077) == 5) 40318316Swollman && (pmp->pm_HugeSectors == 2880))) { /* 1.44M */ 40418316Swollman Phy_Sector_Size = 512; 40518316Swollman } else { 40618316Swollman if (((devvp->v_rdev&077) != 1) 40718316Swollman && ((devvp->v_rdev&077) != 0)) { /* 2HC */ 40818316Swollman error = EINVAL; 40918316Swollman goto error_exit; 41018316Swollman } 41118316Swollman } 41218316Swollman } 41318316Swollman } 41418316Swollman pc98_wrk = pmp->pm_BytesPerSec / Phy_Sector_Size; 41518316Swollman pmp->pm_BytesPerSec = Phy_Sector_Size; 41618316Swollman pmp->pm_SectPerClust = pmp->pm_SectPerClust * pc98_wrk; 41718316Swollman pmp->pm_HugeSectors = pmp->pm_HugeSectors * pc98_wrk; 41818316Swollman pmp->pm_ResSectors = pmp->pm_ResSectors * pc98_wrk; 41918316Swollman pmp->pm_FATsecs = pmp->pm_FATsecs * pc98_wrk; 42018316Swollman pmp->pm_SecPerTrack = pmp->pm_SecPerTrack * pc98_wrk; 42118316Swollman pmp->pm_HiddenSects = pmp->pm_HiddenSects * pc98_wrk; 42218316Swollman#endif /* */ 42318316Swollman pmp->pm_fatblk = pmp->pm_ResSectors; 42418316Swollman pmp->pm_rootdirblk = pmp->pm_fatblk + 42518316Swollman (pmp->pm_FATs * pmp->pm_FATsecs); 42618316Swollman pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry)) 42718316Swollman / 42818316Swollman pmp->pm_BytesPerSec;/* in sectors */ 42918316Swollman pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize; 43018316Swollman pmp->pm_nmbrofclusters = (pmp->pm_HugeSectors - pmp->pm_firstcluster) / 43118316Swollman pmp->pm_SectPerClust; 43218316Swollman pmp->pm_maxcluster = pmp->pm_nmbrofclusters + 1; 43318316Swollman pmp->pm_fatsize = pmp->pm_FATsecs * pmp->pm_BytesPerSec; 43418316Swollman if (FAT12(pmp)) 43518316Swollman /* 43618316Swollman * This will usually be a floppy disk. This size makes sure 43718316Swollman * that one fat entry will not be split across multiple 43818316Swollman * blocks. 43918316Swollman */ 44018316Swollman pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec; 44118316Swollman else 44218316Swollman /* 44318316Swollman * This will usually be a hard disk. Reading or writing one 44418316Swollman * block should be quite fast. 44518316Swollman */ 44618316Swollman pmp->pm_fatblocksize = MAXBSIZE; 44718316Swollman pmp->pm_fatblocksec = pmp->pm_fatblocksize / pmp->pm_BytesPerSec; 44818316Swollman 44918316Swollman 45018316Swollman if ((pmp->pm_rootdirsize % pmp->pm_SectPerClust) != 0) 45118316Swollman printf("mountmsdosfs(): Warning: root directory is not a multiple of the clustersize in length\n"); 45218316Swollman 45318316Swollman /* 45418316Swollman * Compute mask and shift value for isolating cluster relative byte 45518316Swollman * offsets and cluster numbers from a file offset. 45618316Swollman */ 45718316Swollman bpc = pmp->pm_SectPerClust * pmp->pm_BytesPerSec; 45818316Swollman pmp->pm_bpcluster = bpc; 45918316Swollman pmp->pm_depclust = bpc / sizeof(struct direntry); 46018316Swollman pmp->pm_crbomask = bpc - 1; 46118316Swollman if (bpc == 0) { 46218316Swollman error = EINVAL; 46318316Swollman goto error_exit; 46418316Swollman } 46518316Swollman bit = 1; 46618316Swollman for (i = 0; i < 32; i++) { 46718316Swollman if (bit & bpc) { 46818316Swollman if (bit ^ bpc) { 46918316Swollman error = EINVAL; 47018316Swollman goto error_exit; 47118316Swollman } 47218316Swollman pmp->pm_cnshift = i; 47318316Swollman break; 47418316Swollman } 47518316Swollman bit <<= 1; 47618316Swollman } 47718316Swollman 47818316Swollman#ifdef PC98 47918316Swollman if (Phy_Sector_Size == 512) { 48018316Swollman pmp->pm_brbomask = 0x01ff; /* 512 byte blocks only (so far) */ 48118316Swollman pmp->pm_bnshift = 9; /* shift right 9 bits to get bn */ 48218316Swollman } else { 48318316Swollman pmp->pm_brbomask = 0x03ff; 48418316Swollman pmp->pm_bnshift = 10; 48518316Swollman } 48618316Swollman#else 48718316Swollman pmp->pm_brbomask = 0x01ff; /* 512 byte blocks only (so far) */ 48818316Swollman pmp->pm_bnshift = 9; /* shift right 9 bits to get bn */ 48918316Swollman#endif 49018316Swollman 49118316Swollman /* 49218316Swollman * Release the bootsector buffer. 49318316Swollman */ 49418316Swollman brelse(bp0); 49518316Swollman bp0 = NULL; 49618316Swollman 49718316Swollman /* 49818316Swollman * Allocate memory for the bitmap of allocated clusters, and then 49918316Swollman * fill it in. 50018316Swollman */ 50118316Swollman pmp->pm_inusemap = malloc(((pmp->pm_maxcluster + N_INUSEBITS - 1) 50218316Swollman / N_INUSEBITS) 50318316Swollman * sizeof(*pmp->pm_inusemap), 50418316Swollman M_MSDOSFSFAT, M_WAITOK); 50518316Swollman 50618316Swollman /* 50718316Swollman * fillinusemap() needs pm_devvp. 50818316Swollman */ 50918316Swollman pmp->pm_dev = dev; 51018316Swollman pmp->pm_devvp = devvp; 51118316Swollman 51218316Swollman /* 51318316Swollman * Have the inuse map filled in. 51418316Swollman */ 51518316Swollman error = fillinusemap(pmp); 51618316Swollman if (error) 51718316Swollman goto error_exit; 51818316Swollman 51918316Swollman /* 52018316Swollman * If they want fat updates to be synchronous then let them suffer 52118316Swollman * the performance degradation in exchange for the on disk copy of 52218316Swollman * the fat being correct just about all the time. I suppose this 52318316Swollman * would be a good thing to turn on if the kernel is still flakey. 52418316Swollman */ 52518316Swollman pmp->pm_waitonfat = mp->mnt_flag & MNT_SYNCHRONOUS; 52618316Swollman 52718316Swollman /* 52818316Swollman * Finish up. 52918316Swollman */ 53018316Swollman pmp->pm_ronly = ronly; 53118316Swollman if (ronly == 0) 53218316Swollman pmp->pm_fmod = 1; 53318316Swollman mp->mnt_data = (qaddr_t) pmp; 53418316Swollman mp->mnt_stat.f_fsid.val[0] = (long)dev; 53518316Swollman mp->mnt_stat.f_fsid.val[1] = MOUNT_MSDOS; 53618316Swollman mp->mnt_flag |= MNT_LOCAL; 53718316Swollman devvp->v_specflags |= SI_MOUNTEDON; 53818316Swollman 53918316Swollman return 0; 54018316Swollman 54118316Swollmanerror_exit:; 54218316Swollman if (bp0) 54318316Swollman brelse(bp0); 54418316Swollman if (needclose) 54518316Swollman (void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD | FWRITE, 54618316Swollman NOCRED, p); 54718316Swollman if (pmp) { 54818316Swollman if (pmp->pm_inusemap) 54918316Swollman free((caddr_t) pmp->pm_inusemap, M_MSDOSFSFAT); 55018316Swollman free((caddr_t) pmp, M_MSDOSFSMNT); 55118316Swollman mp->mnt_data = (qaddr_t) 0; 55218316Swollman } 55318316Swollman return error; 55418316Swollman} 55518316Swollman 55618316Swollmanstatic int 55718316Swollmanmsdosfs_start(mp, flags, p) 55818316Swollman struct mount *mp; 55918316Swollman int flags; 56018316Swollman struct proc *p; 56118316Swollman{ 56218316Swollman return 0; 56318316Swollman} 56418316Swollman 56518316Swollman/* 56618316Swollman * Unmount the filesystem described by mp. 56718316Swollman */ 56818316Swollmanstatic int 56918316Swollmanmsdosfs_unmount(mp, mntflags, p) 57018316Swollman struct mount *mp; 57118316Swollman int mntflags; 57218316Swollman struct proc *p; 57318316Swollman{ 57418316Swollman int flags = 0; 57518316Swollman int error; 57618316Swollman struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data; 57718316Swollman 57818316Swollman /* only the mounter, or superuser can unmount */ 57918316Swollman if ((p->p_cred->p_ruid != pmp->pm_mounter) && 58018316Swollman (error = suser(p->p_ucred, &p->p_acflag))) 58118316Swollman return error; 58218316Swollman 58318316Swollman if (mntflags & MNT_FORCE) { 58418316Swollman if (!msdosfsdoforce) 58518316Swollman return EINVAL; 58618316Swollman flags |= FORCECLOSE; 58718316Swollman } 58818316Swollman error = vflush(mp, NULLVP, flags); 58918316Swollman if (error) 59018316Swollman return error; 59118316Swollman pmp->pm_devvp->v_specflags &= ~SI_MOUNTEDON; 59218316Swollman error = VOP_CLOSE(pmp->pm_devvp, pmp->pm_ronly ? FREAD : FREAD | FWRITE, 59318316Swollman NOCRED, p); 59418316Swollman vrele(pmp->pm_devvp); 59518316Swollman free((caddr_t) pmp->pm_inusemap, M_MSDOSFSFAT); 59618316Swollman free((caddr_t) pmp, M_MSDOSFSMNT); 59718316Swollman mp->mnt_data = (qaddr_t) 0; 59818316Swollman mp->mnt_flag &= ~MNT_LOCAL; 59918316Swollman return error; 60018316Swollman} 60118316Swollman 60218316Swollmanstatic int 60318316Swollmanmsdosfs_root(mp, vpp) 60418316Swollman struct mount *mp; 60518316Swollman struct vnode **vpp; 60618316Swollman{ 60718316Swollman struct denode *ndep; 60818316Swollman struct msdosfsmount *pmp = (struct msdosfsmount *) (mp->mnt_data); 60918316Swollman int error; 61018316Swollman 61118316Swollman error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, NULL, &ndep); 61218316Swollman#ifdef MSDOSFS_DEBUG 61318316Swollman printf("msdosfs_root(); mp %p, pmp %p, ndep %p, vp %p\n", 61418316Swollman mp, pmp, ndep, DETOV(ndep)); 61518316Swollman#endif 61618316Swollman if (error == 0) 61718316Swollman *vpp = DETOV(ndep); 61818316Swollman return error; 61918316Swollman} 62018316Swollman 62118316Swollmanstatic int 62218316Swollmanmsdosfs_quotactl(mp, cmds, uid, arg, p) 62318316Swollman struct mount *mp; 62418316Swollman int cmds; 62518316Swollman uid_t uid; 62618316Swollman caddr_t arg; 62718316Swollman struct proc *p; 62818316Swollman{ 62918316Swollman return EOPNOTSUPP; 63018316Swollman} 631 632static int 633msdosfs_statfs(mp, sbp, p) 634 struct mount *mp; 635 struct statfs *sbp; 636 struct proc *p; 637{ 638 struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data; 639 640 /* 641 * Fill in the stat block. 642 */ 643 sbp->f_type = MOUNT_MSDOS; 644 sbp->f_bsize = pmp->pm_bpcluster; 645 sbp->f_iosize = pmp->pm_bpcluster; 646 sbp->f_blocks = pmp->pm_nmbrofclusters; 647 sbp->f_bfree = pmp->pm_freeclustercount; 648 sbp->f_bavail = pmp->pm_freeclustercount; 649 sbp->f_files = pmp->pm_RootDirEnts; /* XXX */ 650 sbp->f_ffree = 0; /* what to put in here? */ 651 652 /* 653 * Copy the mounted on and mounted from names into the passed in 654 * stat block, if it is not the one in the mount structure. 655 */ 656 if (sbp != &mp->mnt_stat) { 657 bcopy((caddr_t) mp->mnt_stat.f_mntonname, 658 (caddr_t) & sbp->f_mntonname[0], MNAMELEN); 659 bcopy((caddr_t) mp->mnt_stat.f_mntfromname, 660 (caddr_t) & sbp->f_mntfromname[0], MNAMELEN); 661 } 662#if 0 663 strncpy(&sbp->f_fstypename[0], mp->mnt_op->vfs_name, MFSNAMELEN); 664 sbp->f_fstypename[MFSNAMELEN] = '\0'; 665#endif 666 return 0; 667} 668 669static int 670msdosfs_sync(mp, waitfor, cred, p) 671 struct mount *mp; 672 int waitfor; 673 struct ucred *cred; 674 struct proc *p; 675{ 676 struct vnode *vp; 677 struct denode *dep; 678 struct msdosfsmount *pmp; 679 int error; 680 int allerror = 0; 681 682 pmp = (struct msdosfsmount *) mp->mnt_data; 683 684 /* 685 * If we ever switch to not updating all of the fats all the time, 686 * this would be the place to update them from the first one. 687 */ 688 if (pmp->pm_fmod) 689 if (pmp->pm_ronly) 690 panic("msdosfs_sync: rofs mod"); 691 else { 692 /* update fats here */ 693 } 694 695 /* 696 * Go thru in memory denodes and write them out along with 697 * unwritten file blocks. 698 */ 699loop: 700 for (vp = mp->mnt_vnodelist.lh_first; vp; 701 vp = vp->v_mntvnodes.le_next) { 702 if (vp->v_mount != mp) /* not ours anymore */ 703 goto loop; 704 if (VOP_ISLOCKED(vp)) /* file is busy */ 705 continue; 706 dep = VTODE(vp); 707 if ((dep->de_flag & (DE_MODIFIED | DE_UPDATE)) == 0 && 708 vp->v_dirtyblkhd.lh_first == NULL) 709 continue; 710 if (vget(vp, 1)) /* not there anymore? */ 711 goto loop; 712 error = VOP_FSYNC(vp, cred, waitfor, p); 713 if (error) 714 allerror = error; 715 vput(vp); /* done with this one */ 716 } 717 718 /* 719 * Flush filesystem control info. 720 */ 721 error = VOP_FSYNC(pmp->pm_devvp, cred, waitfor, p); 722 if (error) 723 allerror = error; 724 return allerror; 725} 726 727static int 728msdosfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp) 729 struct mount *mp; 730 struct fid *fhp; 731 struct mbuf *nam; 732 struct vnode **vpp; 733 int *exflagsp; 734 struct ucred **credanonp; 735{ 736 struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data; 737 struct defid *defhp = (struct defid *) fhp; 738 struct denode *dep; 739 struct netcred *np; 740 int error; 741 742 np = vfs_export_lookup(mp, &pmp->pm_export, nam); 743 if (np == NULL) 744 return EACCES; 745 error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs, 746 NULL, &dep); 747 if (error) { 748 *vpp = NULLVP; 749 return error; 750 } 751 *vpp = DETOV(dep); 752 *exflagsp = np->netc_exflags; 753 *credanonp = &np->netc_anon; 754 return 0; 755} 756 757 758static int 759msdosfs_vptofh(vp, fhp) 760 struct vnode *vp; 761 struct fid *fhp; 762{ 763 struct denode *dep = VTODE(vp); 764 struct defid *defhp = (struct defid *) fhp; 765 766 defhp->defid_len = sizeof(struct defid); 767 defhp->defid_dirclust = dep->de_dirclust; 768 defhp->defid_dirofs = dep->de_diroffset; 769 /* defhp->defid_gen = ip->i_gen; */ 770 return 0; 771} 772 773static int 774msdosfs_vget(mp, ino, vpp) 775 struct mount *mp; 776 ino_t ino; 777 struct vnode **vpp; 778{ 779 return EOPNOTSUPP; 780} 781 782static struct vfsops msdosfs_vfsops = { 783 msdosfs_mount, 784 msdosfs_start, 785 msdosfs_unmount, 786 msdosfs_root, 787 msdosfs_quotactl, 788 msdosfs_statfs, 789 msdosfs_sync, 790 msdosfs_vget, 791 msdosfs_fhtovp, 792 msdosfs_vptofh, 793 msdosfs_init 794}; 795 796VFS_SET(msdosfs_vfsops, msdos, MOUNT_MSDOS, 0); 797