msdosfs_vfsops.c revision 15033
11556Srgrimes/* $Id: msdosfs_vfsops.c,v 1.11 1996/01/05 18:31:43 wollman Exp $ */ 21556Srgrimes/* $NetBSD: msdosfs_vfsops.c,v 1.19 1994/08/21 18:44:10 ws Exp $ */ 31556Srgrimes 41556Srgrimes/*- 51556Srgrimes * Copyright (C) 1994 Wolfgang Solfrank. 61556Srgrimes * Copyright (C) 1994 TooLs GmbH. 71556Srgrimes * All rights reserved. 81556Srgrimes * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). 91556Srgrimes * 101556Srgrimes * Redistribution and use in source and binary forms, with or without 111556Srgrimes * modification, are permitted provided that the following conditions 121556Srgrimes * are met: 131556Srgrimes * 1. Redistributions of source code must retain the above copyright 141556Srgrimes * notice, this list of conditions and the following disclaimer. 151556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 161556Srgrimes * notice, this list of conditions and the following disclaimer in the 171556Srgrimes * documentation and/or other materials provided with the distribution. 181556Srgrimes * 3. All advertising materials mentioning features or use of this software 191556Srgrimes * must display the following acknowledgement: 201556Srgrimes * This product includes software developed by TooLs GmbH. 211556Srgrimes * 4. The name of TooLs GmbH may not be used to endorse or promote products 221556Srgrimes * derived from this software without specific prior written permission. 231556Srgrimes * 241556Srgrimes * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 251556Srgrimes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 261556Srgrimes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 271556Srgrimes * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 281556Srgrimes * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 291556Srgrimes * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 301556Srgrimes * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 311556Srgrimes * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 321556Srgrimes * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 331556Srgrimes * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3436150Scharnier */ 3536150Scharnier/* 3636150Scharnier * Written by Paul Popelka (paulp@uts.amdahl.com) 371556Srgrimes * 3899110Sobrien * You can do anything you want with this software, just don't say you wrote 3999110Sobrien * it, and don't remove this notice. 401556Srgrimes * 41100437Stjr * This software is provided "as is". 4217987Speter * 43102576Skeramida * The author supplies this software to be publicly redistributed on the 4417987Speter * understanding that the author is not responsible for the correct 4545266Scracauer * functioning of this software in any circumstances and is not liable for 4653891Scracauer * any damages caused by this software. 4717987Speter * 481556Srgrimes * October 1992 491556Srgrimes */ 501556Srgrimes 511556Srgrimes#include <sys/param.h> 521556Srgrimes#include <sys/systm.h> 531556Srgrimes#include <sys/namei.h> 541556Srgrimes#include <sys/proc.h> 551556Srgrimes#include <sys/kernel.h> 561556Srgrimes#include <sys/vnode.h> 571556Srgrimes#include <miscfs/specfs/specdev.h> /* XXX */ /* defines v_rdev */ 581556Srgrimes#include <sys/mount.h> 591556Srgrimes#include <sys/buf.h> 601556Srgrimes#include <sys/file.h> 611556Srgrimes#include <sys/malloc.h> 621556Srgrimes 631556Srgrimes#include <msdosfs/bpb.h> 641556Srgrimes#include <msdosfs/bootsect.h> 651556Srgrimes#include <msdosfs/direntry.h> 661556Srgrimes#include <msdosfs/denode.h> 671556Srgrimes#include <msdosfs/msdosfsmount.h> 681556Srgrimes#include <msdosfs/fat.h> 6917987Speter 701556Srgrimesstatic int msdosfsdoforce = 1; /* 1 = force unmount */ 7117987Speter 721556Srgrimesstatic int mountmsdosfs __P((struct vnode *devvp, struct mount *mp, 7317987Speter struct proc *p)); 741556Srgrimesstatic int msdosfs_fhtovp __P((struct mount *, struct fid *, 751556Srgrimes struct mbuf *, struct vnode **, int *, 761556Srgrimes struct ucred **)); 771556Srgrimesstatic int msdosfs_mount __P((struct mount *, char *, caddr_t, 781556Srgrimes struct nameidata *, struct proc *)); 791556Srgrimesstatic int msdosfs_quotactl __P((struct mount *, int, uid_t, caddr_t, 801556Srgrimes struct proc *)); 811556Srgrimesstatic int msdosfs_root __P((struct mount *, struct vnode **)); 821556Srgrimesstatic int msdosfs_start __P((struct mount *, int, struct proc *)); 831556Srgrimesstatic int msdosfs_statfs __P((struct mount *, struct statfs *, 841556Srgrimes struct proc *)); 851556Srgrimesstatic int msdosfs_sync __P((struct mount *, int, struct ucred *, 861556Srgrimes struct proc *)); 871556Srgrimesstatic int msdosfs_unmount __P((struct mount *, int, struct proc *)); 881556Srgrimesstatic int msdosfs_vget __P((struct mount *mp, ino_t ino, 891556Srgrimes struct vnode **vpp)); 9017987Speterstatic int msdosfs_vptofh __P((struct vnode *, struct fid *)); 911556Srgrimes 921556Srgrimes/* 93149933Sstefanf * mp - path - addr in user space of mount point (ie /usr or whatever) 94149933Sstefanf * data - addr in user space of mount params including the name of the block 9590111Simp * special file to treat as a filesystem. 9690111Simp */ 9790111Simpstatic int 9890111Simpmsdosfs_mount(mp, path, data, ndp, p) 9990111Simp struct mount *mp; 10090111Simp char *path; 1011556Srgrimes caddr_t data; 1021556Srgrimes struct nameidata *ndp; 1031556Srgrimes struct proc *p; 1041556Srgrimes{ 1051556Srgrimes struct vnode *devvp; /* vnode for blk device to mount */ 1061556Srgrimes struct msdosfs_args args; /* will hold data from mount request */ 1071556Srgrimes struct msdosfsmount *pmp; /* msdosfs specific mount control block */ 1081556Srgrimes int error, flags; 1091556Srgrimes u_int size; 1101556Srgrimes struct ucred *cred, *scred; 1111556Srgrimes struct vattr va; 1121556Srgrimes 1131556Srgrimes /* 1141556Srgrimes * Copy in the args for the mount request. 1151556Srgrimes */ 1161556Srgrimes error = copyin(data, (caddr_t) & args, sizeof(struct msdosfs_args)); 1171556Srgrimes if (error) 1181556Srgrimes return error; 1191556Srgrimes 1201556Srgrimes /* 1211556Srgrimes * If they just want to update then be sure we can do what is 1221556Srgrimes * asked. Can't change a filesystem from read/write to read only. 1231556Srgrimes * Why? And if they've supplied a new device file name then we 12446684Skris * continue, otherwise return. 1251556Srgrimes */ 1261556Srgrimes if (mp->mnt_flag & MNT_UPDATE) { 12717987Speter pmp = (struct msdosfsmount *) mp->mnt_data; 12890111Simp error = 0; 1291556Srgrimes if (pmp->pm_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) { 1301556Srgrimes flags = WRITECLOSE; 1311556Srgrimes if (mp->mnt_flag & MNT_FORCE) 1321556Srgrimes flags |= FORCECLOSE; 1331556Srgrimes if (vfs_busy(mp)) 1341556Srgrimes return EBUSY; 1351556Srgrimes error = vflush(mp, NULLVP, flags); 1361556Srgrimes vfs_unbusy(mp); 1371556Srgrimes } 1381556Srgrimes if (!error && (mp->mnt_flag & MNT_RELOAD)) 1391556Srgrimes /* not yet implemented */ 1401556Srgrimes error = EINVAL; 1411556Srgrimes if (error) 1421556Srgrimes return error; 1431556Srgrimes if (pmp->pm_ronly && (mp->mnt_flag & MNT_RDONLY) == 0) 1441556Srgrimes pmp->pm_ronly = 0; 1451556Srgrimes if (args.fspec == 0) { 1461556Srgrimes /* 1471556Srgrimes * Process export requests. 1481556Srgrimes */ 1491556Srgrimes return vfs_export(mp, &pmp->pm_export, &args.export); 1501556Srgrimes } 1511556Srgrimes } else 1521556Srgrimes pmp = NULL; 1531556Srgrimes 1541556Srgrimes /* 1551556Srgrimes * check to see that the user in owns the target directory. 1561556Srgrimes * Note the very XXX trick to make sure we're checking as the 1571556Srgrimes * real user -- were mount() executable by anyone, this wouldn't 1581556Srgrimes * be a problem. 1591556Srgrimes * 16090111Simp * XXX there should be one consistent error out. 16190111Simp */ 1621556Srgrimes cred = crdup(p->p_ucred); /* XXX */ 1631556Srgrimes cred->cr_uid = p->p_cred->p_ruid; /* XXX */ 1641556Srgrimes error = VOP_GETATTR(mp->mnt_vnodecovered, &va, cred, p); 1651556Srgrimes if (error) { 1661556Srgrimes crfree(cred); /* XXX */ 1671556Srgrimes return error; 1681556Srgrimes } 1691556Srgrimes if (cred->cr_uid != 0) { 1701556Srgrimes if (va.va_uid != cred->cr_uid) { 1711556Srgrimes error = EACCES; 1721556Srgrimes crfree(cred); /* XXX */ 1731556Srgrimes return error; 1741556Srgrimes } 1751556Srgrimes 1761556Srgrimes /* a user mounted it; we'll verify permissions when unmounting */ 1771556Srgrimes mp->mnt_flag |= MNT_USER; 1781556Srgrimes } 1791556Srgrimes 1801556Srgrimes /* 1811556Srgrimes * Now, lookup the name of the block device this mount or name 1821556Srgrimes * update request is to apply to. 18390111Simp */ 18417987Speter NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p); 185149927Sstefanf scred = p->p_ucred; /* XXX */ 186149927Sstefanf p->p_ucred = cred; /* XXX */ 187149927Sstefanf error = namei(ndp); 1881556Srgrimes p->p_ucred = scred; /* XXX */ 1891556Srgrimes crfree(cred); /* XXX */ 1901556Srgrimes if (error != 0) 1911556Srgrimes return error; 1921556Srgrimes 19317987Speter /* 1941556Srgrimes * Be sure they've given us a block device to treat as a 19517987Speter * filesystem. And, that its major number is within the bdevsw 196149802Sstefanf * table. 1971556Srgrimes */ 1981556Srgrimes devvp = ndp->ni_vp; 199149932Sstefanf if (devvp->v_type != VBLK) { 2001556Srgrimes vrele(devvp); 2011556Srgrimes return ENOTBLK; 2021556Srgrimes } 2031556Srgrimes if (major(devvp->v_rdev) >= nblkdev) { 2041556Srgrimes vrele(devvp); 2051556Srgrimes return ENXIO; 20618754Ssteve } 2071556Srgrimes 20818754Ssteve /* 2091556Srgrimes * If this is an update, then make sure the vnode for the block 2101556Srgrimes * special device is the same as the one our filesystem is in. 2111556Srgrimes */ 2121556Srgrimes if (mp->mnt_flag & MNT_UPDATE) { 2131556Srgrimes if (devvp != pmp->pm_devvp) 2141556Srgrimes error = EINVAL; 2151556Srgrimes else 2161556Srgrimes vrele(devvp); 2171556Srgrimes } else { 2181556Srgrimes 2191556Srgrimes /* 2201556Srgrimes * Well, it's not an update, it's a real mount request. 2211556Srgrimes * Time to get dirty. 2221556Srgrimes */ 2231556Srgrimes error = mountmsdosfs(devvp, mp, p); 2241556Srgrimes } 225149927Sstefanf if (error) { 2261556Srgrimes vrele(devvp); 2271556Srgrimes return error; 2281556Srgrimes } 2291556Srgrimes 2301556Srgrimes /* 2311556Srgrimes * Copy in the name of the directory the filesystem is to be 2321556Srgrimes * mounted on. Then copy in the name of the block special file 2331556Srgrimes * representing the filesystem being mounted. And we clear the 23420425Ssteve * remainder of the character strings to be tidy. Set up the 2351556Srgrimes * user id/group id/mask as specified by the user. Then, we try to 23617987Speter * fill in the filesystem stats structure as best we can with 2371556Srgrimes * whatever applies from a dos file system. 23820425Ssteve */ 23920425Ssteve pmp = (struct msdosfsmount *) mp->mnt_data; 2401556Srgrimes copyinstr(path, (caddr_t) mp->mnt_stat.f_mntonname, 2411556Srgrimes sizeof(mp->mnt_stat.f_mntonname) - 1, &size); 2421556Srgrimes bzero(mp->mnt_stat.f_mntonname + size, 2431556Srgrimes sizeof(mp->mnt_stat.f_mntonname) - size); 244149933Sstefanf copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size); 2451556Srgrimes bzero(mp->mnt_stat.f_mntfromname + size, 2461556Srgrimes MNAMELEN - size); 247149933Sstefanf pmp->pm_mounter = p->p_cred->p_ruid; 2481556Srgrimes pmp->pm_gid = args.gid; 2491556Srgrimes pmp->pm_uid = args.uid; 2501556Srgrimes pmp->pm_mask = args.mask; 2511556Srgrimes (void) msdosfs_statfs(mp, &mp->mnt_stat, p); 2521556Srgrimes#ifdef MSDOSFS_DEBUG 2531556Srgrimes printf("msdosfs_mount(): mp %p, pmp %p, inusemap %p\n", mp, pmp, pmp->pm_inusemap); 2541556Srgrimes#endif 2551556Srgrimes return 0; 2561556Srgrimes} 2571556Srgrimes 2581556Srgrimesstatic int 2591556Srgrimesmountmsdosfs(devvp, mp, p) 2601556Srgrimes struct vnode *devvp; 2611556Srgrimes struct mount *mp; 2621556Srgrimes struct proc *p; 263149927Sstefanf{ 2641556Srgrimes int i; 2651556Srgrimes int bpc; 2661556Srgrimes int bit; 267149927Sstefanf int error; 2681556Srgrimes int needclose; 2691556Srgrimes int ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 2701556Srgrimes dev_t dev = devvp->v_rdev; 2711556Srgrimes union bootsector *bsp; 2721556Srgrimes struct msdosfsmount *pmp = NULL; 2731556Srgrimes struct buf *bp0 = NULL; 2741556Srgrimes struct byte_bpb33 *b33; 2751556Srgrimes struct byte_bpb50 *b50; 2761556Srgrimes 277149927Sstefanf /* 2781556Srgrimes * Multiple mounts of the same block special file aren't allowed. 2791556Srgrimes * Make sure no one else has the special file open. And flush any 2801556Srgrimes * old buffers from this filesystem. Presumably this prevents us 2811556Srgrimes * from running into buffers that are the wrong blocksize. 2821556Srgrimes */ 283149933Sstefanf error = vfs_mountedon(devvp); 28417987Speter if (error) 2851556Srgrimes return error; 2861556Srgrimes if (vcount(devvp) > 1) 2871556Srgrimes return EBUSY; 2881556Srgrimes error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0); 2891556Srgrimes if (error) 2901556Srgrimes return error; 2911556Srgrimes 2921556Srgrimes /* 2931556Srgrimes * Now open the block special file. 2941556Srgrimes */ 2951556Srgrimes error = VOP_OPEN(devvp, ronly ? FREAD : FREAD | FWRITE, FSCRED, p); 2961556Srgrimes if (error) 2971556Srgrimes return error; 2981556Srgrimes needclose = 1; 2991556Srgrimes#ifdef HDSUPPORT 3001556Srgrimes /* 3011556Srgrimes * Put this in when we support reading dos filesystems from 3021556Srgrimes * partitioned harddisks. 3031556Srgrimes */ 3041556Srgrimes if (VOP_IOCTL(devvp, DIOCGPART, &msdosfspart, FREAD, NOCRED, p) == 0) { 3051556Srgrimes } 3061556Srgrimes#endif 307149933Sstefanf 3081556Srgrimes /* 3091556Srgrimes * Read the boot sector of the filesystem, and then check the boot 3101556Srgrimes * signature. If not a dos boot sector then error out. We could 3111556Srgrimes * also add some checking on the bsOemName field. So far I've seen 3121556Srgrimes * the following values: "IBM 3.3" "MSDOS3.3" "MSDOS5.0" 3131556Srgrimes */ 3141556Srgrimes error = bread(devvp, 0, 512, NOCRED, &bp0); 3151556Srgrimes if (error) 3161556Srgrimes goto error_exit; 3171556Srgrimes bp0->b_flags |= B_AGE; 3181556Srgrimes bsp = (union bootsector *) bp0->b_data; 319149933Sstefanf b33 = (struct byte_bpb33 *) bsp->bs33.bsBPB; 32017987Speter b50 = (struct byte_bpb50 *) bsp->bs50.bsBPB; 3211556Srgrimes#ifdef MSDOSFS_CHECKSIG 3221556Srgrimes if (bsp->bs50.bsBootSectSig != BOOTSIG) { 3231556Srgrimes error = EINVAL; 3241556Srgrimes goto error_exit; 3251556Srgrimes } 3261556Srgrimes#endif 3271556Srgrimes if ( bsp->bs50.bsJump[0] != 0xe9 && 3281556Srgrimes (bsp->bs50.bsJump[0] != 0xeb || bsp->bs50.bsJump[2] != 0x90)) { 32917987Speter error = EINVAL; 3301556Srgrimes goto error_exit; 3311556Srgrimes } 3321556Srgrimes 3331556Srgrimes pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK); 3341556Srgrimes bzero((caddr_t)pmp, sizeof *pmp); 3351556Srgrimes pmp->pm_mountp = mp; 3361556Srgrimes 3371556Srgrimes /* 3381556Srgrimes * Compute several useful quantities from the bpb in the 3391556Srgrimes * bootsector. Copy in the dos 5 variant of the bpb then fix up 340149933Sstefanf * the fields that are different between dos 5 and dos 3.3. 3411556Srgrimes */ 3421556Srgrimes pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec); 3431556Srgrimes pmp->pm_SectPerClust = b50->bpbSecPerClust; 3441556Srgrimes pmp->pm_ResSectors = getushort(b50->bpbResSectors); 3451556Srgrimes pmp->pm_FATs = b50->bpbFATs; 3461556Srgrimes pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts); 3471556Srgrimes pmp->pm_Sectors = getushort(b50->bpbSectors); 3481556Srgrimes pmp->pm_Media = b50->bpbMedia; 3491556Srgrimes pmp->pm_FATsecs = getushort(b50->bpbFATsecs); 3501556Srgrimes pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack); 3511556Srgrimes pmp->pm_Heads = getushort(b50->bpbHeads); 3521556Srgrimes 3531556Srgrimes /* XXX - We should probably check more values here */ 3541556Srgrimes if (!pmp->pm_BytesPerSec || !pmp->pm_SectPerClust || 3551556Srgrimes !pmp->pm_Heads || pmp->pm_Heads > 255 || 3561556Srgrimes !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 63) { 3571556Srgrimes error = EINVAL; 3581556Srgrimes goto error_exit; 35990111Simp } 36017987Speter 3611556Srgrimes if (pmp->pm_Sectors == 0) { 3621556Srgrimes pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs); 3631556Srgrimes pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors); 3641556Srgrimes } else { 3651556Srgrimes pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs); 3661556Srgrimes pmp->pm_HugeSectors = pmp->pm_Sectors; 3671556Srgrimes } 36817987Speter pmp->pm_fatblk = pmp->pm_ResSectors; 3691556Srgrimes pmp->pm_rootdirblk = pmp->pm_fatblk + 3701556Srgrimes (pmp->pm_FATs * pmp->pm_FATsecs); 3711556Srgrimes pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry)) 3721556Srgrimes / 3731556Srgrimes pmp->pm_BytesPerSec;/* in sectors */ 3741556Srgrimes pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize; 3751556Srgrimes pmp->pm_nmbrofclusters = (pmp->pm_HugeSectors - pmp->pm_firstcluster) / 3761556Srgrimes pmp->pm_SectPerClust; 3771556Srgrimes pmp->pm_maxcluster = pmp->pm_nmbrofclusters + 1; 3781556Srgrimes pmp->pm_fatsize = pmp->pm_FATsecs * pmp->pm_BytesPerSec; 3791556Srgrimes if (FAT12(pmp)) 3801556Srgrimes /* 3811556Srgrimes * This will usually be a floppy disk. This size makes sure 3821556Srgrimes * that one fat entry will not be split across multiple 3831556Srgrimes * blocks. 3841556Srgrimes */ 3851556Srgrimes pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec; 3861556Srgrimes else 3871556Srgrimes /* 3881556Srgrimes * This will usually be a hard disk. Reading or writing one 3891556Srgrimes * block should be quite fast. 3901556Srgrimes */ 39190111Simp pmp->pm_fatblocksize = MAXBSIZE; 39217987Speter pmp->pm_fatblocksec = pmp->pm_fatblocksize / pmp->pm_BytesPerSec; 3931556Srgrimes 3941556Srgrimes 3951556Srgrimes if ((pmp->pm_rootdirsize % pmp->pm_SectPerClust) != 0) 3961556Srgrimes printf("mountmsdosfs(): Warning: root directory is not a multiple of the clustersize in length\n"); 3971556Srgrimes 3981556Srgrimes /* 3991556Srgrimes * Compute mask and shift value for isolating cluster relative byte 4001556Srgrimes * offsets and cluster numbers from a file offset. 4011556Srgrimes */ 4021556Srgrimes bpc = pmp->pm_SectPerClust * pmp->pm_BytesPerSec; 4031556Srgrimes pmp->pm_bpcluster = bpc; 4041556Srgrimes pmp->pm_depclust = bpc / sizeof(struct direntry); 4051556Srgrimes pmp->pm_crbomask = bpc - 1; 40645916Scracauer if (bpc == 0) { 4071556Srgrimes error = EINVAL; 4081556Srgrimes goto error_exit; 4091556Srgrimes } 4101556Srgrimes bit = 1; 4111556Srgrimes for (i = 0; i < 32; i++) { 4121556Srgrimes if (bit & bpc) { 4131556Srgrimes if (bit ^ bpc) { 4141556Srgrimes error = EINVAL; 4151556Srgrimes goto error_exit; 4161556Srgrimes } 4171556Srgrimes pmp->pm_cnshift = i; 41890111Simp break; 41917987Speter } 42025222Ssteve bit <<= 1; 4211556Srgrimes } 4221556Srgrimes 42317987Speter pmp->pm_brbomask = 0x01ff; /* 512 byte blocks only (so far) */ 42417987Speter pmp->pm_bnshift = 9; /* shift right 9 bits to get bn */ 42517987Speter 42617987Speter /* 42717987Speter * Release the bootsector buffer. 42817987Speter */ 42966612Sbrian brelse(bp0); 43017987Speter bp0 = NULL; 43196922Stjr 4321556Srgrimes /* 4331556Srgrimes * Allocate memory for the bitmap of allocated clusters, and then 43417987Speter * fill it in. 43517987Speter */ 43617987Speter pmp->pm_inusemap = malloc(((pmp->pm_maxcluster + N_INUSEBITS - 1) 43717987Speter / N_INUSEBITS) 43817987Speter * sizeof(*pmp->pm_inusemap), 43917987Speter M_MSDOSFSFAT, M_WAITOK); 44017987Speter 44117987Speter /* 4421556Srgrimes * fillinusemap() needs pm_devvp. 4431556Srgrimes */ 4441556Srgrimes pmp->pm_dev = dev; 4451556Srgrimes pmp->pm_devvp = devvp; 4461556Srgrimes 4471556Srgrimes /* 4481556Srgrimes * Have the inuse map filled in. 4491556Srgrimes */ 4501556Srgrimes error = fillinusemap(pmp); 4511556Srgrimes if (error) 4521556Srgrimes goto error_exit; 4531556Srgrimes 4541556Srgrimes /* 4551556Srgrimes * If they want fat updates to be synchronous then let them suffer 45690111Simp * the performance degradation in exchange for the on disk copy of 45717987Speter * the fat being correct just about all the time. I suppose this 4581556Srgrimes * would be a good thing to turn on if the kernel is still flakey. 4591556Srgrimes */ 4601556Srgrimes pmp->pm_waitonfat = mp->mnt_flag & MNT_SYNCHRONOUS; 4611556Srgrimes 4621556Srgrimes /* 4631556Srgrimes * Finish up. 464149802Sstefanf */ 4651556Srgrimes pmp->pm_ronly = ronly; 4661556Srgrimes if (ronly == 0) 4671556Srgrimes pmp->pm_fmod = 1; 4681556Srgrimes mp->mnt_data = (qaddr_t) pmp; 4691556Srgrimes mp->mnt_stat.f_fsid.val[0] = (long)dev; 4701556Srgrimes mp->mnt_stat.f_fsid.val[1] = MOUNT_MSDOS; 4711556Srgrimes mp->mnt_flag |= MNT_LOCAL; 4721556Srgrimes devvp->v_specflags |= SI_MOUNTEDON; 4731556Srgrimes 4741556Srgrimes return 0; 4751556Srgrimes 4761556Srgrimeserror_exit:; 47753891Scracauer if (bp0) 4781556Srgrimes brelse(bp0); 4791556Srgrimes if (needclose) 4801556Srgrimes (void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD | FWRITE, 4811556Srgrimes NOCRED, p); 4821556Srgrimes if (pmp) { 483124780Sdes if (pmp->pm_inusemap) 4841556Srgrimes free((caddr_t) pmp->pm_inusemap, M_MSDOSFSFAT); 4851556Srgrimes free((caddr_t) pmp, M_MSDOSFSMNT); 4861556Srgrimes mp->mnt_data = (qaddr_t) 0; 48753282Scracauer } 48852900Scracauer return error; 4891556Srgrimes} 490124780Sdes 4911556Srgrimesstatic int 4921556Srgrimesmsdosfs_start(mp, flags, p) 4931556Srgrimes struct mount *mp; 4941556Srgrimes int flags; 4951556Srgrimes struct proc *p; 4961556Srgrimes{ 4971556Srgrimes return 0; 4981556Srgrimes} 4991556Srgrimes 5001556Srgrimes/* 5011556Srgrimes * Unmount the filesystem described by mp. 5021556Srgrimes */ 5031556Srgrimesstatic int 50445916Scracauermsdosfs_unmount(mp, mntflags, p) 5051556Srgrimes struct mount *mp; 5061556Srgrimes int mntflags; 5071556Srgrimes struct proc *p; 5081556Srgrimes{ 5091556Srgrimes int flags = 0; 5101556Srgrimes int error; 5111556Srgrimes struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data; 5121556Srgrimes 5131556Srgrimes /* only the mounter, or superuser can unmount */ 5141556Srgrimes if ((p->p_cred->p_ruid != pmp->pm_mounter) && 5151556Srgrimes (error = suser(p->p_ucred, &p->p_acflag))) 5161556Srgrimes return error; 5171556Srgrimes 5181556Srgrimes if (mntflags & MNT_FORCE) { 5191556Srgrimes if (!msdosfsdoforce) 52090111Simp return EINVAL; 52117987Speter flags |= FORCECLOSE; 5221556Srgrimes } 5231556Srgrimes error = vflush(mp, NULLVP, flags); 5241556Srgrimes if (error) 5251556Srgrimes return error; 5261556Srgrimes pmp->pm_devvp->v_specflags &= ~SI_MOUNTEDON; 5271556Srgrimes error = VOP_CLOSE(pmp->pm_devvp, pmp->pm_ronly ? FREAD : FREAD | FWRITE, 5281556Srgrimes NOCRED, p); 5291556Srgrimes vrele(pmp->pm_devvp); 5301556Srgrimes free((caddr_t) pmp->pm_inusemap, M_MSDOSFSFAT); 53117987Speter free((caddr_t) pmp, M_MSDOSFSMNT); 53217987Speter mp->mnt_data = (qaddr_t) 0; 5331556Srgrimes mp->mnt_flag &= ~MNT_LOCAL; 53417987Speter return error; 5351556Srgrimes} 53617987Speter 5371556Srgrimesstatic int 5381556Srgrimesmsdosfs_root(mp, vpp) 53917987Speter struct mount *mp; 5401556Srgrimes struct vnode **vpp; 54153891Scracauer{ 5421556Srgrimes struct denode *ndep; 5431556Srgrimes struct msdosfsmount *pmp = (struct msdosfsmount *) (mp->mnt_data); 5441556Srgrimes int error; 5451556Srgrimes 5461556Srgrimes error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, NULL, &ndep); 547124780Sdes#ifdef MSDOSFS_DEBUG 5481556Srgrimes printf("msdosfs_root(); mp %p, pmp %p, ndep %p, vp %p\n", 5491556Srgrimes mp, pmp, ndep, DETOV(ndep)); 5501556Srgrimes#endif 5511556Srgrimes if (error == 0) 5521556Srgrimes *vpp = DETOV(ndep); 5531556Srgrimes return error; 5541556Srgrimes} 5551556Srgrimes 5561556Srgrimesstatic int 5571556Srgrimesmsdosfs_quotactl(mp, cmds, uid, arg, p) 558109627Stjr struct mount *mp; 5591556Srgrimes int cmds; 5601556Srgrimes uid_t uid; 5611556Srgrimes caddr_t arg; 5621556Srgrimes struct proc *p; 5631556Srgrimes{ 5641556Srgrimes return EOPNOTSUPP; 5651556Srgrimes} 5661556Srgrimes 5671556Srgrimesstatic int 5681556Srgrimesmsdosfs_statfs(mp, sbp, p) 56990111Simp struct mount *mp; 57017987Speter struct statfs *sbp; 5711556Srgrimes struct proc *p; 5721556Srgrimes{ 5731556Srgrimes struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data; 5741556Srgrimes 5751556Srgrimes /* 5761556Srgrimes * Fill in the stat block. 5771556Srgrimes */ 5781556Srgrimes sbp->f_type = MOUNT_MSDOS; 5791556Srgrimes sbp->f_bsize = pmp->pm_bpcluster; 5801556Srgrimes sbp->f_iosize = pmp->pm_bpcluster; 5811556Srgrimes sbp->f_blocks = pmp->pm_nmbrofclusters; 5821556Srgrimes sbp->f_bfree = pmp->pm_freeclustercount; 5831556Srgrimes sbp->f_bavail = pmp->pm_freeclustercount; 5841556Srgrimes sbp->f_files = pmp->pm_RootDirEnts; /* XXX */ 5851556Srgrimes sbp->f_ffree = 0; /* what to put in here? */ 5861556Srgrimes 5871556Srgrimes /* 5881556Srgrimes * Copy the mounted on and mounted from names into the passed in 5891556Srgrimes * stat block, if it is not the one in the mount structure. 5901556Srgrimes */ 59145916Scracauer if (sbp != &mp->mnt_stat) { 59254884Scracauer bcopy((caddr_t) mp->mnt_stat.f_mntonname, 59317987Speter (caddr_t) & sbp->f_mntonname[0], MNAMELEN); 59417987Speter bcopy((caddr_t) mp->mnt_stat.f_mntfromname, 59517987Speter (caddr_t) & sbp->f_mntfromname[0], MNAMELEN); 59617987Speter } 59717987Speter#if 0 59817987Speter strncpy(&sbp->f_fstypename[0], mp->mnt_op->vfs_name, MFSNAMELEN); 59954884Scracauer sbp->f_fstypename[MFSNAMELEN] = '\0'; 60017987Speter#endif 6011556Srgrimes return 0; 6021556Srgrimes} 603149802Sstefanf 6041556Srgrimesstatic int 6051556Srgrimesmsdosfs_sync(mp, waitfor, cred, p) 6061556Srgrimes struct mount *mp; 6071556Srgrimes int waitfor; 60854884Scracauer struct ucred *cred; 60917987Speter struct proc *p; 61017987Speter{ 6111556Srgrimes struct vnode *vp; 61217987Speter struct denode *dep; 6131556Srgrimes struct msdosfsmount *pmp; 6141556Srgrimes int error; 6151556Srgrimes int allerror = 0; 6161556Srgrimes 6171556Srgrimes pmp = (struct msdosfsmount *) mp->mnt_data; 6181556Srgrimes 6191556Srgrimes /* 6201556Srgrimes * If we ever switch to not updating all of the fats all the time, 6211556Srgrimes * this would be the place to update them from the first one. 6221556Srgrimes */ 6231556Srgrimes if (pmp->pm_fmod) 6241556Srgrimes if (pmp->pm_ronly) 6251556Srgrimes panic("msdosfs_sync: rofs mod"); 6261556Srgrimes else { 6271556Srgrimes /* update fats here */ 6281556Srgrimes } 6291556Srgrimes 6301556Srgrimes /* 6311556Srgrimes * Go thru in memory denodes and write them out along with 6321556Srgrimes * unwritten file blocks. 6331556Srgrimes */ 6341556Srgrimesloop: 6351556Srgrimes for (vp = mp->mnt_vnodelist.lh_first; vp; 6361556Srgrimes vp = vp->v_mntvnodes.le_next) { 6371556Srgrimes if (vp->v_mount != mp) /* not ours anymore */ 6381556Srgrimes goto loop; 6391556Srgrimes if (VOP_ISLOCKED(vp)) /* file is busy */ 6401556Srgrimes continue; 6411556Srgrimes dep = VTODE(vp); 6421556Srgrimes if ((dep->de_flag & (DE_MODIFIED | DE_UPDATE)) == 0 && 6431556Srgrimes vp->v_dirtyblkhd.lh_first == NULL) 6441556Srgrimes continue; 6451556Srgrimes if (vget(vp, 1)) /* not there anymore? */ 6461556Srgrimes goto loop; 6471556Srgrimes error = VOP_FSYNC(vp, cred, waitfor, p); 6481556Srgrimes if (error) 6491556Srgrimes allerror = error; 6501556Srgrimes vput(vp); /* done with this one */ 6511556Srgrimes } 6521556Srgrimes 6531556Srgrimes /* 6541556Srgrimes * Flush filesystem control info. 6551556Srgrimes */ 6561556Srgrimes error = VOP_FSYNC(pmp->pm_devvp, cred, waitfor, p); 6571556Srgrimes if (error) 6581556Srgrimes allerror = error; 6591556Srgrimes return allerror; 6601556Srgrimes} 6611556Srgrimes 6621556Srgrimesstatic int 66317987Spetermsdosfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp) 66417987Speter struct mount *mp; 66517987Speter struct fid *fhp; 66617987Speter struct mbuf *nam; 66717987Speter struct vnode **vpp; 66817987Speter int *exflagsp; 66917987Speter struct ucred **credanonp; 67017987Speter{ 67154884Scracauer struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data; 67217987Speter struct defid *defhp = (struct defid *) fhp; 67354884Scracauer struct denode *dep; 67454884Scracauer struct netcred *np; 67554884Scracauer int error; 67654884Scracauer 67754884Scracauer np = vfs_export_lookup(mp, &pmp->pm_export, nam); 67854884Scracauer if (np == NULL) 67954884Scracauer return EACCES; 68054884Scracauer error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs, 68154884Scracauer NULL, &dep); 68254884Scracauer if (error) { 68354884Scracauer *vpp = NULLVP; 68454884Scracauer return error; 68554884Scracauer } 68654884Scracauer *vpp = DETOV(dep); 68754884Scracauer *exflagsp = np->netc_exflags; 68854884Scracauer *credanonp = &np->netc_anon; 689123996Smaxim return 0; 69054884Scracauer} 69154884Scracauer 69254884Scracauer 69354884Scracauerstatic int 69417987Spetermsdosfs_vptofh(vp, fhp) 69517987Speter struct vnode *vp; 6961556Srgrimes struct fid *fhp; 69720425Ssteve{ 6981556Srgrimes struct denode *dep = VTODE(vp); 6991556Srgrimes struct defid *defhp = (struct defid *) fhp; 7001556Srgrimes 7011556Srgrimes defhp->defid_len = sizeof(struct defid); 7021556Srgrimes defhp->defid_dirclust = dep->de_dirclust; 7031556Srgrimes defhp->defid_dirofs = dep->de_diroffset; 7041556Srgrimes /* defhp->defid_gen = ip->i_gen; */ 7051556Srgrimes return 0; 7061556Srgrimes} 7071556Srgrimes 7081556Srgrimesstatic int 70920425Sstevemsdosfs_vget(mp, ino, vpp) 7101556Srgrimes struct mount *mp; 7111556Srgrimes ino_t ino; 7121556Srgrimes struct vnode **vpp; 7131556Srgrimes{ 7141556Srgrimes return EOPNOTSUPP; 7151556Srgrimes} 7161556Srgrimes 7171556Srgrimesstatic struct vfsops msdosfs_vfsops = { 7181556Srgrimes msdosfs_mount, 7191556Srgrimes msdosfs_start, 7201556Srgrimes msdosfs_unmount, 72145221Scracauer msdosfs_root, 72245221Scracauer msdosfs_quotactl, 72317987Speter msdosfs_statfs, 7241556Srgrimes msdosfs_sync, 72548896Ssheldonh msdosfs_vget, 7261556Srgrimes msdosfs_fhtovp, 727100437Stjr msdosfs_vptofh, 728100437Stjr msdosfs_init 729100437Stjr}; 7301556Srgrimes 7311556SrgrimesVFS_SET(msdosfs_vfsops, msdos, MOUNT_MSDOS, 0); 7321556Srgrimes