msdosfs_vfsops.c revision 2893
12893Sdfr/* $Id$ */ 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) 372893Sdfr * 382893Sdfr * You can do anything you want with this software, just don't say you wrote 392893Sdfr * it, and don't remove this notice. 402893Sdfr * 412893Sdfr * This software is provided "as is". 422893Sdfr * 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. 472893Sdfr * 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 702893Sdfrint msdosfsdoforce = 1; /* 1 = force unmount */ 712893Sdfr 722893Sdfr/* 732893Sdfr * 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 752893Sdfr * special file to treat as a filesystem. 762893Sdfr */ 772893Sdfrint 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 */ 962893Sdfr if (error = copyin(data, (caddr_t) & args, sizeof(struct msdosfs_args))) 972893Sdfr return error; 982893Sdfr 992893Sdfr /* 1002893Sdfr * If they just want to update then be sure we can do what is 1012893Sdfr * asked. Can't change a filesystem from read/write to read only. 1022893Sdfr * Why? And if they've supplied a new device file name then we 1032893Sdfr * continue, otherwise return. 1042893Sdfr */ 1052893Sdfr if (mp->mnt_flag & MNT_UPDATE) { 1062893Sdfr pmp = (struct msdosfsmount *) mp->mnt_data; 1072893Sdfr error = 0; 1082893Sdfr if (pmp->pm_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) { 1092893Sdfr flags = WRITECLOSE; 1102893Sdfr if (mp->mnt_flag & MNT_FORCE) 1112893Sdfr flags |= FORCECLOSE; 1122893Sdfr if (vfs_busy(mp)) 1132893Sdfr return EBUSY; 1142893Sdfr error = vflush(mp, NULLVP, flags); 1152893Sdfr vfs_unbusy(mp); 1162893Sdfr } 1172893Sdfr if (!error && (mp->mnt_flag & MNT_RELOAD)) 1182893Sdfr /* not yet implemented */ 1192893Sdfr error = EINVAL; 1202893Sdfr if (error) 1212893Sdfr return error; 1222893Sdfr if (pmp->pm_ronly && (mp->mnt_flag & MNT_RDONLY) == 0) 1232893Sdfr pmp->pm_ronly = 0; 1242893Sdfr if (args.fspec == 0) { 1252893Sdfr /* 1262893Sdfr * Process export requests. 1272893Sdfr */ 1282893Sdfr return vfs_export(mp, &pmp->pm_export, &args.export); 1292893Sdfr } 1302893Sdfr } else 1312893Sdfr pmp = NULL; 1322893Sdfr 1332893Sdfr /* 1342893Sdfr * check to see that the user in owns the target directory. 1352893Sdfr * Note the very XXX trick to make sure we're checking as the 1362893Sdfr * real user -- were mount() executable by anyone, this wouldn't 1372893Sdfr * be a problem. 1382893Sdfr * 1392893Sdfr * XXX there should be one consistent error out. 1402893Sdfr */ 1412893Sdfr cred = crdup(p->p_ucred); /* XXX */ 1422893Sdfr cred->cr_uid = p->p_cred->p_ruid; /* XXX */ 1432893Sdfr error = VOP_GETATTR(mp->mnt_vnodecovered, &va, cred, p); 1442893Sdfr if (error) { 1452893Sdfr crfree(cred); /* XXX */ 1462893Sdfr return error; 1472893Sdfr } 1482893Sdfr if (cred->cr_uid != 0) { 1492893Sdfr if (va.va_uid != cred->cr_uid) { 1502893Sdfr error = EACCES; 1512893Sdfr crfree(cred); /* XXX */ 1522893Sdfr return error; 1532893Sdfr } 1542893Sdfr 1552893Sdfr /* a user mounted it; we'll verify permissions when unmounting */ 1562893Sdfr mp->mnt_flag |= MNT_USER; 1572893Sdfr } 1582893Sdfr 1592893Sdfr /* 1602893Sdfr * Now, lookup the name of the block device this mount or name 1612893Sdfr * update request is to apply to. 1622893Sdfr */ 1632893Sdfr NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p); 1642893Sdfr scred = p->p_ucred; /* XXX */ 1652893Sdfr p->p_ucred = cred; /* XXX */ 1662893Sdfr error = namei(ndp); 1672893Sdfr p->p_ucred = scred; /* XXX */ 1682893Sdfr crfree(cred); /* XXX */ 1692893Sdfr if (error != 0) 1702893Sdfr return error; 1712893Sdfr 1722893Sdfr /* 1732893Sdfr * Be sure they've given us a block device to treat as a 1742893Sdfr * filesystem. And, that its major number is within the bdevsw 1752893Sdfr * table. 1762893Sdfr */ 1772893Sdfr devvp = ndp->ni_vp; 1782893Sdfr if (devvp->v_type != VBLK) { 1792893Sdfr vrele(devvp); 1802893Sdfr return ENOTBLK; 1812893Sdfr } 1822893Sdfr if (major(devvp->v_rdev) >= nblkdev) { 1832893Sdfr vrele(devvp); 1842893Sdfr return ENXIO; 1852893Sdfr } 1862893Sdfr 1872893Sdfr /* 1882893Sdfr * If this is an update, then make sure the vnode for the block 1892893Sdfr * special device is the same as the one our filesystem is in. 1902893Sdfr */ 1912893Sdfr if (mp->mnt_flag & MNT_UPDATE) { 1922893Sdfr if (devvp != pmp->pm_devvp) 1932893Sdfr error = EINVAL; 1942893Sdfr else 1952893Sdfr vrele(devvp); 1962893Sdfr } else { 1972893Sdfr 1982893Sdfr /* 1992893Sdfr * Well, it's not an update, it's a real mount request. 2002893Sdfr * Time to get dirty. 2012893Sdfr */ 2022893Sdfr error = mountmsdosfs(devvp, mp, p); 2032893Sdfr } 2042893Sdfr if (error) { 2052893Sdfr vrele(devvp); 2062893Sdfr return error; 2072893Sdfr } 2082893Sdfr 2092893Sdfr /* 2102893Sdfr * Copy in the name of the directory the filesystem is to be 2112893Sdfr * mounted on. Then copy in the name of the block special file 2122893Sdfr * representing the filesystem being mounted. And we clear the 2132893Sdfr * remainder of the character strings to be tidy. Set up the 2142893Sdfr * user id/group id/mask as specified by the user. Then, we try to 2152893Sdfr * fill in the filesystem stats structure as best we can with 2162893Sdfr * whatever applies from a dos file system. 2172893Sdfr */ 2182893Sdfr pmp = (struct msdosfsmount *) mp->mnt_data; 2192893Sdfr copyinstr(path, (caddr_t) mp->mnt_stat.f_mntonname, 2202893Sdfr sizeof(mp->mnt_stat.f_mntonname) - 1, &size); 2212893Sdfr bzero(mp->mnt_stat.f_mntonname + size, 2222893Sdfr sizeof(mp->mnt_stat.f_mntonname) - size); 2232893Sdfr copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size); 2242893Sdfr bzero(mp->mnt_stat.f_mntfromname + size, 2252893Sdfr MNAMELEN - size); 2262893Sdfr pmp->pm_mounter = p->p_cred->p_ruid; 2272893Sdfr pmp->pm_gid = args.gid; 2282893Sdfr pmp->pm_uid = args.uid; 2292893Sdfr pmp->pm_mask = args.mask; 2302893Sdfr (void) msdosfs_statfs(mp, &mp->mnt_stat, p); 2312893Sdfr#ifdef MSDOSFS_DEBUG 2322893Sdfr printf("msdosfs_mount(): mp %x, pmp %x, inusemap %x\n", mp, pmp, pmp->pm_inusemap); 2332893Sdfr#endif 2342893Sdfr return 0; 2352893Sdfr} 2362893Sdfr 2372893Sdfrint 2382893Sdfrmountmsdosfs(devvp, mp, p) 2392893Sdfr struct vnode *devvp; 2402893Sdfr struct mount *mp; 2412893Sdfr struct proc *p; 2422893Sdfr{ 2432893Sdfr int i; 2442893Sdfr int bpc; 2452893Sdfr int bit; 2462893Sdfr int error; 2472893Sdfr int needclose; 2482893Sdfr int ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 2492893Sdfr dev_t dev = devvp->v_rdev; 2502893Sdfr union bootsector *bsp; 2512893Sdfr struct msdosfsmount *pmp = NULL; 2522893Sdfr struct buf *bp0 = NULL; 2532893Sdfr struct byte_bpb33 *b33; 2542893Sdfr struct byte_bpb50 *b50; 2552893Sdfr 2562893Sdfr /* 2572893Sdfr * Multiple mounts of the same block special file aren't allowed. 2582893Sdfr * Make sure no one else has the special file open. And flush any 2592893Sdfr * old buffers from this filesystem. Presumably this prevents us 2602893Sdfr * from running into buffers that are the wrong blocksize. 2612893Sdfr */ 2622893Sdfr if (error = vfs_mountedon(devvp)) 2632893Sdfr return error; 2642893Sdfr if (vcount(devvp) > 1) 2652893Sdfr return EBUSY; 2662893Sdfr if (error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0)) 2672893Sdfr return error; 2682893Sdfr 2692893Sdfr /* 2702893Sdfr * Now open the block special file. 2712893Sdfr */ 2722893Sdfr if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD | FWRITE, FSCRED, p)) 2732893Sdfr return error; 2742893Sdfr needclose = 1; 2752893Sdfr#ifdef HDSUPPORT 2762893Sdfr /* 2772893Sdfr * Put this in when we support reading dos filesystems from 2782893Sdfr * partitioned harddisks. 2792893Sdfr */ 2802893Sdfr if (VOP_IOCTL(devvp, DIOCGPART, &msdosfspart, FREAD, NOCRED, p) == 0) { 2812893Sdfr } 2822893Sdfr#endif 2832893Sdfr 2842893Sdfr /* 2852893Sdfr * Read the boot sector of the filesystem, and then check the boot 2862893Sdfr * signature. If not a dos boot sector then error out. We could 2872893Sdfr * also add some checking on the bsOemName field. So far I've seen 2882893Sdfr * the following values: "IBM 3.3" "MSDOS3.3" "MSDOS5.0" 2892893Sdfr */ 2902893Sdfr if (error = bread(devvp, 0, 512, NOCRED, &bp0)) 2912893Sdfr goto error_exit; 2922893Sdfr bp0->b_flags |= B_AGE; 2932893Sdfr bsp = (union bootsector *) bp0->b_data; 2942893Sdfr b33 = (struct byte_bpb33 *) bsp->bs33.bsBPB; 2952893Sdfr b50 = (struct byte_bpb50 *) bsp->bs50.bsBPB; 2962893Sdfr#ifdef MSDOSFS_CHECKSIG 2972893Sdfr if (bsp->bs50.bsBootSectSig != BOOTSIG) { 2982893Sdfr error = EINVAL; 2992893Sdfr goto error_exit; 3002893Sdfr } 3012893Sdfr#endif 3022893Sdfr if ( bsp->bs50.bsJump[0] != 0xe9 && 3032893Sdfr (bsp->bs50.bsJump[0] != 0xeb || bsp->bs50.bsJump[2] != 0x90)) { 3042893Sdfr error = EINVAL; 3052893Sdfr goto error_exit; 3062893Sdfr } 3072893Sdfr 3082893Sdfr pmp = malloc(sizeof *pmp, M_MSDOSFSMNT, M_WAITOK); 3092893Sdfr bzero((caddr_t)pmp, sizeof *pmp); 3102893Sdfr pmp->pm_mountp = mp; 3112893Sdfr 3122893Sdfr /* 3132893Sdfr * Compute several useful quantities from the bpb in the 3142893Sdfr * bootsector. Copy in the dos 5 variant of the bpb then fix up 3152893Sdfr * the fields that are different between dos 5 and dos 3.3. 3162893Sdfr */ 3172893Sdfr pmp->pm_BytesPerSec = getushort(b50->bpbBytesPerSec); 3182893Sdfr pmp->pm_SectPerClust = b50->bpbSecPerClust; 3192893Sdfr pmp->pm_ResSectors = getushort(b50->bpbResSectors); 3202893Sdfr pmp->pm_FATs = b50->bpbFATs; 3212893Sdfr pmp->pm_RootDirEnts = getushort(b50->bpbRootDirEnts); 3222893Sdfr pmp->pm_Sectors = getushort(b50->bpbSectors); 3232893Sdfr pmp->pm_Media = b50->bpbMedia; 3242893Sdfr pmp->pm_FATsecs = getushort(b50->bpbFATsecs); 3252893Sdfr pmp->pm_SecPerTrack = getushort(b50->bpbSecPerTrack); 3262893Sdfr pmp->pm_Heads = getushort(b50->bpbHeads); 3272893Sdfr 3282893Sdfr /* XXX - We should probably check more values here */ 3292893Sdfr if (!pmp->pm_BytesPerSec || !pmp->pm_SectPerClust || 3302893Sdfr !pmp->pm_Heads || pmp->pm_Heads > 255 || 3312893Sdfr !pmp->pm_SecPerTrack || pmp->pm_SecPerTrack > 63) { 3322893Sdfr error = EINVAL; 3332893Sdfr goto error_exit; 3342893Sdfr } 3352893Sdfr 3362893Sdfr if (pmp->pm_Sectors == 0) { 3372893Sdfr pmp->pm_HiddenSects = getulong(b50->bpbHiddenSecs); 3382893Sdfr pmp->pm_HugeSectors = getulong(b50->bpbHugeSectors); 3392893Sdfr } else { 3402893Sdfr pmp->pm_HiddenSects = getushort(b33->bpbHiddenSecs); 3412893Sdfr pmp->pm_HugeSectors = pmp->pm_Sectors; 3422893Sdfr } 3432893Sdfr pmp->pm_fatblk = pmp->pm_ResSectors; 3442893Sdfr pmp->pm_rootdirblk = pmp->pm_fatblk + 3452893Sdfr (pmp->pm_FATs * pmp->pm_FATsecs); 3462893Sdfr pmp->pm_rootdirsize = (pmp->pm_RootDirEnts * sizeof(struct direntry)) 3472893Sdfr / 3482893Sdfr pmp->pm_BytesPerSec;/* in sectors */ 3492893Sdfr pmp->pm_firstcluster = pmp->pm_rootdirblk + pmp->pm_rootdirsize; 3502893Sdfr pmp->pm_nmbrofclusters = (pmp->pm_HugeSectors - pmp->pm_firstcluster) / 3512893Sdfr pmp->pm_SectPerClust; 3522893Sdfr pmp->pm_maxcluster = pmp->pm_nmbrofclusters + 1; 3532893Sdfr pmp->pm_fatsize = pmp->pm_FATsecs * pmp->pm_BytesPerSec; 3542893Sdfr if (FAT12(pmp)) 3552893Sdfr /* 3562893Sdfr * This will usually be a floppy disk. This size makes sure 3572893Sdfr * that one fat entry will not be split across multiple 3582893Sdfr * blocks. 3592893Sdfr */ 3602893Sdfr pmp->pm_fatblocksize = 3 * pmp->pm_BytesPerSec; 3612893Sdfr else 3622893Sdfr /* 3632893Sdfr * This will usually be a hard disk. Reading or writing one 3642893Sdfr * block should be quite fast. 3652893Sdfr */ 3662893Sdfr pmp->pm_fatblocksize = MAXBSIZE; 3672893Sdfr pmp->pm_fatblocksec = pmp->pm_fatblocksize / pmp->pm_BytesPerSec; 3682893Sdfr 3692893Sdfr 3702893Sdfr if ((pmp->pm_rootdirsize % pmp->pm_SectPerClust) != 0) 3712893Sdfr printf("mountmsdosfs(): root directory is not a multiple of the clustersize in length\n"); 3722893Sdfr 3732893Sdfr /* 3742893Sdfr * Compute mask and shift value for isolating cluster relative byte 3752893Sdfr * offsets and cluster numbers from a file offset. 3762893Sdfr */ 3772893Sdfr bpc = pmp->pm_SectPerClust * pmp->pm_BytesPerSec; 3782893Sdfr pmp->pm_bpcluster = bpc; 3792893Sdfr pmp->pm_depclust = bpc / sizeof(struct direntry); 3802893Sdfr pmp->pm_crbomask = bpc - 1; 3812893Sdfr if (bpc == 0) { 3822893Sdfr error = EINVAL; 3832893Sdfr goto error_exit; 3842893Sdfr } 3852893Sdfr bit = 1; 3862893Sdfr for (i = 0; i < 32; i++) { 3872893Sdfr if (bit & bpc) { 3882893Sdfr if (bit ^ bpc) { 3892893Sdfr error = EINVAL; 3902893Sdfr goto error_exit; 3912893Sdfr } 3922893Sdfr pmp->pm_cnshift = i; 3932893Sdfr break; 3942893Sdfr } 3952893Sdfr bit <<= 1; 3962893Sdfr } 3972893Sdfr 3982893Sdfr pmp->pm_brbomask = 0x01ff; /* 512 byte blocks only (so far) */ 3992893Sdfr pmp->pm_bnshift = 9; /* shift right 9 bits to get bn */ 4002893Sdfr 4012893Sdfr /* 4022893Sdfr * Release the bootsector buffer. 4032893Sdfr */ 4042893Sdfr brelse(bp0); 4052893Sdfr bp0 = NULL; 4062893Sdfr 4072893Sdfr /* 4082893Sdfr * Allocate memory for the bitmap of allocated clusters, and then 4092893Sdfr * fill it in. 4102893Sdfr */ 4112893Sdfr pmp->pm_inusemap = malloc(((pmp->pm_maxcluster + N_INUSEBITS - 1) 4122893Sdfr / N_INUSEBITS) 4132893Sdfr * sizeof(*pmp->pm_inusemap), 4142893Sdfr M_MSDOSFSFAT, M_WAITOK); 4152893Sdfr 4162893Sdfr /* 4172893Sdfr * fillinusemap() needs pm_devvp. 4182893Sdfr */ 4192893Sdfr pmp->pm_dev = dev; 4202893Sdfr pmp->pm_devvp = devvp; 4212893Sdfr 4222893Sdfr /* 4232893Sdfr * Have the inuse map filled in. 4242893Sdfr */ 4252893Sdfr error = fillinusemap(pmp); 4262893Sdfr if (error) 4272893Sdfr goto error_exit; 4282893Sdfr 4292893Sdfr /* 4302893Sdfr * If they want fat updates to be synchronous then let them suffer 4312893Sdfr * the performance degradation in exchange for the on disk copy of 4322893Sdfr * the fat being correct just about all the time. I suppose this 4332893Sdfr * would be a good thing to turn on if the kernel is still flakey. 4342893Sdfr */ 4352893Sdfr pmp->pm_waitonfat = mp->mnt_flag & MNT_SYNCHRONOUS; 4362893Sdfr 4372893Sdfr /* 4382893Sdfr * Finish up. 4392893Sdfr */ 4402893Sdfr pmp->pm_ronly = ronly; 4412893Sdfr if (ronly == 0) 4422893Sdfr pmp->pm_fmod = 1; 4432893Sdfr mp->mnt_data = (qaddr_t) pmp; 4442893Sdfr mp->mnt_stat.f_fsid.val[0] = (long)dev; 4452893Sdfr mp->mnt_stat.f_fsid.val[1] = MOUNT_MSDOS; 4462893Sdfr mp->mnt_flag |= MNT_LOCAL; 4472893Sdfr#ifdef QUOTA 4482893Sdfr /* 4492893Sdfr * If we ever do quotas for DOS filesystems this would be a place 4502893Sdfr * to fill in the info in the msdosfsmount structure. You dolt, 4512893Sdfr * quotas on dos filesystems make no sense because files have no 4522893Sdfr * owners on dos filesystems. of course there is some empty space 4532893Sdfr * in the directory entry where we could put uid's and gid's. 4542893Sdfr */ 4552893Sdfr#endif 4562893Sdfr devvp->v_specflags |= SI_MOUNTEDON; 4572893Sdfr 4582893Sdfr return 0; 4592893Sdfr 4602893Sdfrerror_exit:; 4612893Sdfr if (bp0) 4622893Sdfr brelse(bp0); 4632893Sdfr if (needclose) 4642893Sdfr (void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD | FWRITE, 4652893Sdfr NOCRED, p); 4662893Sdfr if (pmp) { 4672893Sdfr if (pmp->pm_inusemap) 4682893Sdfr free((caddr_t) pmp->pm_inusemap, M_MSDOSFSFAT); 4692893Sdfr free((caddr_t) pmp, M_MSDOSFSMNT); 4702893Sdfr mp->mnt_data = (qaddr_t) 0; 4712893Sdfr } 4722893Sdfr return error; 4732893Sdfr} 4742893Sdfr 4752893Sdfrint 4762893Sdfrmsdosfs_start(mp, flags, p) 4772893Sdfr struct mount *mp; 4782893Sdfr int flags; 4792893Sdfr struct proc *p; 4802893Sdfr{ 4812893Sdfr return 0; 4822893Sdfr} 4832893Sdfr 4842893Sdfr/* 4852893Sdfr * Unmount the filesystem described by mp. 4862893Sdfr */ 4872893Sdfrint 4882893Sdfrmsdosfs_unmount(mp, mntflags, p) 4892893Sdfr struct mount *mp; 4902893Sdfr int mntflags; 4912893Sdfr struct proc *p; 4922893Sdfr{ 4932893Sdfr int flags = 0; 4942893Sdfr int error; 4952893Sdfr struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data; 4962893Sdfr struct vnode *vp = pmp->pm_devvp; 4972893Sdfr 4982893Sdfr /* only the mounter, or superuser can unmount */ 4992893Sdfr if ((p->p_cred->p_ruid != pmp->pm_mounter) && 5002893Sdfr (error = suser(p->p_ucred, &p->p_acflag))) 5012893Sdfr return error; 5022893Sdfr 5032893Sdfr if (mntflags & MNT_FORCE) { 5042893Sdfr if (!msdosfsdoforce) 5052893Sdfr return EINVAL; 5062893Sdfr flags |= FORCECLOSE; 5072893Sdfr } 5082893Sdfr#ifdef QUOTA 5092893Sdfr#endif 5102893Sdfr if (error = vflush(mp, NULLVP, flags)) 5112893Sdfr return error; 5122893Sdfr pmp->pm_devvp->v_specflags &= ~SI_MOUNTEDON; 5132893Sdfr#ifdef MSDOSFS_DEBUG 5142893Sdfr printf("msdosfs_umount(): just before calling VOP_CLOSE()\n"); 5152893Sdfr printf("flag %08x, usecount %d, writecount %d, holdcnt %d\n", 5162893Sdfr vp->v_flag, vp->v_usecount, vp->v_writecount, vp->v_holdcnt); 5172893Sdfr printf("lastr %d, id %d, mount %08x, op %08x\n", 5182893Sdfr vp->v_lastr, vp->v_id, vp->v_mount, vp->v_op); 5192893Sdfr printf("freef %08x, freeb %08x, mountf %08x, mountb %08x\n", 5202893Sdfr vp->v_freef, vp->v_freeb, vp->v_mountf, vp->v_mountb); 5212893Sdfr printf("cleanblkhd %08x, dirtyblkhd %08x, numoutput %d, type %d\n", 5222893Sdfr vp->v_cleanblkhd, vp->v_dirtyblkhd, vp->v_numoutput, vp->v_type); 5232893Sdfr printf("union %08x, tag %d, data[0] %08x, data[1] %08x\n", 5242893Sdfr vp->v_socket, vp->v_tag, vp->v_data[0], vp->v_data[1]); 5252893Sdfr#endif 5262893Sdfr error = VOP_CLOSE(pmp->pm_devvp, pmp->pm_ronly ? FREAD : FREAD | FWRITE, 5272893Sdfr NOCRED, p); 5282893Sdfr vrele(pmp->pm_devvp); 5292893Sdfr free((caddr_t) pmp->pm_inusemap, M_MSDOSFSFAT); 5302893Sdfr free((caddr_t) pmp, M_MSDOSFSMNT); 5312893Sdfr mp->mnt_data = (qaddr_t) 0; 5322893Sdfr mp->mnt_flag &= ~MNT_LOCAL; 5332893Sdfr return error; 5342893Sdfr} 5352893Sdfr 5362893Sdfrint 5372893Sdfrmsdosfs_root(mp, vpp) 5382893Sdfr struct mount *mp; 5392893Sdfr struct vnode **vpp; 5402893Sdfr{ 5412893Sdfr struct denode *ndep; 5422893Sdfr struct msdosfsmount *pmp = (struct msdosfsmount *) (mp->mnt_data); 5432893Sdfr int error; 5442893Sdfr 5452893Sdfr error = deget(pmp, MSDOSFSROOT, MSDOSFSROOT_OFS, NULL, &ndep); 5462893Sdfr#ifdef MSDOSFS_DEBUG 5472893Sdfr printf("msdosfs_root(); mp %08x, pmp %08x, ndep %08x, vp %08x\n", 5482893Sdfr mp, pmp, ndep, DETOV(ndep)); 5492893Sdfr#endif 5502893Sdfr if (error == 0) 5512893Sdfr *vpp = DETOV(ndep); 5522893Sdfr return error; 5532893Sdfr} 5542893Sdfr 5552893Sdfrint 5562893Sdfrmsdosfs_quotactl(mp, cmds, uid, arg, p) 5572893Sdfr struct mount *mp; 5582893Sdfr int cmds; 5592893Sdfr uid_t uid; 5602893Sdfr caddr_t arg; 5612893Sdfr struct proc *p; 5622893Sdfr{ 5632893Sdfr#ifdef QUOTA 5642893Sdfr#else 5652893Sdfr return EOPNOTSUPP; 5662893Sdfr#endif 5672893Sdfr} 5682893Sdfr 5692893Sdfrint 5702893Sdfrmsdosfs_statfs(mp, sbp, p) 5712893Sdfr struct mount *mp; 5722893Sdfr struct statfs *sbp; 5732893Sdfr struct proc *p; 5742893Sdfr{ 5752893Sdfr struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data; 5762893Sdfr 5772893Sdfr /* 5782893Sdfr * Fill in the stat block. 5792893Sdfr */ 5802893Sdfr#ifdef COMPAT_09 5812893Sdfr sbp->f_type = 4; 5822893Sdfr#else 5832893Sdfr sbp->f_type = 0; 5842893Sdfr#endif 5852893Sdfr sbp->f_bsize = pmp->pm_bpcluster; 5862893Sdfr sbp->f_iosize = pmp->pm_bpcluster; 5872893Sdfr sbp->f_blocks = pmp->pm_nmbrofclusters; 5882893Sdfr sbp->f_bfree = pmp->pm_freeclustercount; 5892893Sdfr sbp->f_bavail = pmp->pm_freeclustercount; 5902893Sdfr sbp->f_files = pmp->pm_RootDirEnts; /* XXX */ 5912893Sdfr sbp->f_ffree = 0; /* what to put in here? */ 5922893Sdfr 5932893Sdfr /* 5942893Sdfr * Copy the mounted on and mounted from names into the passed in 5952893Sdfr * stat block, if it is not the one in the mount structure. 5962893Sdfr */ 5972893Sdfr if (sbp != &mp->mnt_stat) { 5982893Sdfr bcopy((caddr_t) mp->mnt_stat.f_mntonname, 5992893Sdfr (caddr_t) & sbp->f_mntonname[0], MNAMELEN); 6002893Sdfr bcopy((caddr_t) mp->mnt_stat.f_mntfromname, 6012893Sdfr (caddr_t) & sbp->f_mntfromname[0], MNAMELEN); 6022893Sdfr } 6032893Sdfr#if 0 6042893Sdfr strncpy(&sbp->f_fstypename[0], mp->mnt_op->vfs_name, MFSNAMELEN); 6052893Sdfr sbp->f_fstypename[MFSNAMELEN] = '\0'; 6062893Sdfr#endif 6072893Sdfr return 0; 6082893Sdfr} 6092893Sdfr 6102893Sdfrint 6112893Sdfrmsdosfs_sync(mp, waitfor, cred, p) 6122893Sdfr struct mount *mp; 6132893Sdfr int waitfor; 6142893Sdfr struct ucred *cred; 6152893Sdfr struct proc *p; 6162893Sdfr{ 6172893Sdfr struct vnode *vp; 6182893Sdfr struct denode *dep; 6192893Sdfr struct msdosfsmount *pmp; 6202893Sdfr int error; 6212893Sdfr int allerror = 0; 6222893Sdfr 6232893Sdfr pmp = (struct msdosfsmount *) mp->mnt_data; 6242893Sdfr 6252893Sdfr /* 6262893Sdfr * If we ever switch to not updating all of the fats all the time, 6272893Sdfr * this would be the place to update them from the first one. 6282893Sdfr */ 6292893Sdfr if (pmp->pm_fmod) 6302893Sdfr if (pmp->pm_ronly) 6312893Sdfr panic("msdosfs_sync: rofs mod"); 6322893Sdfr else { 6332893Sdfr /* update fats here */ 6342893Sdfr } 6352893Sdfr 6362893Sdfr /* 6372893Sdfr * Go thru in memory denodes and write them out along with 6382893Sdfr * unwritten file blocks. 6392893Sdfr */ 6402893Sdfrloop: 6412893Sdfr for (vp = mp->mnt_vnodelist.lh_first; vp; 6422893Sdfr vp = vp->v_mntvnodes.le_next) { 6432893Sdfr if (vp->v_mount != mp) /* not ours anymore */ 6442893Sdfr goto loop; 6452893Sdfr if (VOP_ISLOCKED(vp)) /* file is busy */ 6462893Sdfr continue; 6472893Sdfr dep = VTODE(vp); 6482893Sdfr if ((dep->de_flag & DE_UPDATE) == 0 && 6492893Sdfr vp->v_dirtyblkhd.lh_first == NULL) 6502893Sdfr continue; 6512893Sdfr if (vget(vp, 1)) /* not there anymore? */ 6522893Sdfr goto loop; 6532893Sdfr if (error = VOP_FSYNC(vp, cred, waitfor, p)) 6542893Sdfr allerror = error; 6552893Sdfr vput(vp); /* done with this one */ 6562893Sdfr } 6572893Sdfr 6582893Sdfr /* 6592893Sdfr * Flush filesystem control info. 6602893Sdfr */ 6612893Sdfr if (error = VOP_FSYNC(pmp->pm_devvp, cred, waitfor, p)) 6622893Sdfr allerror = error; 6632893Sdfr return allerror; 6642893Sdfr} 6652893Sdfr 6662893Sdfrint 6672893Sdfrmsdosfs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp) 6682893Sdfr struct mount *mp; 6692893Sdfr struct fid *fhp; 6702893Sdfr struct mbuf *nam; 6712893Sdfr struct vnode **vpp; 6722893Sdfr int *exflagsp; 6732893Sdfr struct ucred **credanonp; 6742893Sdfr{ 6752893Sdfr struct msdosfsmount *pmp = (struct msdosfsmount *) mp->mnt_data; 6762893Sdfr struct defid *defhp = (struct defid *) fhp; 6772893Sdfr struct denode *dep; 6782893Sdfr struct netcred *np; 6792893Sdfr int error; 6802893Sdfr 6812893Sdfr np = vfs_export_lookup(mp, &pmp->pm_export, nam); 6822893Sdfr if (np == NULL) 6832893Sdfr return EACCES; 6842893Sdfr error = deget(pmp, defhp->defid_dirclust, defhp->defid_dirofs, 6852893Sdfr NULL, &dep); 6862893Sdfr if (error) { 6872893Sdfr *vpp = NULLVP; 6882893Sdfr return error; 6892893Sdfr } 6902893Sdfr *vpp = DETOV(dep); 6912893Sdfr *exflagsp = np->netc_exflags; 6922893Sdfr *credanonp = &np->netc_anon; 6932893Sdfr return 0; 6942893Sdfr} 6952893Sdfr 6962893Sdfr 6972893Sdfrint 6982893Sdfrmsdosfs_vptofh(vp, fhp) 6992893Sdfr struct vnode *vp; 7002893Sdfr struct fid *fhp; 7012893Sdfr{ 7022893Sdfr struct denode *dep = VTODE(vp); 7032893Sdfr struct defid *defhp = (struct defid *) fhp; 7042893Sdfr 7052893Sdfr defhp->defid_len = sizeof(struct defid); 7062893Sdfr defhp->defid_dirclust = dep->de_dirclust; 7072893Sdfr defhp->defid_dirofs = dep->de_diroffset; 7082893Sdfr /* defhp->defid_gen = ip->i_gen; */ 7092893Sdfr return 0; 7102893Sdfr} 7112893Sdfr 7122893Sdfrint 7132893Sdfrmsdosfs_vget(mp, ino, vpp) 7142893Sdfr struct mount *mp; 7152893Sdfr ino_t ino; 7162893Sdfr struct vnode **vpp; 7172893Sdfr{ 7182893Sdfr return EOPNOTSUPP; 7192893Sdfr} 7202893Sdfr 7212893Sdfrstruct vfsops msdosfs_vfsops = { 7222893Sdfr msdosfs_mount, 7232893Sdfr msdosfs_start, 7242893Sdfr msdosfs_unmount, 7252893Sdfr msdosfs_root, 7262893Sdfr msdosfs_quotactl, 7272893Sdfr msdosfs_statfs, 7282893Sdfr msdosfs_sync, 7292893Sdfr msdosfs_vget, 7302893Sdfr msdosfs_fhtovp, 7312893Sdfr msdosfs_vptofh, 7322893Sdfr msdosfs_init 7332893Sdfr}; 734