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