msdosfs_vfsops.c revision 30309
1219820Sjeff/* $Id: msdosfs_vfsops.c,v 1.20 1997/08/16 19:15:24 wollman Exp $ */ 2272027Shselasky/* $NetBSD: msdosfs_vfsops.c,v 1.19 1994/08/21 18:44:10 ws Exp $ */ 3219820Sjeff 4219820Sjeff/*- 5219820Sjeff * Copyright (C) 1994 Wolfgang Solfrank. 6219820Sjeff * Copyright (C) 1994 TooLs GmbH. 7219820Sjeff * All rights reserved. 8219820Sjeff * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). 9219820Sjeff * 10219820Sjeff * Redistribution and use in source and binary forms, with or without 11219820Sjeff * modification, are permitted provided that the following conditions 12219820Sjeff * are met: 13219820Sjeff * 1. Redistributions of source code must retain the above copyright 14219820Sjeff * notice, this list of conditions and the following disclaimer. 15219820Sjeff * 2. Redistributions in binary form must reproduce the above copyright 16219820Sjeff * notice, this list of conditions and the following disclaimer in the 17219820Sjeff * documentation and/or other materials provided with the distribution. 18219820Sjeff * 3. All advertising materials mentioning features or use of this software 19219820Sjeff * must display the following acknowledgement: 20219820Sjeff * This product includes software developed by TooLs GmbH. 21219820Sjeff * 4. The name of TooLs GmbH may not be used to endorse or promote products 22219820Sjeff * derived from this software without specific prior written permission. 23219820Sjeff * 24219820Sjeff * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 25219820Sjeff * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 26219820Sjeff * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 27219820Sjeff * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28219820Sjeff * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 29219820Sjeff * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 30219820Sjeff * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 31219820Sjeff * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 32219820Sjeff * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 33300676Shselasky * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34300676Shselasky */ 35219820Sjeff/* 36219820Sjeff * Written by Paul Popelka (paulp@uts.amdahl.com) 37272027Shselasky * 38272027Shselasky * You can do anything you want with this software, just don't say you wrote 39219820Sjeff * it, and don't remove this notice. 40306486Shselasky * 41255932Salfred * This software is provided "as is". 42219820Sjeff * 43306486Shselasky * The author supplies this software to be publicly redistributed on the 44219820Sjeff * understanding that the author is not responsible for the correct 45272027Shselasky * functioning of this software in any circumstances and is not liable for 46255932Salfred * any damages caused by this software. 47255932Salfred * 48255932Salfred * October 1992 49255932Salfred */ 50219820Sjeff 51255932Salfred#include <sys/param.h> 52219820Sjeff#include <sys/systm.h> 53219820Sjeff#include <sys/namei.h> 54219820Sjeff#include <sys/proc.h> 55219820Sjeff#include <sys/kernel.h> 56219820Sjeff#include <sys/vnode.h> 57219820Sjeff#include <miscfs/specfs/specdev.h> /* XXX */ /* defines v_rdev */ 58219820Sjeff#include <sys/mount.h> 59219820Sjeff#include <sys/buf.h> 60219820Sjeff#include <sys/fcntl.h> 61219820Sjeff#include <sys/malloc.h> 62219820Sjeff 63219820Sjeff#include <msdosfs/bpb.h> 64219820Sjeff#include <msdosfs/bootsect.h> 65219820Sjeff#include <msdosfs/direntry.h> 66219820Sjeff#include <msdosfs/denode.h> 67219820Sjeff#include <msdosfs/msdosfsmount.h> 68219820Sjeff#include <msdosfs/fat.h> 69219820Sjeff 70219820SjeffMALLOC_DEFINE(M_MSDOSFSFAT, "MSDOSFS FAT", "MSDOSFS file allocation table"); 71219820Sjeff 72219820Sjeffstatic int mountmsdosfs __P((struct vnode *devvp, struct mount *mp, 73219820Sjeff struct proc *p)); 74219820Sjeffstatic int msdosfs_fhtovp __P((struct mount *, struct fid *, 75219820Sjeff struct sockaddr *, struct vnode **, int *, 76219820Sjeff struct ucred **)); 77219820Sjeffstatic int msdosfs_mount __P((struct mount *, char *, caddr_t, 78219820Sjeff struct nameidata *, struct proc *)); 79255932Salfredstatic int msdosfs_quotactl __P((struct mount *, int, uid_t, caddr_t, 80219820Sjeff struct proc *)); 81219820Sjeffstatic int msdosfs_root __P((struct mount *, struct vnode **)); 82219820Sjeffstatic int msdosfs_start __P((struct mount *, int, struct proc *)); 83255932Salfredstatic int msdosfs_statfs __P((struct mount *, struct statfs *, 84255932Salfred struct proc *)); 85255932Salfredstatic int msdosfs_sync __P((struct mount *, int, struct ucred *, 86255932Salfred struct proc *)); 87255932Salfredstatic int msdosfs_unmount __P((struct mount *, int, struct proc *)); 88272027Shselaskystatic int msdosfs_vget __P((struct mount *mp, ino_t ino, 89255932Salfred struct vnode **vpp)); 90255932Salfredstatic int msdosfs_vptofh __P((struct vnode *, struct fid *)); 91255932Salfred 92255932Salfred/* 93255932Salfred * mp - path - addr in user space of mount point (ie /usr or whatever) 94255932Salfred * data - addr in user space of mount params including the name of the block 95255932Salfred * special file to treat as a filesystem. 96255932Salfred */ 97255932Salfredstatic int 98255932Salfredmsdosfs_mount(mp, path, data, ndp, p) 99255932Salfred struct mount *mp; 100255932Salfred char *path; 101255932Salfred caddr_t data; 102255932Salfred struct nameidata *ndp; 103255932Salfred struct proc *p; 104255932Salfred{ 105255932Salfred struct vnode *devvp; /* vnode for blk device to mount */ 106255932Salfred struct msdosfs_args args; /* will hold data from mount request */ 107255932Salfred struct msdosfsmount *pmp; /* msdosfs specific mount control block */ 108255932Salfred int error, flags; 109219820Sjeff u_int size; 110219820Sjeff struct ucred *cred, *scred; 111219820Sjeff struct vattr va; 112219820Sjeff 113219820Sjeff /* 114219820Sjeff * Copy in the args for the mount request. 115219820Sjeff */ 116219820Sjeff error = copyin(data, (caddr_t) & args, sizeof(struct msdosfs_args)); 117219820Sjeff if (error) 118219820Sjeff return error; 119219820Sjeff 120219820Sjeff /* 121219820Sjeff * If they just want to update then be sure we can do what is 122219820Sjeff * asked. Can't change a filesystem from read/write to read only. 123255932Salfred * Why? And if they've supplied a new device file name then we 124219820Sjeff * continue, otherwise return. 125255932Salfred */ 126219820Sjeff if (mp->mnt_flag & MNT_UPDATE) { 127219820Sjeff pmp = (struct msdosfsmount *) mp->mnt_data; 128219820Sjeff error = 0; 129219820Sjeff if (pmp->pm_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) { 130219820Sjeff flags = WRITECLOSE; 131255932Salfred if (mp->mnt_flag & MNT_FORCE) 132219820Sjeff flags |= FORCECLOSE; 133255932Salfred error = vflush(mp, NULLVP, flags); 134255932Salfred } 135219820Sjeff if (!error && (mp->mnt_flag & MNT_RELOAD)) 136219820Sjeff /* not yet implemented */ 137219820Sjeff error = EINVAL; 138255932Salfred if (error) 139255932Salfred return error; 140255932Salfred if (pmp->pm_ronly && (mp->mnt_flag & MNT_WANTRDWR)) 141219820Sjeff pmp->pm_ronly = 0; 142255932Salfred if (args.fspec == 0) { 143272027Shselasky /* 144219820Sjeff * Process export requests. 145219820Sjeff */ 146219820Sjeff return vfs_export(mp, &pmp->pm_export, &args.export); 147219820Sjeff } 148272027Shselasky } else 149272027Shselasky pmp = NULL; 150255932Salfred 151272027Shselasky /* 152219820Sjeff * check to see that the user in owns the target directory. 153219820Sjeff * Note the very XXX trick to make sure we're checking as the 154219820Sjeff * real user -- were mount() executable by anyone, this wouldn't 155219820Sjeff * be a problem. 156219820Sjeff * 157219820Sjeff * XXX there should be one consistent error out. 158219820Sjeff */ 159219820Sjeff cred = crdup(p->p_ucred); /* XXX */ 160219820Sjeff cred->cr_uid = p->p_cred->p_ruid; /* XXX */ 161219820Sjeff error = VOP_GETATTR(mp->mnt_vnodecovered, &va, cred, p); 162219820Sjeff if (error) { 163219820Sjeff crfree(cred); /* XXX */ 164219820Sjeff return error; 165219820Sjeff } 166219820Sjeff if (cred->cr_uid != 0) { 167219820Sjeff if (va.va_uid != cred->cr_uid) { 168219820Sjeff error = EACCES; 169219820Sjeff crfree(cred); /* XXX */ 170255932Salfred return error; 171255932Salfred } 172219820Sjeff 173219820Sjeff /* a user mounted it; we'll verify permissions when unmounting */ 174219820Sjeff mp->mnt_flag |= MNT_USER; 175255932Salfred } 176219820Sjeff 177255932Salfred /* 178219820Sjeff * Now, lookup the name of the block device this mount or name 179219820Sjeff * update request is to apply to. 180219820Sjeff */ 181219820Sjeff NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p); 182219820Sjeff scred = p->p_ucred; /* XXX */ 183255932Salfred p->p_ucred = cred; /* XXX */ 184255932Salfred error = namei(ndp); 185255932Salfred p->p_ucred = scred; /* XXX */ 186255932Salfred crfree(cred); /* XXX */ 187255932Salfred if (error != 0) 188272027Shselasky return error; 189255932Salfred 190255932Salfred /* 191272027Shselasky * Be sure they've given us a block device to treat as a 192272027Shselasky * filesystem. And, that its major number is within the bdevsw 193272027Shselasky * table. 194272027Shselasky */ 195272027Shselasky devvp = ndp->ni_vp; 196272027Shselasky if (devvp->v_type != VBLK) { 197272027Shselasky vrele(devvp); 198272027Shselasky return ENOTBLK; 199272027Shselasky } 200272027Shselasky if (major(devvp->v_rdev) >= nblkdev) { 201272027Shselasky vrele(devvp); 202272027Shselasky return ENXIO; 203272027Shselasky } 204272027Shselasky 205272027Shselasky /* 206255932Salfred * If this is an update, then make sure the vnode for the block 207255932Salfred * special device is the same as the one our filesystem is in. 208255932Salfred */ 209255932Salfred if (mp->mnt_flag & MNT_UPDATE) { 210255932Salfred if (devvp != pmp->pm_devvp) 211255932Salfred error = EINVAL; 212255932Salfred else 213219820Sjeff vrele(devvp); 214219820Sjeff } else { 215255932Salfred 216219820Sjeff /* 217255932Salfred * Well, it's not an update, it's a real mount request. 218255932Salfred * Time to get dirty. 219255932Salfred */ 220255932Salfred error = mountmsdosfs(devvp, mp, p); 221219820Sjeff } 222255932Salfred if (error) { 223255932Salfred vrele(devvp); 224255932Salfred return error; 225255932Salfred } 226255932Salfred 227255932Salfred /* 228255932Salfred * Copy in the name of the directory the filesystem is to be 229255932Salfred * mounted on. Then copy in the name of the block special file 230255932Salfred * representing the filesystem being mounted. And we clear the 231255932Salfred * remainder of the character strings to be tidy. Set up the 232255932Salfred * user id/group id/mask as specified by the user. Then, we try to 233255932Salfred * fill in the filesystem stats structure as best we can with 234219820Sjeff * whatever applies from a dos file system. 235255932Salfred */ 236255932Salfred pmp = (struct msdosfsmount *) mp->mnt_data; 237255932Salfred copyinstr(path, (caddr_t) mp->mnt_stat.f_mntonname, 238255932Salfred sizeof(mp->mnt_stat.f_mntonname) - 1, &size); 239219820Sjeff bzero(mp->mnt_stat.f_mntonname + size, 240255932Salfred sizeof(mp->mnt_stat.f_mntonname) - size); 241219820Sjeff copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size); 242255932Salfred bzero(mp->mnt_stat.f_mntfromname + size, 243255932Salfred MNAMELEN - size); 244219820Sjeff pmp->pm_mounter = p->p_cred->p_ruid; 245219820Sjeff pmp->pm_gid = args.gid; 246255932Salfred pmp->pm_uid = args.uid; 247219820Sjeff pmp->pm_mask = args.mask; 248219820Sjeff (void) msdosfs_statfs(mp, &mp->mnt_stat, p); 249219820Sjeff#ifdef MSDOSFS_DEBUG 250219820Sjeff printf("msdosfs_mount(): mp %p, pmp %p, inusemap %p\n", mp, pmp, pmp->pm_inusemap); 251219820Sjeff#endif 252219820Sjeff return 0; 253255932Salfred} 254255932Salfred 255255932Salfredstatic int 256255932Salfredmountmsdosfs(devvp, mp, p) 257255932Salfred struct vnode *devvp; 258255932Salfred struct mount *mp; 259255932Salfred struct proc *p; 260272027Shselasky{ 261272027Shselasky int i; 262272027Shselasky int bpc; 263272027Shselasky int bit; 264272027Shselasky int error; 265272027Shselasky int needclose; 266272027Shselasky int ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 267272027Shselasky dev_t dev = devvp->v_rdev; 268272027Shselasky union bootsector *bsp; 269272027Shselasky struct msdosfsmount *pmp = NULL; 270272027Shselasky struct buf *bp0 = NULL; 271272027Shselasky struct byte_bpb33 *b33; 272255932Salfred struct byte_bpb50 *b50; 273255932Salfred#ifdef PC98 274255932Salfred u_int pc98_wrk; 275255932Salfred u_int Phy_Sector_Size; 276255932Salfred#endif 277219820Sjeff 278219820Sjeff /* 279255932Salfred * Multiple mounts of the same block special file aren't allowed. 280255932Salfred * Make sure no one else has the special file open. And flush any 281255932Salfred * old buffers from this filesystem. Presumably this prevents us 282255932Salfred * from running into buffers that are the wrong blocksize. 283255932Salfred */ 284255932Salfred error = vfs_mountedon(devvp); 285255932Salfred if (error) 286255932Salfred return error; 287255932Salfred if (vcount(devvp) > 1) 288255932Salfred return EBUSY; 289255932Salfred error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0); 290255932Salfred if (error) 291255932Salfred return error; 292255932Salfred 293255932Salfred /* 294255932Salfred * Now open the block special file. 295255932Salfred */ 296255932Salfred error = VOP_OPEN(devvp, ronly ? FREAD : FREAD | FWRITE, FSCRED, p); 297255932Salfred if (error) 298255932Salfred return error; 299255932Salfred needclose = 1; 300255932Salfred#ifdef HDSUPPORT 301255932Salfred /* 302255932Salfred * Put this in when we support reading dos filesystems from 303255932Salfred * partitioned harddisks. 304255932Salfred */ 305255932Salfred if (VOP_IOCTL(devvp, DIOCGPART, &msdosfspart, FREAD, NOCRED, p) == 0) { 306255932Salfred } 307219820Sjeff#endif 308219820Sjeff 309219820Sjeff /* 310219820Sjeff * Read the boot sector of the filesystem, and then check the boot 311219820Sjeff * signature. If not a dos boot sector then error out. We could 312219820Sjeff * also add some checking on the bsOemName field. So far I've seen 313219820Sjeff * the following values: "IBM 3.3" "MSDOS3.3" "MSDOS5.0" 314219820Sjeff */ 315219820Sjeff#ifdef PC98 316219820Sjeff devvp->v_flag &= 0xffff; 317219820Sjeff error = bread(devvp, 0, 1024, NOCRED, &bp0); 318219820Sjeff#else 319219820Sjeff error = bread(devvp, 0, 512, NOCRED, &bp0); 320219820Sjeff#endif 321255932Salfred if (error) 322219820Sjeff goto error_exit; 323219820Sjeff bp0->b_flags |= B_AGE; 324219820Sjeff bsp = (union bootsector *) bp0->b_data; 325219820Sjeff b33 = (struct byte_bpb33 *) bsp->bs33.bsBPB; 326219820Sjeff b50 = (struct byte_bpb50 *) bsp->bs50.bsBPB; 327219820Sjeff#ifdef MSDOSFS_CHECKSIG 328219820Sjeff#ifdef PC98 329219820Sjeff if (bsp->bs50.bsBootSectSig != BOOTSIG && 330219820Sjeff bsp->bs50.bsBootSectSig != 0 && /* PC98 DOS 3.3x */ 331219820Sjeff bsp->bs50.bsBootSectSig != 15760 && /* PC98 DOS 5.0 */ 332219820Sjeff bsp->bs50.bsBootSectSig != 64070) { /* PC98 DOS 3.3B */ 333219820Sjeff#else 334219820Sjeff if (bsp->bs50.bsBootSectSig != BOOTSIG) { 335219820Sjeff#endif 336219820Sjeff error = EINVAL; 337255932Salfred goto error_exit; 338219820Sjeff } 339219820Sjeff#endif 340219820Sjeff if ( bsp->bs50.bsJump[0] != 0xe9 && 341219820Sjeff (bsp->bs50.bsJump[0] != 0xeb || bsp->bs50.bsJump[2] != 0x90)) { 342219820Sjeff error = EINVAL; 343219820Sjeff goto error_exit; 344219820Sjeff } 345219820Sjeff 346219820Sjeff pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK); 347255932Salfred bzero((caddr_t)pmp, sizeof *pmp); 348255932Salfred pmp->pm_mountp = mp; 349219820Sjeff 350219820Sjeff /* 351219820Sjeff * Compute several useful quantities from the bpb in the 352219820Sjeff * bootsector. Copy in the dos 5 variant of the bpb then fix up 353219820Sjeff * the fields that are different between dos 5 and dos 3.3. 354219820Sjeff */ 355255932Salfred pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec); 356255932Salfred pmp->pm_SectPerClust = b50->bpbSecPerClust; 357255932Salfred pmp->pm_ResSectors = getushort(b50->bpbResSectors); 358255932Salfred pmp->pm_FATs = b50->bpbFATs; 359255932Salfred pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts); 360255932Salfred pmp->pm_Sectors = getushort(b50->bpbSectors); 361255932Salfred pmp->pm_Media = b50->bpbMedia; 362219820Sjeff pmp->pm_FATsecs = getushort(b50->bpbFATsecs); 363219820Sjeff pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack); 364219820Sjeff pmp->pm_Heads = getushort(b50->bpbHeads); 365219820Sjeff 366219820Sjeff /* XXX - We should probably check more values here */ 367219820Sjeff if (!pmp->pm_BytesPerSec || !pmp->pm_SectPerClust || 368219820Sjeff !pmp->pm_Heads || pmp->pm_Heads > 255 || 369219820Sjeff#ifdef PC98 370219820Sjeff !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 255) { 371255932Salfred#else 372219820Sjeff !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 63) { 373219820Sjeff#endif 374219820Sjeff error = EINVAL; 375219820Sjeff goto error_exit; 376219820Sjeff } 377219820Sjeff 378219820Sjeff if (pmp->pm_Sectors == 0) { 379219820Sjeff pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs); 380219820Sjeff pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors); 381219820Sjeff } else { 382219820Sjeff pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs); 383255932Salfred pmp->pm_HugeSectors = pmp->pm_Sectors; 384219820Sjeff } 385219820Sjeff#ifdef PC98 /* for PC98 added Satoshi Yasuda */ 386219820Sjeff Phy_Sector_Size = 512; 387219820Sjeff if ((devvp->v_rdev>>8) == 2) { /* floppy check */ 388219820Sjeff if (((devvp->v_rdev&077) == 2) && (pmp->pm_HugeSectors == 1232)) { 389219820Sjeff Phy_Sector_Size = 1024; /* 2HD */ 390219820Sjeff /* 391219820Sjeff * 1024byte/sector support 392219820Sjeff */ 393219820Sjeff devvp->v_flag |= 0x10000; 394219820Sjeff } else { 395219820Sjeff if ((((devvp->v_rdev&077) == 3) /* 2DD 8 or 9 sector */ 396219820Sjeff && (pmp->pm_HugeSectors == 1440)) /* 9 sector */ 397219820Sjeff || (((devvp->v_rdev&077) == 4) 398219820Sjeff && (pmp->pm_HugeSectors == 1280)) /* 8 sector */ 399219820Sjeff || (((devvp->v_rdev&077) == 5) 400219820Sjeff && (pmp->pm_HugeSectors == 2880))) { /* 1.44M */ 401255932Salfred Phy_Sector_Size = 512; 402255932Salfred } else { 403255932Salfred if (((devvp->v_rdev&077) != 1) 404255932Salfred && ((devvp->v_rdev&077) != 0)) { /* 2HC */ 405255932Salfred error = EINVAL; 406255932Salfred goto error_exit; 407255932Salfred } 408255932Salfred } 409255932Salfred } 410255932Salfred } 411255932Salfred pc98_wrk = pmp->pm_BytesPerSec / Phy_Sector_Size; 412255932Salfred pmp->pm_BytesPerSec = Phy_Sector_Size; 413255932Salfred pmp->pm_SectPerClust = pmp->pm_SectPerClust * pc98_wrk; 414255932Salfred pmp->pm_HugeSectors = pmp->pm_HugeSectors * pc98_wrk; 415255932Salfred pmp->pm_ResSectors = pmp->pm_ResSectors * pc98_wrk; 416255932Salfred pmp->pm_FATsecs = pmp->pm_FATsecs * pc98_wrk; 417255932Salfred pmp->pm_SecPerTrack = pmp->pm_SecPerTrack * pc98_wrk; 418255932Salfred pmp->pm_HiddenSects = pmp->pm_HiddenSects * pc98_wrk; 419255932Salfred#endif /* */ 420255932Salfred pmp->pm_fatblk = pmp->pm_ResSectors; 421255932Salfred pmp->pm_rootdirblk = pmp->pm_fatblk + 422219820Sjeff (pmp->pm_FATs * pmp->pm_FATsecs); 423219820Sjeff pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry)) 424255932Salfred / 425219820Sjeff pmp->pm_BytesPerSec;/* in sectors */ 426219820Sjeff pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize; 427255932Salfred pmp->pm_nmbrofclusters = (pmp->pm_HugeSectors - pmp->pm_firstcluster) / 428219820Sjeff pmp->pm_SectPerClust; 429255932Salfred pmp->pm_maxcluster = pmp->pm_nmbrofclusters + 1; 430255932Salfred pmp->pm_fatsize = pmp->pm_FATsecs * pmp->pm_BytesPerSec; 431255932Salfred if (FAT12(pmp)) 432255932Salfred /* 433255932Salfred * This will usually be a floppy disk. This size makes sure 434255932Salfred * that one fat entry will not be split across multiple 435219820Sjeff * blocks. 436219820Sjeff */ 437255932Salfred pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec; 438219820Sjeff else 439219820Sjeff /* 440219820Sjeff * This will usually be a hard disk. Reading or writing one 441255932Salfred * block should be quite fast. 442255932Salfred */ 443255932Salfred pmp->pm_fatblocksize = MAXBSIZE; 444219820Sjeff pmp->pm_fatblocksec = pmp->pm_fatblocksize / pmp->pm_BytesPerSec; 445219820Sjeff 446219820Sjeff 447219820Sjeff if ((pmp->pm_rootdirsize % pmp->pm_SectPerClust) != 0) 448219820Sjeff printf("mountmsdosfs(): Warning: root directory is not a multiple of the clustersize in length\n"); 449219820Sjeff 450219820Sjeff /* 451219820Sjeff * Compute mask and shift value for isolating cluster relative byte 452255932Salfred * offsets and cluster numbers from a file offset. 453255932Salfred */ 454255932Salfred bpc = pmp->pm_SectPerClust * pmp->pm_BytesPerSec; 455255932Salfred pmp->pm_bpcluster = bpc; 456255932Salfred pmp->pm_depclust = bpc / sizeof(struct direntry); 457255932Salfred pmp->pm_crbomask = bpc - 1; 458255932Salfred if (bpc == 0) { 459255932Salfred error = EINVAL; 460255932Salfred goto error_exit; 461255932Salfred } 462255932Salfred bit = 1; 463255932Salfred for (i = 0; i < 32; i++) { 464255932Salfred if (bit & bpc) { 465255932Salfred if (bit ^ bpc) { 466255932Salfred error = EINVAL; 467219820Sjeff goto error_exit; 468219820Sjeff } 469219820Sjeff pmp->pm_cnshift = i; 470219820Sjeff break; 471219820Sjeff } 472219820Sjeff bit <<= 1; 473219820Sjeff } 474219820Sjeff 475219820Sjeff#ifdef PC98 476219820Sjeff if (Phy_Sector_Size == 512) { 477219820Sjeff pmp->pm_brbomask = 0x01ff; /* 512 byte blocks only (so far) */ 478219820Sjeff pmp->pm_bnshift = 9; /* shift right 9 bits to get bn */ 479219820Sjeff } else { 480219820Sjeff pmp->pm_brbomask = 0x03ff; 481219820Sjeff pmp->pm_bnshift = 10; 482219820Sjeff } 483219820Sjeff#else 484219820Sjeff pmp->pm_brbomask = 0x01ff; /* 512 byte blocks only (so far) */ 485219820Sjeff pmp->pm_bnshift = 9; /* shift right 9 bits to get bn */ 486219820Sjeff#endif 487219820Sjeff 488219820Sjeff /* 489219820Sjeff * Release the bootsector buffer. 490219820Sjeff */ 491219820Sjeff brelse(bp0); 492219820Sjeff bp0 = NULL; 493219820Sjeff 494219820Sjeff /* 495219820Sjeff * Allocate memory for the bitmap of allocated clusters, and then 496219820Sjeff * fill it in. 497255932Salfred */ 498255932Salfred pmp->pm_inusemap = malloc(((pmp->pm_maxcluster + N_INUSEBITS - 1) 499219820Sjeff / N_INUSEBITS) 500219820Sjeff * sizeof(*pmp->pm_inusemap), 501219820Sjeff M_MSDOSFSFAT, M_WAITOK); 502219820Sjeff 503219820Sjeff /* 504219820Sjeff * fillinusemap() needs pm_devvp. 505255932Salfred */ 506219820Sjeff pmp->pm_dev = dev; 507255932Salfred pmp->pm_devvp = devvp; 508219820Sjeff 509255932Salfred /* 510255932Salfred * Have the inuse map filled in. 511255932Salfred */ 512255932Salfred error = fillinusemap(pmp); 513255932Salfred if (error) 514255932Salfred goto error_exit; 515255932Salfred 516255932Salfred /* 517255932Salfred * If they want fat updates to be synchronous then let them suffer 518255932Salfred * the performance degradation in exchange for the on disk copy of 519255932Salfred * the fat being correct just about all the time. I suppose this 520255932Salfred * would be a good thing to turn on if the kernel is still flakey. 521255932Salfred */ 522255932Salfred pmp->pm_waitonfat = mp->mnt_flag & MNT_SYNCHRONOUS; 523255932Salfred 524255932Salfred /* 525255932Salfred * Finish up. 526255932Salfred */ 527255932Salfred pmp->pm_ronly = ronly; 528255932Salfred if (ronly == 0) 529255932Salfred pmp->pm_fmod = 1; 530255932Salfred mp->mnt_data = (qaddr_t) pmp; 531255932Salfred mp->mnt_stat.f_fsid.val[0] = (long)dev; 532255932Salfred mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; 533255932Salfred mp->mnt_flag |= MNT_LOCAL; 534255932Salfred devvp->v_specflags |= SI_MOUNTEDON; 535255932Salfred 536255932Salfred return 0; 537255932Salfred 538255932Salfrederror_exit:; 539255932Salfred if (bp0) 540255932Salfred brelse(bp0); 541255932Salfred if (needclose) 542255932Salfred (void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD | FWRITE, 543255932Salfred NOCRED, p); 544255932Salfred if (pmp) { 545255932Salfred if (pmp->pm_inusemap) 546255932Salfred free((caddr_t) pmp->pm_inusemap, M_MSDOSFSFAT); 547255932Salfred free((caddr_t) pmp, M_MSDOSFSMNT); 548255932Salfred mp->mnt_data = (qaddr_t) 0; 549255932Salfred } 550219820Sjeff return error; 551255932Salfred} 552255932Salfred 553255932Salfredstatic int 554255932Salfredmsdosfs_start(mp, flags, p) 555255932Salfred struct mount *mp; 556219820Sjeff int flags; 557255932Salfred struct proc *p; 558272027Shselasky{ 559255932Salfred return 0; 560255932Salfred} 561255932Salfred 562272027Shselasky/* 563272027Shselasky * Unmount the filesystem described by mp. 564272027Shselasky */ 565255932Salfredstatic int 566255932Salfredmsdosfs_unmount(mp, mntflags, p) 567255932Salfred struct mount *mp; 568255932Salfred int mntflags; 569255932Salfred struct proc *p; 570272027Shselasky{ 571272027Shselasky int flags = 0; 572272027Shselasky int error; 573255932Salfred struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data; 574255932Salfred 575255932Salfred /* only the mounter, or superuser can unmount */ 576255932Salfred if ((p->p_cred->p_ruid != pmp->pm_mounter) && 577255932Salfred (error = suser(p->p_ucred, &p->p_acflag))) 578255932Salfred return error; 579255932Salfred 580255932Salfred if (mntflags & MNT_FORCE) { 581255932Salfred flags |= FORCECLOSE; 582255932Salfred } 583255932Salfred error = vflush(mp, NULLVP, flags); 584255932Salfred if (error) 585255932Salfred return error; 586255932Salfred pmp->pm_devvp->v_specflags &= ~SI_MOUNTEDON; 587255932Salfred error = VOP_CLOSE(pmp->pm_devvp, pmp->pm_ronly ? FREAD : FREAD | FWRITE, 588255932Salfred NOCRED, p); 589255932Salfred vrele(pmp->pm_devvp); 590255932Salfred free((caddr_t) pmp->pm_inusemap, M_MSDOSFSFAT); 591255932Salfred free((caddr_t) pmp, M_MSDOSFSMNT); 592255932Salfred mp->mnt_data = (qaddr_t) 0; 593255932Salfred mp->mnt_flag &= ~MNT_LOCAL; 594255932Salfred return error; 595255932Salfred} 596255932Salfred 597272027Shselaskystatic int 598272027Shselaskymsdosfs_root(mp, vpp) 599255932Salfred struct mount *mp; 600255932Salfred struct vnode **vpp; 601255932Salfred{ 602255932Salfred struct denode *ndep; 603255932Salfred struct msdosfsmount *pmp = (struct msdosfsmount *) (mp->mnt_data); 604255932Salfred int error; 605255932Salfred 606255932Salfred error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, NULL, &ndep); 607255932Salfred#ifdef MSDOSFS_DEBUG 608255932Salfred printf("msdosfs_root(); mp %p, pmp %p, ndep %p, vp %p\n", 609255932Salfred mp, pmp, ndep, DETOV(ndep)); 610255932Salfred#endif 611255932Salfred if (error == 0) 612255932Salfred *vpp = DETOV(ndep); 613255932Salfred return error; 614255932Salfred} 615255932Salfred 616255932Salfredstatic int 617255932Salfredmsdosfs_quotactl(mp, cmds, uid, arg, p) 618255932Salfred struct mount *mp; 619255932Salfred int cmds; 620255932Salfred uid_t uid; 621255932Salfred caddr_t arg; 622255932Salfred struct proc *p; 623255932Salfred{ 624255932Salfred return EOPNOTSUPP; 625255932Salfred} 626255932Salfred 627255932Salfredstatic int 628255932Salfredmsdosfs_statfs(mp, sbp, p) 629255932Salfred struct mount *mp; 630255932Salfred struct statfs *sbp; 631255932Salfred struct proc *p; 632255932Salfred{ 633255932Salfred struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data; 634255932Salfred 635255932Salfred /* 636255932Salfred * Fill in the stat block. 637255932Salfred */ 638255932Salfred sbp->f_bsize = pmp->pm_bpcluster; 639255932Salfred sbp->f_iosize = pmp->pm_bpcluster; 640255932Salfred sbp->f_blocks = pmp->pm_nmbrofclusters; 641255932Salfred sbp->f_bfree = pmp->pm_freeclustercount; 642255932Salfred sbp->f_bavail = pmp->pm_freeclustercount; 643255932Salfred sbp->f_files = pmp->pm_RootDirEnts; /* XXX */ 644255932Salfred sbp->f_ffree = 0; /* what to put in here? */ 645255932Salfred 646255932Salfred /* 647255932Salfred * Copy the mounted on and mounted from names into the passed in 648255932Salfred * stat block, if it is not the one in the mount structure. 649255932Salfred */ 650255932Salfred if (sbp != &mp->mnt_stat) { 651255932Salfred sbp->f_type = mp->mnt_vfc->vfc_typenum; 652255932Salfred bcopy((caddr_t) mp->mnt_stat.f_mntonname, 653255932Salfred (caddr_t) & sbp->f_mntonname[0], MNAMELEN); 654255932Salfred bcopy((caddr_t) mp->mnt_stat.f_mntfromname, 655255932Salfred (caddr_t) & sbp->f_mntfromname[0], MNAMELEN); 656255932Salfred } 657255932Salfred#if 0 658255932Salfred strncpy(&sbp->f_fstypename[0], mp->mnt_op->vfs_name, MFSNAMELEN); 659255932Salfred sbp->f_fstypename[MFSNAMELEN] = '\0'; 660255932Salfred#endif 661255932Salfred return 0; 662255932Salfred} 663255932Salfred 664255932Salfredstatic int 665255932Salfredmsdosfs_sync(mp, waitfor, cred, p) 666255932Salfred struct mount *mp; 667255932Salfred int waitfor; 668255932Salfred struct ucred *cred; 669255932Salfred struct proc *p; 670255932Salfred{ 671255932Salfred struct vnode *vp; 672255932Salfred struct denode *dep; 673255932Salfred struct msdosfsmount *pmp; 674255932Salfred int error; 675255932Salfred int allerror = 0; 676255932Salfred 677255932Salfred pmp = (struct msdosfsmount *) mp->mnt_data; 678272027Shselasky 679255932Salfred /* 680255932Salfred * If we ever switch to not updating all of the fats all the time, 681255932Salfred * this would be the place to update them from the first one. 682255932Salfred */ 683255932Salfred if (pmp->pm_fmod) 684255932Salfred if (pmp->pm_ronly) 685255932Salfred panic("msdosfs_sync: rofs mod"); 686255932Salfred else { 687255932Salfred /* update fats here */ 688255932Salfred } 689255932Salfred 690255932Salfred /* 691255932Salfred * Go thru in memory denodes and write them out along with 692255932Salfred * unwritten file blocks. 693255932Salfred */ 694255932Salfred simple_lock(&mntvnode_slock); 695255932Salfredloop: 696255932Salfred for (vp = mp->mnt_vnodelist.lh_first; vp; 697255932Salfred vp = vp->v_mntvnodes.le_next) { 698255932Salfred if (vp->v_mount != mp) /* not ours anymore */ 699255932Salfred goto loop; 700255932Salfred simple_lock(&vp->v_interlock); 701255932Salfred dep = VTODE(vp); 702255932Salfred if ((dep->de_flag & (DE_MODIFIED | DE_UPDATE)) == 0 && 703255932Salfred vp->v_dirtyblkhd.lh_first == NULL) { 704255932Salfred simple_unlock(&vp->v_interlock); 705255932Salfred continue; 706255932Salfred } 707255932Salfred simple_unlock(&mntvnode_slock); 708255932Salfred error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, p); 709255932Salfred if (error) { 710255932Salfred simple_lock(&mntvnode_slock); 711255932Salfred if (error == ENOENT) 712255932Salfred goto loop; 713255932Salfred continue; 714255932Salfred } 715255932Salfred error = VOP_FSYNC(vp, cred, waitfor, p); 716255932Salfred if (error) 717255932Salfred allerror = error; 718255932Salfred VOP_UNLOCK(vp, 0, p); 719255932Salfred vrele(vp); /* done with this one */ 720255932Salfred simple_lock(&mntvnode_slock); 721255932Salfred } 722255932Salfred simple_unlock(&mntvnode_slock); 723255932Salfred 724255932Salfred /* 725255932Salfred * Flush filesystem control info. 726255932Salfred */ 727255932Salfred error = VOP_FSYNC(pmp->pm_devvp, cred, waitfor, p); 728255932Salfred if (error) 729255932Salfred allerror = error; 730255932Salfred return allerror; 731255932Salfred} 732255932Salfred 733255932Salfredstatic int 734255932Salfredmsdosfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp) 735255932Salfred struct mount *mp; 736255932Salfred struct fid *fhp; 737255932Salfred struct sockaddr *nam; 738255932Salfred struct vnode **vpp; 739255932Salfred int *exflagsp; 740255932Salfred struct ucred **credanonp; 741255932Salfred{ 742255932Salfred struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data; 743255932Salfred struct defid *defhp = (struct defid *) fhp; 744255932Salfred struct denode *dep; 745255932Salfred struct netcred *np; 746255932Salfred int error; 747255932Salfred 748255932Salfred np = vfs_export_lookup(mp, &pmp->pm_export, nam); 749255932Salfred if (np == NULL) 750255932Salfred return EACCES; 751255932Salfred error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs, 752255932Salfred NULL, &dep); 753255932Salfred if (error) { 754255932Salfred *vpp = NULLVP; 755255932Salfred return error; 756255932Salfred } 757255932Salfred *vpp = DETOV(dep); 758272027Shselasky *exflagsp = np->netc_exflags; 759255932Salfred *credanonp = &np->netc_anon; 760255932Salfred return 0; 761255932Salfred} 762219820Sjeff 763219820Sjeff 764219820Sjeffstatic int 765219820Sjeffmsdosfs_vptofh(vp, fhp) 766219820Sjeff struct vnode *vp; 767219820Sjeff struct fid *fhp; 768219820Sjeff{ 769219820Sjeff struct denode *dep = VTODE(vp); 770255932Salfred struct defid *defhp = (struct defid *) fhp; 771255932Salfred 772255932Salfred defhp->defid_len = sizeof(struct defid); 773255932Salfred defhp->defid_dirclust = dep->de_dirclust; 774255932Salfred defhp->defid_dirofs = dep->de_diroffset; 775255932Salfred /* defhp->defid_gen = ip->i_gen; */ 776255932Salfred return 0; 777219820Sjeff} 778255932Salfred 779255932Salfredstatic int 780255932Salfredmsdosfs_vget(mp, ino, vpp) 781255932Salfred struct mount *mp; 782219820Sjeff ino_t ino; 783255932Salfred struct vnode **vpp; 784272027Shselasky{ 785272027Shselasky return EOPNOTSUPP; 786255932Salfred} 787255932Salfred 788255932Salfredstatic struct vfsops msdosfs_vfsops = { 789255932Salfred msdosfs_mount, 790255932Salfred msdosfs_start, 791255932Salfred msdosfs_unmount, 792255932Salfred msdosfs_root, 793255932Salfred msdosfs_quotactl, 794255932Salfred msdosfs_statfs, 795255932Salfred msdosfs_sync, 796255932Salfred msdosfs_vget, 797255932Salfred msdosfs_fhtovp, 798255932Salfred msdosfs_vptofh, 799219820Sjeff msdosfs_init 800219820Sjeff}; 801219820Sjeff 802255932SalfredVFS_SET(msdosfs_vfsops, msdos, MOUNT_MSDOS, 0); 803255932Salfred