msdosfs_vfsops.c revision 12145
112145Sphk/* $Id: msdosfs_vfsops.c,v 1.8 1995/11/07 14:06:44 phk Exp $ */ 22893Sdfr/* $NetBSD: msdosfs_vfsops.c,v 1.19 1994/08/21 18:44:10 ws Exp $ */ 32893Sdfr 42893Sdfr/*- 52893Sdfr * Copyright (C) 1994 Wolfgang Solfrank. 62893Sdfr * Copyright (C) 1994 TooLs GmbH. 72893Sdfr * All rights reserved. 82893Sdfr * Original code by Paul Popelka (paulp@uts.amdahl.com) (see below). 92893Sdfr * 102893Sdfr * Redistribution and use in source and binary forms, with or without 112893Sdfr * modification, are permitted provided that the following conditions 122893Sdfr * are met: 132893Sdfr * 1. Redistributions of source code must retain the above copyright 142893Sdfr * notice, this list of conditions and the following disclaimer. 152893Sdfr * 2. Redistributions in binary form must reproduce the above copyright 162893Sdfr * notice, this list of conditions and the following disclaimer in the 172893Sdfr * documentation and/or other materials provided with the distribution. 182893Sdfr * 3. All advertising materials mentioning features or use of this software 192893Sdfr * must display the following acknowledgement: 202893Sdfr * This product includes software developed by TooLs GmbH. 212893Sdfr * 4. The name of TooLs GmbH may not be used to endorse or promote products 222893Sdfr * derived from this software without specific prior written permission. 232893Sdfr * 242893Sdfr * THIS SOFTWARE IS PROVIDED BY TOOLS GMBH ``AS IS'' AND ANY EXPRESS OR 252893Sdfr * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 262893Sdfr * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 272893Sdfr * IN NO EVENT SHALL TOOLS GMBH BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 282893Sdfr * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 292893Sdfr * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 302893Sdfr * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 312893Sdfr * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 322893Sdfr * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 332893Sdfr * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 342893Sdfr */ 352893Sdfr/* 362893Sdfr * Written by Paul Popelka (paulp@uts.amdahl.com) 378876Srgrimes * 382893Sdfr * You can do anything you want with this software, just don't say you wrote 392893Sdfr * it, and don't remove this notice. 408876Srgrimes * 412893Sdfr * This software is provided "as is". 428876Srgrimes * 432893Sdfr * The author supplies this software to be publicly redistributed on the 442893Sdfr * understanding that the author is not responsible for the correct 452893Sdfr * functioning of this software in any circumstances and is not liable for 462893Sdfr * any damages caused by this software. 478876Srgrimes * 482893Sdfr * October 1992 492893Sdfr */ 502893Sdfr 512893Sdfr#include <sys/param.h> 522893Sdfr#include <sys/systm.h> 532893Sdfr#include <sys/namei.h> 542893Sdfr#include <sys/proc.h> 552893Sdfr#include <sys/kernel.h> 562893Sdfr#include <sys/vnode.h> 572893Sdfr#include <miscfs/specfs/specdev.h> /* XXX */ /* defines v_rdev */ 582893Sdfr#include <sys/mount.h> 592893Sdfr#include <sys/buf.h> 602893Sdfr#include <sys/file.h> 612893Sdfr#include <sys/malloc.h> 622893Sdfr 632893Sdfr#include <msdosfs/bpb.h> 642893Sdfr#include <msdosfs/bootsect.h> 652893Sdfr#include <msdosfs/direntry.h> 662893Sdfr#include <msdosfs/denode.h> 672893Sdfr#include <msdosfs/msdosfsmount.h> 682893Sdfr#include <msdosfs/fat.h> 692893Sdfr 7012144Sphkstatic int msdosfsdoforce = 1; /* 1 = force unmount */ 712893Sdfr 722893Sdfr/* 738876Srgrimes * mp - path - addr in user space of mount point (ie /usr or whatever) 742893Sdfr * data - addr in user space of mount params including the name of the block 758876Srgrimes * special file to treat as a filesystem. 762893Sdfr */ 7712144Sphkstatic int 782893Sdfrmsdosfs_mount(mp, path, data, ndp, p) 792893Sdfr struct mount *mp; 802893Sdfr char *path; 812893Sdfr caddr_t data; 822893Sdfr struct nameidata *ndp; 832893Sdfr struct proc *p; 842893Sdfr{ 852893Sdfr struct vnode *devvp; /* vnode for blk device to mount */ 862893Sdfr struct msdosfs_args args; /* will hold data from mount request */ 872893Sdfr struct msdosfsmount *pmp; /* msdosfs specific mount control block */ 882893Sdfr int error, flags; 892893Sdfr u_int size; 902893Sdfr struct ucred *cred, *scred; 912893Sdfr struct vattr va; 922893Sdfr 932893Sdfr /* 942893Sdfr * Copy in the args for the mount request. 952893Sdfr */ 963152Sphk error = copyin(data, (caddr_t) & args, sizeof(struct msdosfs_args)); 973152Sphk if (error) 982893Sdfr return error; 992893Sdfr 1002893Sdfr /* 1012893Sdfr * If they just want to update then be sure we can do what is 1022893Sdfr * asked. Can't change a filesystem from read/write to read only. 1032893Sdfr * Why? And if they've supplied a new device file name then we 1042893Sdfr * continue, otherwise return. 1052893Sdfr */ 1062893Sdfr if (mp->mnt_flag & MNT_UPDATE) { 1072893Sdfr pmp = (struct msdosfsmount *) mp->mnt_data; 1082893Sdfr error = 0; 1092893Sdfr if (pmp->pm_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) { 1102893Sdfr flags = WRITECLOSE; 1112893Sdfr if (mp->mnt_flag & MNT_FORCE) 1122893Sdfr flags |= FORCECLOSE; 1132893Sdfr if (vfs_busy(mp)) 1142893Sdfr return EBUSY; 1152893Sdfr error = vflush(mp, NULLVP, flags); 1162893Sdfr vfs_unbusy(mp); 1172893Sdfr } 1182893Sdfr if (!error && (mp->mnt_flag & MNT_RELOAD)) 1192893Sdfr /* not yet implemented */ 1202893Sdfr error = EINVAL; 1212893Sdfr if (error) 1222893Sdfr return error; 1232893Sdfr if (pmp->pm_ronly && (mp->mnt_flag & MNT_RDONLY) == 0) 1242893Sdfr pmp->pm_ronly = 0; 1252893Sdfr if (args.fspec == 0) { 1262893Sdfr /* 1272893Sdfr * Process export requests. 1282893Sdfr */ 1292893Sdfr return vfs_export(mp, &pmp->pm_export, &args.export); 1302893Sdfr } 1312893Sdfr } else 1322893Sdfr pmp = NULL; 1332893Sdfr 1342893Sdfr /* 1352893Sdfr * check to see that the user in owns the target directory. 1362893Sdfr * Note the very XXX trick to make sure we're checking as the 1372893Sdfr * real user -- were mount() executable by anyone, this wouldn't 1382893Sdfr * be a problem. 1392893Sdfr * 1402893Sdfr * XXX there should be one consistent error out. 1412893Sdfr */ 1422893Sdfr cred = crdup(p->p_ucred); /* XXX */ 1432893Sdfr cred->cr_uid = p->p_cred->p_ruid; /* XXX */ 1442893Sdfr error = VOP_GETATTR(mp->mnt_vnodecovered, &va, cred, p); 1452893Sdfr if (error) { 1462893Sdfr crfree(cred); /* XXX */ 1472893Sdfr return error; 1482893Sdfr } 1492893Sdfr if (cred->cr_uid != 0) { 1502893Sdfr if (va.va_uid != cred->cr_uid) { 1512893Sdfr error = EACCES; 1522893Sdfr crfree(cred); /* XXX */ 1532893Sdfr return error; 1542893Sdfr } 1552893Sdfr 1562893Sdfr /* a user mounted it; we'll verify permissions when unmounting */ 1572893Sdfr mp->mnt_flag |= MNT_USER; 1582893Sdfr } 1592893Sdfr 1602893Sdfr /* 1612893Sdfr * Now, lookup the name of the block device this mount or name 1622893Sdfr * update request is to apply to. 1632893Sdfr */ 1642893Sdfr NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p); 1652893Sdfr scred = p->p_ucred; /* XXX */ 1662893Sdfr p->p_ucred = cred; /* XXX */ 1672893Sdfr error = namei(ndp); 1682893Sdfr p->p_ucred = scred; /* XXX */ 1692893Sdfr crfree(cred); /* XXX */ 1702893Sdfr if (error != 0) 1712893Sdfr return error; 1728876Srgrimes 1732893Sdfr /* 1742893Sdfr * Be sure they've given us a block device to treat as a 1752893Sdfr * filesystem. And, that its major number is within the bdevsw 1762893Sdfr * table. 1772893Sdfr */ 1782893Sdfr devvp = ndp->ni_vp; 1792893Sdfr if (devvp->v_type != VBLK) { 1802893Sdfr vrele(devvp); 1812893Sdfr return ENOTBLK; 1822893Sdfr } 1832893Sdfr if (major(devvp->v_rdev) >= nblkdev) { 1842893Sdfr vrele(devvp); 1852893Sdfr return ENXIO; 1862893Sdfr } 1872893Sdfr 1882893Sdfr /* 1892893Sdfr * If this is an update, then make sure the vnode for the block 1902893Sdfr * special device is the same as the one our filesystem is in. 1912893Sdfr */ 1922893Sdfr if (mp->mnt_flag & MNT_UPDATE) { 1932893Sdfr if (devvp != pmp->pm_devvp) 1942893Sdfr error = EINVAL; 1952893Sdfr else 1962893Sdfr vrele(devvp); 1972893Sdfr } else { 1982893Sdfr 1992893Sdfr /* 2002893Sdfr * Well, it's not an update, it's a real mount request. 2012893Sdfr * Time to get dirty. 2022893Sdfr */ 2032893Sdfr error = mountmsdosfs(devvp, mp, p); 2042893Sdfr } 2052893Sdfr if (error) { 2062893Sdfr vrele(devvp); 2072893Sdfr return error; 2082893Sdfr } 2092893Sdfr 2102893Sdfr /* 2112893Sdfr * Copy in the name of the directory the filesystem is to be 2122893Sdfr * mounted on. Then copy in the name of the block special file 2132893Sdfr * representing the filesystem being mounted. And we clear the 2142893Sdfr * remainder of the character strings to be tidy. Set up the 2152893Sdfr * user id/group id/mask as specified by the user. Then, we try to 2162893Sdfr * fill in the filesystem stats structure as best we can with 2172893Sdfr * whatever applies from a dos file system. 2182893Sdfr */ 2192893Sdfr pmp = (struct msdosfsmount *) mp->mnt_data; 2202893Sdfr copyinstr(path, (caddr_t) mp->mnt_stat.f_mntonname, 2212893Sdfr sizeof(mp->mnt_stat.f_mntonname) - 1, &size); 2222893Sdfr bzero(mp->mnt_stat.f_mntonname + size, 2232893Sdfr sizeof(mp->mnt_stat.f_mntonname) - size); 2242893Sdfr copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size); 2252893Sdfr bzero(mp->mnt_stat.f_mntfromname + size, 2262893Sdfr MNAMELEN - size); 2272893Sdfr pmp->pm_mounter = p->p_cred->p_ruid; 2282893Sdfr pmp->pm_gid = args.gid; 2292893Sdfr pmp->pm_uid = args.uid; 2302893Sdfr pmp->pm_mask = args.mask; 2312893Sdfr (void) msdosfs_statfs(mp, &mp->mnt_stat, p); 2322893Sdfr#ifdef MSDOSFS_DEBUG 2333311Sphk printf("msdosfs_mount(): mp %p, pmp %p, inusemap %p\n", mp, pmp, pmp->pm_inusemap); 2342893Sdfr#endif 2352893Sdfr return 0; 2362893Sdfr} 2372893Sdfr 23812144Sphkstatic int 2392893Sdfrmountmsdosfs(devvp, mp, p) 2402893Sdfr struct vnode *devvp; 2412893Sdfr struct mount *mp; 2422893Sdfr struct proc *p; 2432893Sdfr{ 2442893Sdfr int i; 2452893Sdfr int bpc; 2462893Sdfr int bit; 2472893Sdfr int error; 2482893Sdfr int needclose; 2492893Sdfr int ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 2502893Sdfr dev_t dev = devvp->v_rdev; 2512893Sdfr union bootsector *bsp; 2522893Sdfr struct msdosfsmount *pmp = NULL; 2532893Sdfr struct buf *bp0 = NULL; 2542893Sdfr struct byte_bpb33 *b33; 2552893Sdfr struct byte_bpb50 *b50; 2562893Sdfr 2572893Sdfr /* 2582893Sdfr * Multiple mounts of the same block special file aren't allowed. 2592893Sdfr * Make sure no one else has the special file open. And flush any 2602893Sdfr * old buffers from this filesystem. Presumably this prevents us 2612893Sdfr * from running into buffers that are the wrong blocksize. 2622893Sdfr */ 2633152Sphk error = vfs_mountedon(devvp); 2643152Sphk if (error) 2652893Sdfr return error; 2662893Sdfr if (vcount(devvp) > 1) 2672893Sdfr return EBUSY; 2683152Sphk error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0); 2693152Sphk if (error) 2702893Sdfr return error; 2712893Sdfr 2722893Sdfr /* 2732893Sdfr * Now open the block special file. 2742893Sdfr */ 2753152Sphk error = VOP_OPEN(devvp, ronly ? FREAD : FREAD | FWRITE, FSCRED, p); 2763152Sphk if (error) 2772893Sdfr return error; 2782893Sdfr needclose = 1; 2792893Sdfr#ifdef HDSUPPORT 2802893Sdfr /* 2812893Sdfr * Put this in when we support reading dos filesystems from 2822893Sdfr * partitioned harddisks. 2832893Sdfr */ 2842893Sdfr if (VOP_IOCTL(devvp, DIOCGPART, &msdosfspart, FREAD, NOCRED, p) == 0) { 2852893Sdfr } 2862893Sdfr#endif 2872893Sdfr 2882893Sdfr /* 2892893Sdfr * Read the boot sector of the filesystem, and then check the boot 2902893Sdfr * signature. If not a dos boot sector then error out. We could 2912893Sdfr * also add some checking on the bsOemName field. So far I've seen 2922893Sdfr * the following values: "IBM 3.3" "MSDOS3.3" "MSDOS5.0" 2932893Sdfr */ 2943152Sphk error = bread(devvp, 0, 512, NOCRED, &bp0); 2953152Sphk if (error) 2962893Sdfr goto error_exit; 2972893Sdfr bp0->b_flags |= B_AGE; 2982893Sdfr bsp = (union bootsector *) bp0->b_data; 2992893Sdfr b33 = (struct byte_bpb33 *) bsp->bs33.bsBPB; 3002893Sdfr b50 = (struct byte_bpb50 *) bsp->bs50.bsBPB; 3012893Sdfr#ifdef MSDOSFS_CHECKSIG 3022893Sdfr if (bsp->bs50.bsBootSectSig != BOOTSIG) { 3032893Sdfr error = EINVAL; 3042893Sdfr goto error_exit; 3052893Sdfr } 3062893Sdfr#endif 3072893Sdfr if ( bsp->bs50.bsJump[0] != 0xe9 && 3082893Sdfr (bsp->bs50.bsJump[0] != 0xeb || bsp->bs50.bsJump[2] != 0x90)) { 3092893Sdfr error = EINVAL; 3102893Sdfr goto error_exit; 3112893Sdfr } 3122893Sdfr 3132893Sdfr pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK); 3142893Sdfr bzero((caddr_t)pmp, sizeof *pmp); 3152893Sdfr pmp->pm_mountp = mp; 3162893Sdfr 3172893Sdfr /* 3182893Sdfr * Compute several useful quantities from the bpb in the 3192893Sdfr * bootsector. Copy in the dos 5 variant of the bpb then fix up 3202893Sdfr * the fields that are different between dos 5 and dos 3.3. 3212893Sdfr */ 3222893Sdfr pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec); 3232893Sdfr pmp->pm_SectPerClust = b50->bpbSecPerClust; 3242893Sdfr pmp->pm_ResSectors = getushort(b50->bpbResSectors); 3252893Sdfr pmp->pm_FATs = b50->bpbFATs; 3262893Sdfr pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts); 3272893Sdfr pmp->pm_Sectors = getushort(b50->bpbSectors); 3282893Sdfr pmp->pm_Media = b50->bpbMedia; 3292893Sdfr pmp->pm_FATsecs = getushort(b50->bpbFATsecs); 3302893Sdfr pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack); 3312893Sdfr pmp->pm_Heads = getushort(b50->bpbHeads); 3322893Sdfr 3332893Sdfr /* XXX - We should probably check more values here */ 3342893Sdfr if (!pmp->pm_BytesPerSec || !pmp->pm_SectPerClust || 3352893Sdfr !pmp->pm_Heads || pmp->pm_Heads > 255 || 3362893Sdfr !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 63) { 3372893Sdfr error = EINVAL; 3382893Sdfr goto error_exit; 3392893Sdfr } 3402893Sdfr 3412893Sdfr if (pmp->pm_Sectors == 0) { 3422893Sdfr pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs); 3432893Sdfr pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors); 3442893Sdfr } else { 3452893Sdfr pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs); 3462893Sdfr pmp->pm_HugeSectors = pmp->pm_Sectors; 3472893Sdfr } 3482893Sdfr pmp->pm_fatblk = pmp->pm_ResSectors; 3492893Sdfr pmp->pm_rootdirblk = pmp->pm_fatblk + 3502893Sdfr (pmp->pm_FATs * pmp->pm_FATsecs); 3512893Sdfr pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry)) 3522893Sdfr / 3532893Sdfr pmp->pm_BytesPerSec;/* in sectors */ 3542893Sdfr pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize; 3552893Sdfr pmp->pm_nmbrofclusters = (pmp->pm_HugeSectors - pmp->pm_firstcluster) / 3562893Sdfr pmp->pm_SectPerClust; 3572893Sdfr pmp->pm_maxcluster = pmp->pm_nmbrofclusters + 1; 3582893Sdfr pmp->pm_fatsize = pmp->pm_FATsecs * pmp->pm_BytesPerSec; 3592893Sdfr if (FAT12(pmp)) 3602893Sdfr /* 3612893Sdfr * This will usually be a floppy disk. This size makes sure 3622893Sdfr * that one fat entry will not be split across multiple 3632893Sdfr * blocks. 3642893Sdfr */ 3652893Sdfr pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec; 3662893Sdfr else 3672893Sdfr /* 3682893Sdfr * This will usually be a hard disk. Reading or writing one 3692893Sdfr * block should be quite fast. 3702893Sdfr */ 3712893Sdfr pmp->pm_fatblocksize = MAXBSIZE; 3722893Sdfr pmp->pm_fatblocksec = pmp->pm_fatblocksize / pmp->pm_BytesPerSec; 3732893Sdfr 3742893Sdfr 3752893Sdfr if ((pmp->pm_rootdirsize % pmp->pm_SectPerClust) != 0) 3762893Sdfr printf("mountmsdosfs(): root directory is not a multiple of the clustersize in length\n"); 3772893Sdfr 3782893Sdfr /* 3792893Sdfr * Compute mask and shift value for isolating cluster relative byte 3802893Sdfr * offsets and cluster numbers from a file offset. 3812893Sdfr */ 3822893Sdfr bpc = pmp->pm_SectPerClust * pmp->pm_BytesPerSec; 3832893Sdfr pmp->pm_bpcluster = bpc; 3842893Sdfr pmp->pm_depclust = bpc / sizeof(struct direntry); 3852893Sdfr pmp->pm_crbomask = bpc - 1; 3862893Sdfr if (bpc == 0) { 3872893Sdfr error = EINVAL; 3882893Sdfr goto error_exit; 3892893Sdfr } 3902893Sdfr bit = 1; 3912893Sdfr for (i = 0; i < 32; i++) { 3922893Sdfr if (bit & bpc) { 3932893Sdfr if (bit ^ bpc) { 3942893Sdfr error = EINVAL; 3952893Sdfr goto error_exit; 3962893Sdfr } 3972893Sdfr pmp->pm_cnshift = i; 3982893Sdfr break; 3992893Sdfr } 4002893Sdfr bit <<= 1; 4012893Sdfr } 4022893Sdfr 4032893Sdfr pmp->pm_brbomask = 0x01ff; /* 512 byte blocks only (so far) */ 4042893Sdfr pmp->pm_bnshift = 9; /* shift right 9 bits to get bn */ 4052893Sdfr 4062893Sdfr /* 4072893Sdfr * Release the bootsector buffer. 4082893Sdfr */ 4092893Sdfr brelse(bp0); 4102893Sdfr bp0 = NULL; 4112893Sdfr 4122893Sdfr /* 4132893Sdfr * Allocate memory for the bitmap of allocated clusters, and then 4142893Sdfr * fill it in. 4152893Sdfr */ 4162893Sdfr pmp->pm_inusemap = malloc(((pmp->pm_maxcluster + N_INUSEBITS - 1) 4172893Sdfr / N_INUSEBITS) 4182893Sdfr * sizeof(*pmp->pm_inusemap), 4192893Sdfr M_MSDOSFSFAT, M_WAITOK); 4202893Sdfr 4212893Sdfr /* 4222893Sdfr * fillinusemap() needs pm_devvp. 4232893Sdfr */ 4242893Sdfr pmp->pm_dev = dev; 4252893Sdfr pmp->pm_devvp = devvp; 4262893Sdfr 4272893Sdfr /* 4282893Sdfr * Have the inuse map filled in. 4292893Sdfr */ 4302893Sdfr error = fillinusemap(pmp); 4312893Sdfr if (error) 4322893Sdfr goto error_exit; 4332893Sdfr 4342893Sdfr /* 4352893Sdfr * If they want fat updates to be synchronous then let them suffer 4362893Sdfr * the performance degradation in exchange for the on disk copy of 4372893Sdfr * the fat being correct just about all the time. I suppose this 4382893Sdfr * would be a good thing to turn on if the kernel is still flakey. 4392893Sdfr */ 4402893Sdfr pmp->pm_waitonfat = mp->mnt_flag & MNT_SYNCHRONOUS; 4412893Sdfr 4422893Sdfr /* 4432893Sdfr * Finish up. 4442893Sdfr */ 4452893Sdfr pmp->pm_ronly = ronly; 4462893Sdfr if (ronly == 0) 4472893Sdfr pmp->pm_fmod = 1; 4482893Sdfr mp->mnt_data = (qaddr_t) pmp; 4492893Sdfr mp->mnt_stat.f_fsid.val[0] = (long)dev; 4502893Sdfr mp->mnt_stat.f_fsid.val[1] = MOUNT_MSDOS; 4512893Sdfr mp->mnt_flag |= MNT_LOCAL; 4522893Sdfr#ifdef QUOTA 4532893Sdfr /* 4542893Sdfr * If we ever do quotas for DOS filesystems this would be a place 4552893Sdfr * to fill in the info in the msdosfsmount structure. You dolt, 4562893Sdfr * quotas on dos filesystems make no sense because files have no 4572893Sdfr * owners on dos filesystems. of course there is some empty space 4582893Sdfr * in the directory entry where we could put uid's and gid's. 4592893Sdfr */ 4602893Sdfr#endif 4612893Sdfr devvp->v_specflags |= SI_MOUNTEDON; 4622893Sdfr 4632893Sdfr return 0; 4642893Sdfr 4652893Sdfrerror_exit:; 4662893Sdfr if (bp0) 4672893Sdfr brelse(bp0); 4682893Sdfr if (needclose) 4692893Sdfr (void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD | FWRITE, 4702893Sdfr NOCRED, p); 4712893Sdfr if (pmp) { 4722893Sdfr if (pmp->pm_inusemap) 4732893Sdfr free((caddr_t) pmp->pm_inusemap, M_MSDOSFSFAT); 4742893Sdfr free((caddr_t) pmp, M_MSDOSFSMNT); 4752893Sdfr mp->mnt_data = (qaddr_t) 0; 4762893Sdfr } 4772893Sdfr return error; 4782893Sdfr} 4792893Sdfr 48012144Sphkstatic int 4812893Sdfrmsdosfs_start(mp, flags, p) 4822893Sdfr struct mount *mp; 4832893Sdfr int flags; 4842893Sdfr struct proc *p; 4852893Sdfr{ 4862893Sdfr return 0; 4872893Sdfr} 4882893Sdfr 4892893Sdfr/* 4902893Sdfr * Unmount the filesystem described by mp. 4912893Sdfr */ 49212144Sphkstatic int 4932893Sdfrmsdosfs_unmount(mp, mntflags, p) 4942893Sdfr struct mount *mp; 4952893Sdfr int mntflags; 4962893Sdfr struct proc *p; 4972893Sdfr{ 4982893Sdfr int flags = 0; 4992893Sdfr int error; 5002893Sdfr struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data; 5012893Sdfr 5022893Sdfr /* only the mounter, or superuser can unmount */ 5032893Sdfr if ((p->p_cred->p_ruid != pmp->pm_mounter) && 5042893Sdfr (error = suser(p->p_ucred, &p->p_acflag))) 5052893Sdfr return error; 5062893Sdfr 5072893Sdfr if (mntflags & MNT_FORCE) { 5082893Sdfr if (!msdosfsdoforce) 5092893Sdfr return EINVAL; 5102893Sdfr flags |= FORCECLOSE; 5112893Sdfr } 5122893Sdfr#ifdef QUOTA 5132893Sdfr#endif 5143152Sphk error = vflush(mp, NULLVP, flags); 5153152Sphk if (error) 5162893Sdfr return error; 5172893Sdfr pmp->pm_devvp->v_specflags &= ~SI_MOUNTEDON; 5182893Sdfr error = VOP_CLOSE(pmp->pm_devvp, pmp->pm_ronly ? FREAD : FREAD | FWRITE, 5192893Sdfr NOCRED, p); 5202893Sdfr vrele(pmp->pm_devvp); 5212893Sdfr free((caddr_t) pmp->pm_inusemap, M_MSDOSFSFAT); 5222893Sdfr free((caddr_t) pmp, M_MSDOSFSMNT); 5232893Sdfr mp->mnt_data = (qaddr_t) 0; 5242893Sdfr mp->mnt_flag &= ~MNT_LOCAL; 5252893Sdfr return error; 5262893Sdfr} 5272893Sdfr 52812144Sphkstatic int 5292893Sdfrmsdosfs_root(mp, vpp) 5302893Sdfr struct mount *mp; 5312893Sdfr struct vnode **vpp; 5322893Sdfr{ 5332893Sdfr struct denode *ndep; 5342893Sdfr struct msdosfsmount *pmp = (struct msdosfsmount *) (mp->mnt_data); 5352893Sdfr int error; 5362893Sdfr 5372893Sdfr error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, NULL, &ndep); 5382893Sdfr#ifdef MSDOSFS_DEBUG 5393311Sphk printf("msdosfs_root(); mp %p, pmp %p, ndep %p, vp %p\n", 5402893Sdfr mp, pmp, ndep, DETOV(ndep)); 5412893Sdfr#endif 5422893Sdfr if (error == 0) 5432893Sdfr *vpp = DETOV(ndep); 5442893Sdfr return error; 5452893Sdfr} 5462893Sdfr 54712144Sphkstatic int 5482893Sdfrmsdosfs_quotactl(mp, cmds, uid, arg, p) 5492893Sdfr struct mount *mp; 5502893Sdfr int cmds; 5512893Sdfr uid_t uid; 5522893Sdfr caddr_t arg; 5532893Sdfr struct proc *p; 5542893Sdfr{ 5552893Sdfr#ifdef QUOTA 5563152Sphk return EOPNOTSUPP; 5572893Sdfr#else 5582893Sdfr return EOPNOTSUPP; 5592893Sdfr#endif 5602893Sdfr} 5612893Sdfr 56212144Sphkstatic int 5632893Sdfrmsdosfs_statfs(mp, sbp, p) 5642893Sdfr struct mount *mp; 5652893Sdfr struct statfs *sbp; 5662893Sdfr struct proc *p; 5672893Sdfr{ 5682893Sdfr struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data; 5692893Sdfr 5702893Sdfr /* 5712893Sdfr * Fill in the stat block. 5722893Sdfr */ 5732899Sdfr sbp->f_type = MOUNT_MSDOS; 5742893Sdfr sbp->f_bsize = pmp->pm_bpcluster; 5752893Sdfr sbp->f_iosize = pmp->pm_bpcluster; 5762893Sdfr sbp->f_blocks = pmp->pm_nmbrofclusters; 5772893Sdfr sbp->f_bfree = pmp->pm_freeclustercount; 5782893Sdfr sbp->f_bavail = pmp->pm_freeclustercount; 5792893Sdfr sbp->f_files = pmp->pm_RootDirEnts; /* XXX */ 5802893Sdfr sbp->f_ffree = 0; /* what to put in here? */ 5812893Sdfr 5822893Sdfr /* 5832893Sdfr * Copy the mounted on and mounted from names into the passed in 5842893Sdfr * stat block, if it is not the one in the mount structure. 5852893Sdfr */ 5862893Sdfr if (sbp != &mp->mnt_stat) { 5872893Sdfr bcopy((caddr_t) mp->mnt_stat.f_mntonname, 5882893Sdfr (caddr_t) & sbp->f_mntonname[0], MNAMELEN); 5892893Sdfr bcopy((caddr_t) mp->mnt_stat.f_mntfromname, 5902893Sdfr (caddr_t) & sbp->f_mntfromname[0], MNAMELEN); 5912893Sdfr } 5922893Sdfr#if 0 5932893Sdfr strncpy(&sbp->f_fstypename[0], mp->mnt_op->vfs_name, MFSNAMELEN); 5942893Sdfr sbp->f_fstypename[MFSNAMELEN] = '\0'; 5952893Sdfr#endif 5962893Sdfr return 0; 5972893Sdfr} 5982893Sdfr 59912144Sphkstatic int 6002893Sdfrmsdosfs_sync(mp, waitfor, cred, p) 6012893Sdfr struct mount *mp; 6022893Sdfr int waitfor; 6032893Sdfr struct ucred *cred; 6042893Sdfr struct proc *p; 6052893Sdfr{ 6062893Sdfr struct vnode *vp; 6072893Sdfr struct denode *dep; 6082893Sdfr struct msdosfsmount *pmp; 6092893Sdfr int error; 6102893Sdfr int allerror = 0; 6112893Sdfr 6122893Sdfr pmp = (struct msdosfsmount *) mp->mnt_data; 6132893Sdfr 6142893Sdfr /* 6152893Sdfr * If we ever switch to not updating all of the fats all the time, 6162893Sdfr * this would be the place to update them from the first one. 6172893Sdfr */ 6182893Sdfr if (pmp->pm_fmod) 6192893Sdfr if (pmp->pm_ronly) 6202893Sdfr panic("msdosfs_sync: rofs mod"); 6212893Sdfr else { 6222893Sdfr /* update fats here */ 6232893Sdfr } 6242893Sdfr 6252893Sdfr /* 6262893Sdfr * Go thru in memory denodes and write them out along with 6272893Sdfr * unwritten file blocks. 6282893Sdfr */ 6292893Sdfrloop: 6302893Sdfr for (vp = mp->mnt_vnodelist.lh_first; vp; 6312893Sdfr vp = vp->v_mntvnodes.le_next) { 6322893Sdfr if (vp->v_mount != mp) /* not ours anymore */ 6332893Sdfr goto loop; 6342893Sdfr if (VOP_ISLOCKED(vp)) /* file is busy */ 6352893Sdfr continue; 6362893Sdfr dep = VTODE(vp); 6375083Sbde if ((dep->de_flag & (DE_MODIFIED | DE_UPDATE)) == 0 && 6382893Sdfr vp->v_dirtyblkhd.lh_first == NULL) 6392893Sdfr continue; 6402893Sdfr if (vget(vp, 1)) /* not there anymore? */ 6412893Sdfr goto loop; 6423152Sphk error = VOP_FSYNC(vp, cred, waitfor, p); 6433152Sphk if (error) 6442893Sdfr allerror = error; 6452893Sdfr vput(vp); /* done with this one */ 6462893Sdfr } 6472893Sdfr 6482893Sdfr /* 6492893Sdfr * Flush filesystem control info. 6502893Sdfr */ 6513152Sphk error = VOP_FSYNC(pmp->pm_devvp, cred, waitfor, p); 6523152Sphk if (error) 6532893Sdfr allerror = error; 6542893Sdfr return allerror; 6552893Sdfr} 6562893Sdfr 65712144Sphkstatic int 6582893Sdfrmsdosfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp) 6592893Sdfr struct mount *mp; 6602893Sdfr struct fid *fhp; 6612893Sdfr struct mbuf *nam; 6622893Sdfr struct vnode **vpp; 6632893Sdfr int *exflagsp; 6642893Sdfr struct ucred **credanonp; 6652893Sdfr{ 6662893Sdfr struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data; 6672893Sdfr struct defid *defhp = (struct defid *) fhp; 6682893Sdfr struct denode *dep; 6692893Sdfr struct netcred *np; 6702893Sdfr int error; 6712893Sdfr 6722893Sdfr np = vfs_export_lookup(mp, &pmp->pm_export, nam); 6732893Sdfr if (np == NULL) 6742893Sdfr return EACCES; 6752893Sdfr error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs, 6762893Sdfr NULL, &dep); 6772893Sdfr if (error) { 6782893Sdfr *vpp = NULLVP; 6792893Sdfr return error; 6802893Sdfr } 6812893Sdfr *vpp = DETOV(dep); 6822893Sdfr *exflagsp = np->netc_exflags; 6832893Sdfr *credanonp = &np->netc_anon; 6842893Sdfr return 0; 6852893Sdfr} 6862893Sdfr 6872893Sdfr 68812144Sphkstatic int 6892893Sdfrmsdosfs_vptofh(vp, fhp) 6902893Sdfr struct vnode *vp; 6912893Sdfr struct fid *fhp; 6922893Sdfr{ 6932893Sdfr struct denode *dep = VTODE(vp); 6942893Sdfr struct defid *defhp = (struct defid *) fhp; 6952893Sdfr 6962893Sdfr defhp->defid_len = sizeof(struct defid); 6972893Sdfr defhp->defid_dirclust = dep->de_dirclust; 6982893Sdfr defhp->defid_dirofs = dep->de_diroffset; 6992893Sdfr /* defhp->defid_gen = ip->i_gen; */ 7002893Sdfr return 0; 7012893Sdfr} 7022893Sdfr 70312144Sphkstatic int 7042893Sdfrmsdosfs_vget(mp, ino, vpp) 7052893Sdfr struct mount *mp; 7062893Sdfr ino_t ino; 7072893Sdfr struct vnode **vpp; 7082893Sdfr{ 7092893Sdfr return EOPNOTSUPP; 7102893Sdfr} 7112893Sdfr 71212145Sphkstatic struct vfsops msdosfs_vfsops = { 7132893Sdfr msdosfs_mount, 7142893Sdfr msdosfs_start, 7152893Sdfr msdosfs_unmount, 7162893Sdfr msdosfs_root, 7172893Sdfr msdosfs_quotactl, 7182893Sdfr msdosfs_statfs, 7192893Sdfr msdosfs_sync, 7202893Sdfr msdosfs_vget, 7212893Sdfr msdosfs_fhtovp, 7222893Sdfr msdosfs_vptofh, 7232893Sdfr msdosfs_init 7242893Sdfr}; 7252946Swollman 7262946SwollmanVFS_SET(msdosfs_vfsops, msdos, MOUNT_MSDOS, 0); 727