xref: /openbsd-src/sys/ntfs/ntfs_vfsops.c (revision 9593dc34da13a12012033a17061c846c208061c2)
1*9593dc34Smglocker /*	$OpenBSD: ntfs_vfsops.c,v 1.66 2024/09/04 07:54:53 mglocker Exp $	*/
226f3deacStedu /*	$NetBSD: ntfs_vfsops.c,v 1.7 2003/04/24 07:50:19 christos Exp $	*/
326f3deacStedu 
426f3deacStedu /*-
526f3deacStedu  * Copyright (c) 1998, 1999 Semen Ustimenko
626f3deacStedu  * All rights reserved.
726f3deacStedu  *
826f3deacStedu  * Redistribution and use in source and binary forms, with or without
926f3deacStedu  * modification, are permitted provided that the following conditions
1026f3deacStedu  * are met:
1126f3deacStedu  * 1. Redistributions of source code must retain the above copyright
1226f3deacStedu  *    notice, this list of conditions and the following disclaimer.
1326f3deacStedu  * 2. Redistributions in binary form must reproduce the above copyright
1426f3deacStedu  *    notice, this list of conditions and the following disclaimer in the
1526f3deacStedu  *    documentation and/or other materials provided with the distribution.
1626f3deacStedu  *
1726f3deacStedu  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1826f3deacStedu  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1926f3deacStedu  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2026f3deacStedu  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2126f3deacStedu  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2226f3deacStedu  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2326f3deacStedu  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2426f3deacStedu  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2526f3deacStedu  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2626f3deacStedu  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2726f3deacStedu  * SUCH DAMAGE.
2826f3deacStedu  *
2926f3deacStedu  *	Id: ntfs_vfsops.c,v 1.7 1999/05/31 11:28:30 phk Exp
3026f3deacStedu  */
3126f3deacStedu 
3226f3deacStedu #include <sys/param.h>
3326f3deacStedu #include <sys/systm.h>
3426f3deacStedu #include <sys/namei.h>
3526f3deacStedu #include <sys/proc.h>
3626f3deacStedu #include <sys/kernel.h>
3726f3deacStedu #include <sys/vnode.h>
380ae9dfeaStedu #include <sys/lock.h>
3926f3deacStedu #include <sys/mount.h>
4026f3deacStedu #include <sys/buf.h>
41ca666729Sjsing #include <sys/disk.h>
4226f3deacStedu #include <sys/fcntl.h>
4326f3deacStedu #include <sys/malloc.h>
4426f3deacStedu #include <sys/device.h>
4526f3deacStedu #include <sys/conf.h>
46544451c3Sderaadt #include <sys/specdev.h>
4726f3deacStedu 
4826f3deacStedu /*#define NTFS_DEBUG 1*/
4926f3deacStedu #include <ntfs/ntfs.h>
5026f3deacStedu #include <ntfs/ntfs_inode.h>
5126f3deacStedu #include <ntfs/ntfs_subr.h>
5226f3deacStedu #include <ntfs/ntfs_vfsops.h>
5326f3deacStedu #include <ntfs/ntfs_ihash.h>
5426f3deacStedu 
5505c5dae5Sjsing int	ntfs_mount(struct mount *, const char *, void *,
5690337d88Stedu 				struct nameidata *, struct proc *);
5705c5dae5Sjsing int	ntfs_quotactl(struct mount *, int, uid_t, caddr_t,
5890337d88Stedu 				   struct proc *);
5905c5dae5Sjsing int	ntfs_root(struct mount *, struct vnode **);
6005c5dae5Sjsing int	ntfs_start(struct mount *, int, struct proc *);
6105c5dae5Sjsing int	ntfs_statfs(struct mount *, struct statfs *,
6290337d88Stedu 				 struct proc *);
63976e9839Sderaadt int	ntfs_sync(struct mount *, int, int, struct ucred *,
6490337d88Stedu 			       struct proc *);
6505c5dae5Sjsing int	ntfs_unmount(struct mount *, int, struct proc *);
6605c5dae5Sjsing int	ntfs_vget(struct mount *mp, ino_t ino,
6790337d88Stedu 			       struct vnode **vpp);
6805c5dae5Sjsing int	ntfs_mountfs(struct vnode *, struct mount *,
6990337d88Stedu 				  struct ntfs_args *, struct proc *);
7005c5dae5Sjsing int	ntfs_vptofh(struct vnode *, struct fid *);
7126f3deacStedu 
7205c5dae5Sjsing int	ntfs_init(struct vfsconf *);
7305c5dae5Sjsing int	ntfs_fhtovp(struct mount *, struct fid *,
7426f3deacStedu    			     struct vnode **);
7505c5dae5Sjsing int	ntfs_checkexp(struct mount *, struct mbuf *,
7626f3deacStedu 			       int *, struct ucred **);
7705c5dae5Sjsing int	ntfs_sysctl(int *, u_int, void *, size_t *, void *,
7826f3deacStedu  			     size_t, struct proc *);
7926f3deacStedu 
8026f3deacStedu /*
8126f3deacStedu  * Verify a remote client has export rights and return these rights via.
8226f3deacStedu  * exflagsp and credanonp.
8326f3deacStedu  */
8405c5dae5Sjsing int
851cc0505dSjsing ntfs_checkexp(struct mount *mp, struct mbuf *nam, int *exflagsp,
861cc0505dSjsing     struct ucred **credanonp)
8726f3deacStedu {
8826f3deacStedu 	struct netcred *np;
8926f3deacStedu 	struct ntfsmount *ntm = VFSTONTFS(mp);
9026f3deacStedu 
9126f3deacStedu 	/*
9226f3deacStedu 	 * Get the export permission structure for this <mp, client> tuple.
9326f3deacStedu 	 */
9426f3deacStedu 	np = vfs_export_lookup(mp, &ntm->ntm_export, nam);
9526f3deacStedu 	if (np == NULL)
9626f3deacStedu 		return (EACCES);
9726f3deacStedu 
9826f3deacStedu 	*exflagsp = np->netc_exflags;
9926f3deacStedu 	*credanonp = &np->netc_anon;
10026f3deacStedu 	return (0);
10126f3deacStedu }
10226f3deacStedu 
10305c5dae5Sjsing int
1041cc0505dSjsing ntfs_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
1051cc0505dSjsing     size_t newlen, struct proc *p)
10626f3deacStedu {
10726f3deacStedu 	return (EINVAL);
10826f3deacStedu }
10926f3deacStedu 
11005c5dae5Sjsing int
1111cc0505dSjsing ntfs_init(struct vfsconf *vcp)
11226f3deacStedu {
11326f3deacStedu 	return 0;
11426f3deacStedu }
11526f3deacStedu 
11605c5dae5Sjsing int
1171cc0505dSjsing ntfs_mount(struct mount *mp, const char *path, void *data,
1181cc0505dSjsing     struct nameidata *ndp, struct proc *p)
11926f3deacStedu {
12026f3deacStedu 	int		err = 0;
12126f3deacStedu 	struct vnode	*devvp;
1227efda1a1Sderaadt 	struct ntfs_args *args = data;
123aec3986eSjsing 	char fname[MNAMELEN];
124a93bb724Sjsing 	char fspec[MNAMELEN];
12526f3deacStedu 
1262bbed251Stedu 	ntfs_nthashinit();
1272bbed251Stedu 
12826f3deacStedu 	/*
12926f3deacStedu 	 ***
13026f3deacStedu 	 * Mounting non-root file system or updating a file system
13126f3deacStedu 	 ***
13226f3deacStedu 	 */
13326f3deacStedu 
13426f3deacStedu 	/*
13526f3deacStedu 	 * If updating, check whether changing from read-only to
13626f3deacStedu 	 * read/write; if there is no device name, that's all we do.
13726f3deacStedu 	 */
13826f3deacStedu 	if (mp->mnt_flag & MNT_UPDATE) {
13926f3deacStedu 		/* if not updating name...*/
1407efda1a1Sderaadt 		if (args && args->fspec == NULL) {
14126f3deacStedu 			/*
14226f3deacStedu 			 * Process export requests.  Jumping to "success"
14326f3deacStedu 			 * will return the vfs_export() error code.
14426f3deacStedu 			 */
14526f3deacStedu 			struct ntfsmount *ntm = VFSTONTFS(mp);
1467efda1a1Sderaadt 			err = vfs_export(mp, &ntm->ntm_export, &args->export_info);
14726f3deacStedu 			goto success;
14826f3deacStedu 		}
14926f3deacStedu 
15026f3deacStedu 		printf("ntfs_mount(): MNT_UPDATE not supported\n");
15126f3deacStedu 		err = EINVAL;
15226f3deacStedu 		goto error_1;
15326f3deacStedu 	}
15426f3deacStedu 
15526f3deacStedu 	/*
15626f3deacStedu 	 * Not an update, or updating the name: look up the name
15726f3deacStedu 	 * and verify that it refers to a sensible block device.
15826f3deacStedu 	 */
1597efda1a1Sderaadt 	err = copyinstr(args->fspec, fspec, sizeof(fspec), NULL);
160ca666729Sjsing 	if (err)
161ca666729Sjsing 		goto error_1;
162ca666729Sjsing 
163aec3986eSjsing 	if (disk_map(fspec, fname, sizeof(fname), DM_OPENBLCK) == -1)
164aec3986eSjsing 		bcopy(fspec, fname, sizeof(fname));
165aec3986eSjsing 
166aec3986eSjsing 	NDINIT(ndp, LOOKUP, FOLLOW, UIO_SYSSPACE, fname, p);
16726f3deacStedu 	err = namei(ndp);
16826f3deacStedu 	if (err) {
16926f3deacStedu 		/* can't get devvp!*/
17026f3deacStedu 		goto error_1;
17126f3deacStedu 	}
17226f3deacStedu 
17326f3deacStedu 	devvp = ndp->ni_vp;
17426f3deacStedu 
17526f3deacStedu 	if (devvp->v_type != VBLK) {
17626f3deacStedu 		err = ENOTBLK;
17726f3deacStedu 		goto error_2;
17826f3deacStedu 	}
179ca1018d5Spedro 
18026f3deacStedu 	if (major(devvp->v_rdev) >= nblkdev) {
18126f3deacStedu 		err = ENXIO;
18226f3deacStedu 		goto error_2;
18326f3deacStedu 	}
184ca1018d5Spedro 
18526f3deacStedu 	if (mp->mnt_flag & MNT_UPDATE) {
18626f3deacStedu #if 0
18726f3deacStedu 		/*
18826f3deacStedu 		 ********************
18926f3deacStedu 		 * UPDATE
19026f3deacStedu 		 ********************
19126f3deacStedu 		 */
19226f3deacStedu 
19326f3deacStedu 		if (devvp != ntmp->um_devvp)
19426f3deacStedu 			err = EINVAL;	/* needs translation */
19526f3deacStedu 		else
19626f3deacStedu 			vrele(devvp);
19726f3deacStedu 		/*
19826f3deacStedu 		 * Update device name only on success
19926f3deacStedu 		 */
20026f3deacStedu 		if( !err) {
2017efda1a1Sderaadt 			err = set_statfs_info(NULL, UIO_USERSPACE, args->fspec,
20226f3deacStedu 			    UIO_USERSPACE, mp, p);
20326f3deacStedu 		}
20426f3deacStedu #endif
20526f3deacStedu 	} else {
20626f3deacStedu 		/*
20726f3deacStedu 		 ********************
20826f3deacStedu 		 * NEW MOUNT
20926f3deacStedu 		 ********************
21026f3deacStedu 		 */
21126f3deacStedu 
21226f3deacStedu 		/*
21326f3deacStedu 		 * Since this is a new mount, we want the names for
21426f3deacStedu 		 * the device and the mount point copied in.  If an
21526f3deacStedu 		 * error occurs,  the mountpoint is discarded by the
21626f3deacStedu 		 * upper level code.
21726f3deacStedu 		 */
21826f3deacStedu 		/* Save "last mounted on" info for mount point (NULL pad)*/
219a93bb724Sjsing 		bzero(mp->mnt_stat.f_mntonname, MNAMELEN);
220a93bb724Sjsing 		strlcpy(mp->mnt_stat.f_mntonname, path, MNAMELEN);
221a93bb724Sjsing 		bzero(mp->mnt_stat.f_mntfromname, MNAMELEN);
222aec3986eSjsing 		strlcpy(mp->mnt_stat.f_mntfromname, fname, MNAMELEN);
223aec3986eSjsing 		bzero(mp->mnt_stat.f_mntfromspec, MNAMELEN);
224aec3986eSjsing 		strlcpy(mp->mnt_stat.f_mntfromspec, fspec, MNAMELEN);
2257efda1a1Sderaadt 		bcopy(args, &mp->mnt_stat.mount_info.ntfs_args, sizeof(*args));
22626f3deacStedu 		if ( !err) {
2277efda1a1Sderaadt 			err = ntfs_mountfs(devvp, mp, args, p);
22826f3deacStedu 		}
22926f3deacStedu 	}
23026f3deacStedu 	if (err) {
23126f3deacStedu 		goto error_2;
23226f3deacStedu 	}
23326f3deacStedu 
23426f3deacStedu 	/*
23526f3deacStedu 	 * Initialize FS stat information in mount struct; uses both
23626f3deacStedu 	 * mp->mnt_stat.f_mntonname and mp->mnt_stat.f_mntfromname
23726f3deacStedu 	 *
23826f3deacStedu 	 * This code is common to root and non-root mounts
23926f3deacStedu 	 */
24026f3deacStedu 	(void)VFS_STATFS(mp, &mp->mnt_stat, p);
24126f3deacStedu 
24226f3deacStedu 	goto success;
24326f3deacStedu 
24426f3deacStedu 
24526f3deacStedu error_2:	/* error with devvp held*/
24626f3deacStedu 
24726f3deacStedu 	/* release devvp before failing*/
24826f3deacStedu 	vrele(devvp);
24926f3deacStedu 
25026f3deacStedu error_1:	/* no state to back out*/
25126f3deacStedu 
25226f3deacStedu success:
25326f3deacStedu 	return(err);
25426f3deacStedu }
25526f3deacStedu 
25626f3deacStedu /*
25726f3deacStedu  * Common code for mount and mountroot
25826f3deacStedu  */
25926f3deacStedu int
2601cc0505dSjsing ntfs_mountfs(struct vnode *devvp, struct mount *mp, struct ntfs_args *argsp,
2611cc0505dSjsing     struct proc *p)
26226f3deacStedu {
26326f3deacStedu 	struct buf *bp;
264bf3b3870Spat 	struct ntfsmount *ntmp = NULL;
26526f3deacStedu 	dev_t dev = devvp->v_rdev;
266288c69e0Snatano 	int error, ncount, i;
26726f3deacStedu 	struct vnode *vp;
26826f3deacStedu 
26926f3deacStedu 	/*
27026f3deacStedu 	 * Disallow multiple mounts of the same device.
27126f3deacStedu 	 * Disallow mounting of a device that is currently in use
27226f3deacStedu 	 * (except for root, which might share swap device for miniroot).
27326f3deacStedu 	 * Flush out any old buffers remaining from a previous use.
27426f3deacStedu 	 */
27526f3deacStedu 	error = vfs_mountedon(devvp);
27626f3deacStedu 	if (error)
27726f3deacStedu 		return (error);
27826f3deacStedu 	ncount = vcount(devvp);
27926f3deacStedu 	if (ncount > 1 && devvp != rootvp)
28026f3deacStedu 		return (EBUSY);
2816e880534Svisa 	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
282a8d7c3beScheloha 	error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, INFSLP);
28336bb23f1Svisa 	VOP_UNLOCK(devvp);
28426f3deacStedu 	if (error)
28526f3deacStedu 		return (error);
28626f3deacStedu 
287288c69e0Snatano 	error = VOP_OPEN(devvp, FREAD, FSCRED, p);
28826f3deacStedu 	if (error)
28926f3deacStedu 		return (error);
29026f3deacStedu 
29126f3deacStedu 	bp = NULL;
29226f3deacStedu 
29393f62a9eStedu 	error = bread(devvp, BBLOCK, BBSIZE, &bp);
29426f3deacStedu 	if (error)
29526f3deacStedu 		goto out;
296bc9397c2Skrw 	ntmp = malloc(sizeof *ntmp, M_NTFSMNT, M_WAITOK | M_ZERO);
29726f3deacStedu 	bcopy(bp->b_data, &ntmp->ntm_bootfile, sizeof(struct bootfile));
29826f3deacStedu 	brelse(bp);
29926f3deacStedu 	bp = NULL;
30026f3deacStedu 
30126f3deacStedu 	if (strncmp(ntmp->ntm_bootfile.bf_sysid, NTFS_BBID, NTFS_BBIDLEN)) {
30226f3deacStedu 		error = EINVAL;
303a1ea65c6Sjsing 		DPRINTF("ntfs_mountfs: invalid boot block\n");
30426f3deacStedu 		goto out;
30526f3deacStedu 	}
30626f3deacStedu 
30726f3deacStedu 	{
30826f3deacStedu 		int8_t cpr = ntmp->ntm_mftrecsz;
30926f3deacStedu 		if( cpr > 0 )
31026f3deacStedu 			ntmp->ntm_bpmftrec = ntmp->ntm_spc * cpr;
31126f3deacStedu 		else
31226f3deacStedu 			ntmp->ntm_bpmftrec = (1 << (-cpr)) / ntmp->ntm_bps;
31326f3deacStedu 	}
314f2997212Sjsing 	DPRINTF("ntfs_mountfs(): bps: %u, spc: %u, media: %x, "
315f2997212Sjsing 	    "mftrecsz: %u (%u sects)\n", ntmp->ntm_bps, ntmp->ntm_spc,
316a1ea65c6Sjsing 	    ntmp->ntm_bootfile.bf_media, ntmp->ntm_mftrecsz,
317a1ea65c6Sjsing 	    ntmp->ntm_bpmftrec);
318f2997212Sjsing 	DPRINTF("ntfs_mountfs(): mftcn: 0x%llx|0x%llx\n",
319f2997212Sjsing 	    ntmp->ntm_mftcn, ntmp->ntm_mftmirrcn);
32026f3deacStedu 
32126f3deacStedu 	ntmp->ntm_mountp = mp;
32226f3deacStedu 	ntmp->ntm_dev = dev;
32326f3deacStedu 	ntmp->ntm_devvp = devvp;
32426f3deacStedu 	ntmp->ntm_uid = argsp->uid;
32526f3deacStedu 	ntmp->ntm_gid = argsp->gid;
32626f3deacStedu 	ntmp->ntm_mode = argsp->mode;
32726f3deacStedu 	ntmp->ntm_flag = argsp->flag;
32841e0c475Sguenther 	mp->mnt_data = ntmp;
3298fc6378aSjsing 	TAILQ_INIT(&ntmp->ntm_ntnodeq);
33026f3deacStedu 
33126f3deacStedu 	/* set file name encode/decode hooks XXX utf-8 only for now */
33226f3deacStedu 	ntmp->ntm_wget = ntfs_utf8_wget;
33326f3deacStedu 	ntmp->ntm_wput = ntfs_utf8_wput;
33426f3deacStedu 	ntmp->ntm_wcmp = ntfs_utf8_wcmp;
33526f3deacStedu 
336a1ea65c6Sjsing 	DPRINTF("ntfs_mountfs(): case-%s,%s uid: %d, gid: %d, mode: %o\n",
33726f3deacStedu 	    (ntmp->ntm_flag & NTFS_MFLAG_CASEINS) ? "insens." : "sens.",
33826f3deacStedu 	    (ntmp->ntm_flag & NTFS_MFLAG_ALLNAMES) ? " allnames," : "",
339a1ea65c6Sjsing 	    ntmp->ntm_uid, ntmp->ntm_gid, ntmp->ntm_mode);
34026f3deacStedu 
34126f3deacStedu 	/*
34226f3deacStedu 	 * We read in some system nodes to do not allow
34326f3deacStedu 	 * reclaim them and to have every time access to them.
34426f3deacStedu 	 */
34526f3deacStedu 	{
34626f3deacStedu 		int pi[3] = { NTFS_MFTINO, NTFS_ROOTINO, NTFS_BITMAPINO };
34726f3deacStedu 		for (i=0; i<3; i++) {
34826f3deacStedu 			error = VFS_VGET(mp, pi[i], &(ntmp->ntm_sysvn[pi[i]]));
34926f3deacStedu 			if(error)
35026f3deacStedu 				goto out1;
35126f3deacStedu 			ntmp->ntm_sysvn[pi[i]]->v_flag |= VSYSTEM;
352627b2c48Sthib 			vref(ntmp->ntm_sysvn[pi[i]]);
35326f3deacStedu 			vput(ntmp->ntm_sysvn[pi[i]]);
35426f3deacStedu 		}
35526f3deacStedu 	}
35626f3deacStedu 
35726f3deacStedu 	/* read the Unicode lowercase --> uppercase translation table,
35826f3deacStedu 	 * if necessary */
359274476fcStedu 	if ((error = ntfs_toupper_use(mp, ntmp, p)))
36026f3deacStedu 		goto out1;
36126f3deacStedu 
36226f3deacStedu 	/*
36326f3deacStedu 	 * Scan $BitMap and count free clusters
36426f3deacStedu 	 */
36526f3deacStedu 	error = ntfs_calccfree(ntmp, &ntmp->ntm_cfree);
36626f3deacStedu 	if(error)
36726f3deacStedu 		goto out1;
36826f3deacStedu 
36926f3deacStedu 	/*
37026f3deacStedu 	 * Read and translate to internal format attribute
37126f3deacStedu 	 * definition file.
37226f3deacStedu 	 */
37326f3deacStedu 	{
37426f3deacStedu 		int num,j;
37526f3deacStedu 		struct attrdef ad;
37626f3deacStedu 
37726f3deacStedu 		/* Open $AttrDef */
37826f3deacStedu 		error = VFS_VGET(mp, NTFS_ATTRDEFINO, &vp );
37926f3deacStedu 		if(error)
38026f3deacStedu 			goto out1;
38126f3deacStedu 
38226f3deacStedu 		/* Count valid entries */
38326f3deacStedu 		for(num = 0; ; num++) {
38426f3deacStedu 			error = ntfs_readattr(ntmp, VTONT(vp),
385c6c302e5Stedu 			    NTFS_A_DATA, NULL, num * sizeof(ad), sizeof(ad),
38626f3deacStedu 			    &ad, NULL);
38726f3deacStedu 			if (error)
38826f3deacStedu 				goto out1;
38926f3deacStedu 			if (ad.ad_name[0] == 0)
39026f3deacStedu 				break;
39126f3deacStedu 		}
39226f3deacStedu 
39326f3deacStedu 		/* Alloc memory for attribute definitions */
394540e394aSdoug 		ntmp->ntm_ad = mallocarray(num, sizeof(struct ntvattrdef),
39526f3deacStedu 		    M_NTFSMNT, M_WAITOK);
39626f3deacStedu 
39726f3deacStedu 		ntmp->ntm_adnum = num;
39826f3deacStedu 
39926f3deacStedu 		/* Read them and translate */
40026f3deacStedu 		for(i = 0; i < num; i++){
40126f3deacStedu 			error = ntfs_readattr(ntmp, VTONT(vp),
402c6c302e5Stedu 			    NTFS_A_DATA, NULL, i * sizeof(ad), sizeof(ad),
40326f3deacStedu 			    &ad, NULL);
40426f3deacStedu 			if (error)
40526f3deacStedu 				goto out1;
40626f3deacStedu 			j = 0;
40726f3deacStedu 			do {
40826f3deacStedu 				ntmp->ntm_ad[i].ad_name[j] = ad.ad_name[j];
40926f3deacStedu 			} while(ad.ad_name[j++]);
41026f3deacStedu 			ntmp->ntm_ad[i].ad_namelen = j - 1;
41126f3deacStedu 			ntmp->ntm_ad[i].ad_type = ad.ad_type;
41226f3deacStedu 		}
41326f3deacStedu 
41426f3deacStedu 		vput(vp);
41526f3deacStedu 	}
41626f3deacStedu 
41726f3deacStedu 	mp->mnt_stat.f_fsid.val[0] = dev;
4187d8a2b95Stedu 	mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
419f28dec03Snatano 	mp->mnt_stat.f_namemax = NTFS_MAXFILENAME;
42026f3deacStedu 	mp->mnt_flag |= MNT_LOCAL;
42126f3deacStedu 	devvp->v_specmountpoint = mp;
42226f3deacStedu 	return (0);
42326f3deacStedu 
42426f3deacStedu out1:
42526f3deacStedu 	for (i = 0; i < NTFS_SYSNODESNUM; i++)
426bf3b3870Spat 		if (ntmp->ntm_sysvn[i])
427bf3b3870Spat 			vrele(ntmp->ntm_sysvn[i]);
42826f3deacStedu 
42926f3deacStedu 	if (vflush(mp,NULLVP,0))
430a1ea65c6Sjsing 		DPRINTF("ntfs_mountfs: vflush failed\n");
43126f3deacStedu 
43226f3deacStedu out:
4339ee302b8Sbluhm 	if (devvp->v_specinfo)
43426f3deacStedu 		devvp->v_specmountpoint = NULL;
43526f3deacStedu 	if (bp)
43626f3deacStedu 		brelse(bp);
43726f3deacStedu 
438bf3b3870Spat 	if (ntmp != NULL) {
439bf3b3870Spat 		if (ntmp->ntm_ad != NULL)
440825c4e6aStedu 			free(ntmp->ntm_ad, M_NTFSMNT, 0);
441825c4e6aStedu 		free(ntmp, M_NTFSMNT, 0);
442bf3b3870Spat 		mp->mnt_data = NULL;
443bf3b3870Spat 	}
444bf3b3870Spat 
44526f3deacStedu 	/* lock the device vnode before calling VOP_CLOSE() */
4466e880534Svisa 	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
447288c69e0Snatano 	(void)VOP_CLOSE(devvp, FREAD, NOCRED, p);
44836bb23f1Svisa 	VOP_UNLOCK(devvp);
44926f3deacStedu 
45026f3deacStedu 	return (error);
45126f3deacStedu }
45226f3deacStedu 
45305c5dae5Sjsing int
4541cc0505dSjsing ntfs_start(struct mount *mp, int flags, struct proc *p)
45526f3deacStedu {
45626f3deacStedu 	return (0);
45726f3deacStedu }
45826f3deacStedu 
45905c5dae5Sjsing int
4601cc0505dSjsing ntfs_unmount(struct mount *mp, int mntflags, struct proc *p)
46126f3deacStedu {
46226f3deacStedu 	struct ntfsmount *ntmp;
463288c69e0Snatano 	int error, flags, i;
46426f3deacStedu 
465a1ea65c6Sjsing 	DPRINTF("ntfs_unmount: unmounting...\n");
46626f3deacStedu 	ntmp = VFSTONTFS(mp);
46726f3deacStedu 
46826f3deacStedu 	flags = 0;
46926f3deacStedu 	if(mntflags & MNT_FORCE)
47026f3deacStedu 		flags |= FORCECLOSE;
47126f3deacStedu 
472a1ea65c6Sjsing 	DPRINTF("ntfs_unmount: vflushing...\n");
47326f3deacStedu 	error = vflush(mp,NULLVP,flags | SKIPSYSTEM);
47426f3deacStedu 	if (error) {
475a1ea65c6Sjsing 		DPRINTF("ntfs_unmount: vflush failed: %d\n", error);
47626f3deacStedu 		return (error);
47726f3deacStedu 	}
47826f3deacStedu 
47969a62ea9Smikeb 	/* Check if system vnodes are still referenced */
48069a62ea9Smikeb 	for(i=0;i<NTFS_SYSNODESNUM;i++) {
48169a62ea9Smikeb 		if(((mntflags & MNT_FORCE) == 0) && (ntmp->ntm_sysvn[i] &&
48269a62ea9Smikeb 		    ntmp->ntm_sysvn[i]->v_usecount > 1))
48369a62ea9Smikeb 			return (EBUSY);
48469a62ea9Smikeb 	}
48526f3deacStedu 
48626f3deacStedu 	/* Dereference all system vnodes */
48726f3deacStedu 	for(i=0;i<NTFS_SYSNODESNUM;i++)
48826f3deacStedu 		 if(ntmp->ntm_sysvn[i]) vrele(ntmp->ntm_sysvn[i]);
48926f3deacStedu 
49026f3deacStedu 	/* vflush system vnodes */
49126f3deacStedu 	error = vflush(mp,NULLVP,flags);
49226f3deacStedu 	if (error) {
49326f3deacStedu 		/* XXX should this be panic() ? */
49426f3deacStedu 		printf("ntfs_unmount: vflush failed(sysnodes): %d\n",error);
49526f3deacStedu 	}
49626f3deacStedu 
49726f3deacStedu 	/* Check if the type of device node isn't VBAD before
49826f3deacStedu 	 * touching v_specinfo.  If the device vnode is revoked, the
4990d297f47Sjsg 	 * field is NULL and touching it causes null pointer dereference.
50026f3deacStedu 	 */
50126f3deacStedu 	if (ntmp->ntm_devvp->v_type != VBAD)
50226f3deacStedu 		ntmp->ntm_devvp->v_specmountpoint = NULL;
50326f3deacStedu 
50426f3deacStedu 	/* lock the device vnode before calling VOP_CLOSE() */
5056e880534Svisa 	vn_lock(ntmp->ntm_devvp, LK_EXCLUSIVE | LK_RETRY);
506a8d7c3beScheloha 	vinvalbuf(ntmp->ntm_devvp, V_SAVE, NOCRED, p, 0, INFSLP);
507288c69e0Snatano 	(void)VOP_CLOSE(ntmp->ntm_devvp, FREAD, NOCRED, p);
5083542ec7aSkrw 	vput(ntmp->ntm_devvp);
50926f3deacStedu 
510274476fcStedu 	/* free the toupper table, if this has been last mounted ntfs volume */
511274476fcStedu 	ntfs_toupper_unuse(p);
512274476fcStedu 
513a1ea65c6Sjsing 	DPRINTF("ntfs_unmount: freeing memory...\n");
514825c4e6aStedu 	free(ntmp->ntm_ad, M_NTFSMNT, 0);
515825c4e6aStedu 	free(ntmp, M_NTFSMNT, 0);
516200e77f4Sbluhm 	mp->mnt_data = NULL;
517200e77f4Sbluhm 	mp->mnt_flag &= ~MNT_LOCAL;
5184b1ae25eSbluhm 	return (0);
51926f3deacStedu }
52026f3deacStedu 
52105c5dae5Sjsing int
5221cc0505dSjsing ntfs_root(struct mount *mp, struct vnode **vpp)
52326f3deacStedu {
52426f3deacStedu 	struct vnode *nvp;
52526f3deacStedu 	int error = 0;
52626f3deacStedu 
527a1ea65c6Sjsing 	DPRINTF("ntfs_root(): sysvn: %p\n",
528a1ea65c6Sjsing 	    VFSTONTFS(mp)->ntm_sysvn[NTFS_ROOTINO]);
52926f3deacStedu 	error = VFS_VGET(mp, (ino_t)NTFS_ROOTINO, &nvp);
53026f3deacStedu 	if(error) {
53126f3deacStedu 		printf("ntfs_root: VFS_VGET failed: %d\n",error);
53226f3deacStedu 		return (error);
53326f3deacStedu 	}
53426f3deacStedu 
53526f3deacStedu 	*vpp = nvp;
53626f3deacStedu 	return (0);
53726f3deacStedu }
53826f3deacStedu 
539835c1779Sbrad /*
540835c1779Sbrad  * Do operations associated with quotas, not supported
541835c1779Sbrad  */
54205c5dae5Sjsing int
5431cc0505dSjsing ntfs_quotactl(struct mount *mp, int cmds, uid_t uid, caddr_t arg,
54426f3deacStedu     struct proc *p)
54526f3deacStedu {
54626f3deacStedu 	return EOPNOTSUPP;
54726f3deacStedu }
54826f3deacStedu 
54926f3deacStedu int
5501cc0505dSjsing ntfs_calccfree(struct ntfsmount *ntmp, cn_t *cfreep)
55126f3deacStedu {
55226f3deacStedu 	struct vnode *vp;
55326f3deacStedu 	u_int8_t *tmp;
55426f3deacStedu 	int j, error;
555835c1779Sbrad 	cn_t cfree = 0;
5569414ecb5Sjca 	uint64_t bmsize, offset;
5579414ecb5Sjca 	size_t chunksize, i;
55826f3deacStedu 
55926f3deacStedu 	vp = ntmp->ntm_sysvn[NTFS_BITMAPINO];
56026f3deacStedu 
56126f3deacStedu 	bmsize = VTOF(vp)->f_size;
56226f3deacStedu 
5639414ecb5Sjca 	if (bmsize > 1024 * 1024)
5649414ecb5Sjca 		chunksize = 1024 * 1024;
5659414ecb5Sjca 	else
5669414ecb5Sjca 		chunksize = bmsize;
5679414ecb5Sjca 
5689414ecb5Sjca 	tmp = malloc(chunksize, M_TEMP, M_WAITOK);
5699414ecb5Sjca 
5709414ecb5Sjca 	for (offset = 0; offset < bmsize; offset += chunksize) {
5719414ecb5Sjca 		if (chunksize > bmsize - offset)
5729414ecb5Sjca 			chunksize = bmsize - offset;
57326f3deacStedu 
57426f3deacStedu 		error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL,
5759414ecb5Sjca 		    offset, chunksize, tmp, NULL);
57626f3deacStedu 		if (error)
57726f3deacStedu 			goto out;
57826f3deacStedu 
5799414ecb5Sjca 		for (i = 0; i < chunksize; i++)
58026f3deacStedu 			for (j = 0; j < 8; j++)
5819414ecb5Sjca 				if (~tmp[i] & (1 << j))
5829414ecb5Sjca 					cfree++;
5839414ecb5Sjca 	}
5849414ecb5Sjca 
58526f3deacStedu 	*cfreep = cfree;
58626f3deacStedu 
58726f3deacStedu     out:
588825c4e6aStedu 	free(tmp, M_TEMP, 0);
58926f3deacStedu 	return(error);
59026f3deacStedu }
59126f3deacStedu 
59205c5dae5Sjsing int
5931cc0505dSjsing ntfs_statfs(struct mount *mp, struct statfs *sbp, struct proc *p)
59426f3deacStedu {
59526f3deacStedu 	struct ntfsmount *ntmp = VFSTONTFS(mp);
59626f3deacStedu 	u_int64_t mftallocated;
59726f3deacStedu 
598a1ea65c6Sjsing 	DPRINTF("ntfs_statfs():\n");
59926f3deacStedu 
60026f3deacStedu 	mftallocated = VTOF(ntmp->ntm_sysvn[NTFS_MFTINO])->f_allocated;
60126f3deacStedu 
60226f3deacStedu 	sbp->f_bsize = ntmp->ntm_bps;
60326f3deacStedu 	sbp->f_iosize = ntmp->ntm_bps * ntmp->ntm_spc;
60426f3deacStedu 	sbp->f_blocks = ntmp->ntm_bootfile.bf_spv;
60526f3deacStedu 	sbp->f_bfree = sbp->f_bavail = ntfs_cntobn(ntmp->ntm_cfree);
606f28dec03Snatano 	sbp->f_ffree = sbp->f_favail = sbp->f_bfree / ntmp->ntm_bpmftrec;
60726f3deacStedu 	sbp->f_files = mftallocated / ntfs_bntob(ntmp->ntm_bpmftrec) +
60826f3deacStedu 		       sbp->f_ffree;
609f28dec03Snatano 	copy_statfs_info(sbp, mp);
6101ad3841aSjasper 
61126f3deacStedu 	return (0);
61226f3deacStedu }
61326f3deacStedu 
61405c5dae5Sjsing int
615976e9839Sderaadt ntfs_sync(struct mount *mp, int waitfor, int stall, struct ucred *cred, struct proc *p)
61626f3deacStedu {
617a1ea65c6Sjsing 	/*DPRINTF("ntfs_sync():\n");*/
61826f3deacStedu 	return (0);
61926f3deacStedu }
62026f3deacStedu 
62105c5dae5Sjsing int
6221cc0505dSjsing ntfs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
62326f3deacStedu {
62426f3deacStedu 	struct ntfid *ntfhp = (struct ntfid *)fhp;
62526f3deacStedu 	int error;
62626f3deacStedu 
627f2997212Sjsing 	DDPRINTF("ntfs_fhtovp(): %s: %u\n",
628a1ea65c6Sjsing 	    mp->mnt_stat.f_mntonname, ntfhp->ntfid_ino);
62926f3deacStedu 
63026f3deacStedu 	error = ntfs_vgetex(mp, ntfhp->ntfid_ino, ntfhp->ntfid_attr, NULL,
631db7aa982Smpi 			LK_EXCLUSIVE | LK_RETRY, 0, vpp); /* XXX */
63226f3deacStedu 	if (error != 0) {
63326f3deacStedu 		*vpp = NULLVP;
63426f3deacStedu 		return (error);
63526f3deacStedu 	}
63626f3deacStedu 
63726f3deacStedu 	/* XXX as unlink/rmdir/mkdir/creat are not currently possible
63826f3deacStedu 	 * with NTFS, we don't need to check anything else for now */
63926f3deacStedu 	return (0);
64026f3deacStedu }
64126f3deacStedu 
64205c5dae5Sjsing int
6431cc0505dSjsing ntfs_vptofh(struct vnode *vp, struct fid *fhp)
64426f3deacStedu {
64526f3deacStedu 	struct ntnode *ntp;
64626f3deacStedu 	struct ntfid *ntfhp;
64726f3deacStedu 	struct fnode *fn;
64826f3deacStedu 
649a1ea65c6Sjsing 	DDPRINTF("ntfs_fhtovp(): %s: %p\n",
650a1ea65c6Sjsing 	    vp->v_mount->mnt_stat.f_mntonname, vp);
65126f3deacStedu 
65226f3deacStedu 	fn = VTOF(vp);
65326f3deacStedu 	ntp = VTONT(vp);
65426f3deacStedu 	ntfhp = (struct ntfid *)fhp;
65526f3deacStedu 	ntfhp->ntfid_len = sizeof(struct ntfid);
65626f3deacStedu 	ntfhp->ntfid_ino = ntp->i_number;
65726f3deacStedu 	ntfhp->ntfid_attr = fn->f_attrtype;
65826f3deacStedu #ifdef notyet
65926f3deacStedu 	ntfhp->ntfid_gen = ntp->i_gen;
66026f3deacStedu #endif
66126f3deacStedu 	return (0);
66226f3deacStedu }
66326f3deacStedu 
66426f3deacStedu int
66595a73601Sguenther ntfs_vgetex(struct mount *mp, ntfsino_t ino, u_int32_t attrtype, char *attrname,
666db7aa982Smpi     u_long lkflags, u_long flags, struct vnode **vpp)
66726f3deacStedu {
66826f3deacStedu 	int error;
66926f3deacStedu 	struct ntfsmount *ntmp;
67026f3deacStedu 	struct ntnode *ip;
67126f3deacStedu 	struct fnode *fp;
67226f3deacStedu 	struct vnode *vp;
67326f3deacStedu 	enum vtype f_type;
67426f3deacStedu 
675f2997212Sjsing 	DPRINTF("ntfs_vgetex: ino: %u, attr: 0x%x:%s, lkf: 0x%lx, f: 0x%lx\n",
676f2997212Sjsing 	    ino, attrtype, attrname ? attrname : "", lkflags, flags);
67726f3deacStedu 
67826f3deacStedu 	ntmp = VFSTONTFS(mp);
67926f3deacStedu 	*vpp = NULL;
68026f3deacStedu 
68126f3deacStedu 	/* Get ntnode */
682db7aa982Smpi 	error = ntfs_ntlookup(ntmp, ino, &ip);
68326f3deacStedu 	if (error) {
68426f3deacStedu 		printf("ntfs_vget: ntfs_ntget failed\n");
68526f3deacStedu 		return (error);
68626f3deacStedu 	}
68726f3deacStedu 
68826f3deacStedu 	/* It may be not initialized fully, so force load it */
68926f3deacStedu 	if (!(flags & VG_DONTLOADIN) && !(ip->i_flag & IN_LOADED)) {
69026f3deacStedu 		error = ntfs_loadntnode(ntmp, ip);
69126f3deacStedu 		if(error) {
69226f3deacStedu 			printf("ntfs_vget: CAN'T LOAD ATTRIBUTES FOR INO: %d\n",
69326f3deacStedu 			       ip->i_number);
694db7aa982Smpi 			ntfs_ntput(ip);
6951ad3841aSjasper 
69626f3deacStedu 			return (error);
69726f3deacStedu 		}
69826f3deacStedu 	}
69926f3deacStedu 
70026f3deacStedu 	error = ntfs_fget(ntmp, ip, attrtype, attrname, &fp);
70126f3deacStedu 	if (error) {
70226f3deacStedu 		printf("ntfs_vget: ntfs_fget failed\n");
703db7aa982Smpi 		ntfs_ntput(ip);
7041ad3841aSjasper 
70526f3deacStedu 		return (error);
70626f3deacStedu 	}
70726f3deacStedu 
70826f3deacStedu 	if (!(flags & VG_DONTVALIDFN) && !(fp->f_flag & FN_VALID)) {
70926f3deacStedu 		if ((ip->i_frflag & NTFS_FRFLAG_DIR) &&
71026f3deacStedu 		    (fp->f_attrtype == NTFS_A_DATA && fp->f_attrname == NULL)) {
71126f3deacStedu 			f_type = VDIR;
71226f3deacStedu 		} else if (flags & VG_EXT) {
71326f3deacStedu 			f_type = VNON;
71426f3deacStedu 			fp->f_size = fp->f_allocated = 0;
71526f3deacStedu 		} else {
71626f3deacStedu 			f_type = VREG;
71726f3deacStedu 
71826f3deacStedu 			error = ntfs_filesize(ntmp, fp,
71926f3deacStedu 					      &fp->f_size, &fp->f_allocated);
72026f3deacStedu 			if (error) {
721db7aa982Smpi 				ntfs_ntput(ip);
7221ad3841aSjasper 
72326f3deacStedu 				return (error);
72426f3deacStedu 			}
72526f3deacStedu 		}
72626f3deacStedu 
72726f3deacStedu 		fp->f_flag |= FN_VALID;
72826f3deacStedu 	}
72926f3deacStedu 
73026f3deacStedu 	/*
73126f3deacStedu 	 * We may be calling vget() now. To avoid potential deadlock, we need
73226f3deacStedu 	 * to release ntnode lock, since due to locking order vnode
73326f3deacStedu 	 * lock has to be acquired first.
73426f3deacStedu 	 * ntfs_fget() bumped ntnode usecount, so ntnode won't be recycled
73526f3deacStedu 	 * prematurely.
73626f3deacStedu 	 */
737db7aa982Smpi 	ntfs_ntput(ip);
73826f3deacStedu 
73926f3deacStedu 	if (FTOV(fp)) {
74026f3deacStedu 		/* vget() returns error if the vnode has been recycled */
74108107a0bSvisa 		if (vget(FTOV(fp), lkflags) == 0) {
74226f3deacStedu 			*vpp = FTOV(fp);
74326f3deacStedu 			return (0);
74426f3deacStedu 		}
74526f3deacStedu 	}
74626f3deacStedu 
747dc81e71aSthib 	error = getnewvnode(VT_NTFS, ntmp->ntm_mountp, &ntfs_vops, &vp);
74826f3deacStedu 	if(error) {
74926f3deacStedu 		ntfs_frele(fp);
750db7aa982Smpi 		ntfs_ntput(ip);
7511ad3841aSjasper 
75226f3deacStedu 		return (error);
75326f3deacStedu 	}
754f2997212Sjsing 	DPRINTF("ntfs_vget: vnode: %p for ntnode: %u\n", vp, ino);
75526f3deacStedu 
75626f3deacStedu 	fp->f_vp = vp;
75726f3deacStedu 	vp->v_data = fp;
75826f3deacStedu 	vp->v_type = f_type;
75926f3deacStedu 
76026f3deacStedu 	if (ino == NTFS_ROOTINO)
76126f3deacStedu 		vp->v_flag |= VROOT;
76226f3deacStedu 
76326f3deacStedu 	if (lkflags & LK_TYPE_MASK) {
7646e880534Svisa 		error = vn_lock(vp, lkflags);
76526f3deacStedu 		if (error) {
76626f3deacStedu 			vput(vp);
76726f3deacStedu 			return (error);
76826f3deacStedu 		}
76926f3deacStedu 	}
77026f3deacStedu 
77126f3deacStedu 	*vpp = vp;
77226f3deacStedu 	return (0);
77326f3deacStedu }
77426f3deacStedu 
77505c5dae5Sjsing int
7761cc0505dSjsing ntfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
77726f3deacStedu {
77895a73601Sguenther 	if (ino > (ntfsino_t)-1)
77995a73601Sguenther 		panic("ntfs_vget: alien ino_t %llu", (unsigned long long)ino);
78026f3deacStedu 	return ntfs_vgetex(mp, ino, NTFS_A_DATA, NULL,
781db7aa982Smpi 			LK_EXCLUSIVE | LK_RETRY, 0, vpp); /* XXX */
78226f3deacStedu }
78326f3deacStedu 
784e4b1e213Smickey const struct vfsops ntfs_vfsops = {
78541f642fcSbluhm 	.vfs_mount	= ntfs_mount,
78641f642fcSbluhm 	.vfs_start	= ntfs_start,
78741f642fcSbluhm 	.vfs_unmount	= ntfs_unmount,
78841f642fcSbluhm 	.vfs_root	= ntfs_root,
78941f642fcSbluhm 	.vfs_quotactl	= ntfs_quotactl,
79041f642fcSbluhm 	.vfs_statfs	= ntfs_statfs,
79141f642fcSbluhm 	.vfs_sync	= ntfs_sync,
79241f642fcSbluhm 	.vfs_vget	= ntfs_vget,
79341f642fcSbluhm 	.vfs_fhtovp	= ntfs_fhtovp,
79441f642fcSbluhm 	.vfs_vptofh	= ntfs_vptofh,
79541f642fcSbluhm 	.vfs_init	= ntfs_init,
79641f642fcSbluhm 	.vfs_sysctl	= ntfs_sysctl,
79741f642fcSbluhm 	.vfs_checkexp	= ntfs_checkexp,
79826f3deacStedu };
799