xref: /netbsd-src/sys/fs/ntfs/ntfs_vnops.c (revision c6c16cd073ce83998f416e882233d1f576331079)
1*c6c16cd0Sdholland /*	$NetBSD: ntfs_vnops.c,v 1.66 2021/06/29 22:34:07 dholland Exp $	*/
29accf4dfSjdolecek 
39accf4dfSjdolecek /*
49accf4dfSjdolecek  * Copyright (c) 1992, 1993
59accf4dfSjdolecek  *	The Regents of the University of California.  All rights reserved.
69accf4dfSjdolecek  *
79accf4dfSjdolecek  * This code is derived from software contributed to Berkeley by
89accf4dfSjdolecek  * John Heidemann of the UCLA Ficus project.
99accf4dfSjdolecek  *
109accf4dfSjdolecek  * Redistribution and use in source and binary forms, with or without
119accf4dfSjdolecek  * modification, are permitted provided that the following conditions
129accf4dfSjdolecek  * are met:
139accf4dfSjdolecek  * 1. Redistributions of source code must retain the above copyright
149accf4dfSjdolecek  *    notice, this list of conditions and the following disclaimer.
159accf4dfSjdolecek  * 2. Redistributions in binary form must reproduce the above copyright
169accf4dfSjdolecek  *    notice, this list of conditions and the following disclaimer in the
179accf4dfSjdolecek  *    documentation and/or other materials provided with the distribution.
18aad01611Sagc  * 3. Neither the name of the University nor the names of its contributors
199accf4dfSjdolecek  *    may be used to endorse or promote products derived from this software
209accf4dfSjdolecek  *    without specific prior written permission.
219accf4dfSjdolecek  *
229accf4dfSjdolecek  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
239accf4dfSjdolecek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
249accf4dfSjdolecek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
259accf4dfSjdolecek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
269accf4dfSjdolecek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
279accf4dfSjdolecek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
289accf4dfSjdolecek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
299accf4dfSjdolecek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
309accf4dfSjdolecek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
319accf4dfSjdolecek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
329accf4dfSjdolecek  * SUCH DAMAGE.
339accf4dfSjdolecek  *
349accf4dfSjdolecek  *	Id: ntfs_vnops.c,v 1.5 1999/05/12 09:43:06 semenu Exp
359accf4dfSjdolecek  *
369accf4dfSjdolecek  */
379accf4dfSjdolecek 
389accf4dfSjdolecek #include <sys/cdefs.h>
39*c6c16cd0Sdholland __KERNEL_RCSID(0, "$NetBSD: ntfs_vnops.c,v 1.66 2021/06/29 22:34:07 dholland Exp $");
4079b00c49Smartin 
419accf4dfSjdolecek #include <sys/param.h>
429accf4dfSjdolecek #include <sys/systm.h>
439accf4dfSjdolecek #include <sys/kernel.h>
449accf4dfSjdolecek #include <sys/time.h>
459accf4dfSjdolecek #include <sys/stat.h>
469accf4dfSjdolecek #include <sys/vnode.h>
479accf4dfSjdolecek #include <sys/mount.h>
489accf4dfSjdolecek #include <sys/namei.h>
499accf4dfSjdolecek #include <sys/malloc.h>
509accf4dfSjdolecek #include <sys/buf.h>
519accf4dfSjdolecek #include <sys/dirent.h>
52fc9422c9Selad #include <sys/kauth.h>
539accf4dfSjdolecek #include <sys/sysctl.h>
549accf4dfSjdolecek 
559accf4dfSjdolecek 
569accf4dfSjdolecek #include <fs/ntfs/ntfs.h>
579accf4dfSjdolecek #include <fs/ntfs/ntfs_inode.h>
589accf4dfSjdolecek #include <fs/ntfs/ntfs_subr.h>
590bac6265Shannken #include <fs/ntfs/ntfs_vfsops.h>
609accf4dfSjdolecek #include <miscfs/specfs/specdev.h>
619accf4dfSjdolecek #include <miscfs/genfs/genfs.h>
629accf4dfSjdolecek 
639accf4dfSjdolecek #include <sys/unistd.h> /* for pathconf(2) constants */
649accf4dfSjdolecek 
654d595fd7Schristos static int	ntfs_bypass(void *);
664d595fd7Schristos static int	ntfs_read(void *);
674d595fd7Schristos static int	ntfs_write(void *);
684d595fd7Schristos static int	ntfs_getattr(void *);
694d595fd7Schristos static int	ntfs_inactive(void *);
704d595fd7Schristos static int	ntfs_print(void *);
714d595fd7Schristos static int	ntfs_reclaim(void *);
724d595fd7Schristos static int	ntfs_strategy(void *);
734d595fd7Schristos static int	ntfs_access(void *);
744d595fd7Schristos static int	ntfs_open(void *);
754d595fd7Schristos static int	ntfs_close(void *);
764d595fd7Schristos static int	ntfs_readdir(void *);
774d595fd7Schristos static int	ntfs_lookup(void *);
784d595fd7Schristos static int	ntfs_bmap(void *);
794d595fd7Schristos static int	ntfs_fsync(void *);
8008fcacf4Sxtraeme static int	ntfs_pathconf(void *);
819accf4dfSjdolecek 
829accf4dfSjdolecek /*
839accf4dfSjdolecek  * This is a noop, simply returning what one has been given.
849accf4dfSjdolecek  */
859accf4dfSjdolecek int
ntfs_bmap(void * v)864d595fd7Schristos ntfs_bmap(void *v)
874d595fd7Schristos {
889accf4dfSjdolecek 	struct vop_bmap_args /* {
899accf4dfSjdolecek 		struct vnode *a_vp;
909accf4dfSjdolecek 		daddr_t  a_bn;
919accf4dfSjdolecek 		struct vnode **a_vpp;
929accf4dfSjdolecek 		daddr_t *a_bnp;
939accf4dfSjdolecek 		int *a_runp;
949accf4dfSjdolecek 		int *a_runb;
954d595fd7Schristos 	} */ *ap = v;
969accf4dfSjdolecek 	dprintf(("ntfs_bmap: vn: %p, blk: %d\n", ap->a_vp,(u_int32_t)ap->a_bn));
979accf4dfSjdolecek 	if (ap->a_vpp != NULL)
989accf4dfSjdolecek 		*ap->a_vpp = ap->a_vp;
999accf4dfSjdolecek 	if (ap->a_bnp != NULL)
1009accf4dfSjdolecek 		*ap->a_bnp = ap->a_bn;
1019accf4dfSjdolecek 	if (ap->a_runp != NULL)
1029accf4dfSjdolecek 		*ap->a_runp = 0;
1039accf4dfSjdolecek 	return (0);
1049accf4dfSjdolecek }
1059accf4dfSjdolecek 
1069accf4dfSjdolecek static int
ntfs_read(void * v)1074d595fd7Schristos ntfs_read(void *v)
1084d595fd7Schristos {
1099accf4dfSjdolecek 	struct vop_read_args /* {
1109accf4dfSjdolecek 		struct vnode *a_vp;
1119accf4dfSjdolecek 		struct uio *a_uio;
1129accf4dfSjdolecek 		int a_ioflag;
113fc9422c9Selad 		kauth_cred_t a_cred;
1144d595fd7Schristos 	} */ *ap = v;
1159accf4dfSjdolecek 	struct vnode *vp = ap->a_vp;
1169accf4dfSjdolecek 	struct fnode *fp = VTOF(vp);
1179accf4dfSjdolecek 	struct ntnode *ip = FTONT(fp);
1189accf4dfSjdolecek 	struct uio *uio = ap->a_uio;
1199accf4dfSjdolecek 	struct ntfsmount *ntmp = ip->i_mp;
1209accf4dfSjdolecek 	u_int64_t toread;
1219accf4dfSjdolecek 	int error;
1229accf4dfSjdolecek 
123ec5a9318Syamt 	dprintf(("ntfs_read: ino: %llu, off: %qd resid: %qd\n",
124f229ea7fSchristos 	    (unsigned long long)ip->i_number, (long long)uio->uio_offset,
125ec5a9318Syamt 	    (long long)uio->uio_resid));
1269accf4dfSjdolecek 
127aa112c89Schristos 	dprintf(("ntfs_read: filesize: %qu",(long long)fp->f_size));
1289accf4dfSjdolecek 
1299accf4dfSjdolecek 	/* don't allow reading after end of file */
1309accf4dfSjdolecek 	if (uio->uio_offset > fp->f_size)
1319accf4dfSjdolecek 		toread = 0;
1329accf4dfSjdolecek 	else
13328302c22Sjdolecek 		toread = MIN(uio->uio_resid, fp->f_size - uio->uio_offset );
1349accf4dfSjdolecek 
135aa112c89Schristos 	dprintf((", toread: %qu\n",(long long)toread));
1369accf4dfSjdolecek 
1379accf4dfSjdolecek 	if (toread == 0)
1389accf4dfSjdolecek 		return (0);
1399accf4dfSjdolecek 
1409accf4dfSjdolecek 	error = ntfs_readattr(ntmp, ip, fp->f_attrtype,
1419accf4dfSjdolecek 		fp->f_attrname, uio->uio_offset, toread, NULL, uio);
1429accf4dfSjdolecek 	if (error) {
1439accf4dfSjdolecek 		printf("ntfs_read: ntfs_readattr failed: %d\n",error);
1449accf4dfSjdolecek 		return (error);
1459accf4dfSjdolecek 	}
1469accf4dfSjdolecek 
1479accf4dfSjdolecek 	return (0);
1489accf4dfSjdolecek }
1499accf4dfSjdolecek 
1509accf4dfSjdolecek static int
ntfs_bypass(void * v)1514d595fd7Schristos ntfs_bypass(void *v)
1524d595fd7Schristos {
1539accf4dfSjdolecek 	struct vop_generic_args /* {
1549accf4dfSjdolecek 		struct vnodeop_desc *a_desc;
1559accf4dfSjdolecek 		<other random data follows, presumably>
1564d595fd7Schristos 	} */ *ap __unused = v;
1579accf4dfSjdolecek 	int error = ENOTTY;
1589accf4dfSjdolecek 	dprintf(("ntfs_bypass: %s\n", ap->a_desc->vdesc_name));
1599accf4dfSjdolecek 	return (error);
1609accf4dfSjdolecek }
1619accf4dfSjdolecek 
1629accf4dfSjdolecek 
1639accf4dfSjdolecek static int
ntfs_getattr(void * v)1644d595fd7Schristos ntfs_getattr(void *v)
1654d595fd7Schristos {
1669accf4dfSjdolecek 	struct vop_getattr_args /* {
1679accf4dfSjdolecek 		struct vnode *a_vp;
1689accf4dfSjdolecek 		struct vattr *a_vap;
169fc9422c9Selad 		kauth_cred_t a_cred;
1704d595fd7Schristos 	} */ *ap = v;
1719accf4dfSjdolecek 	struct vnode *vp = ap->a_vp;
1729accf4dfSjdolecek 	struct fnode *fp = VTOF(vp);
1739accf4dfSjdolecek 	struct ntnode *ip = FTONT(fp);
1749accf4dfSjdolecek 	struct vattr *vap = ap->a_vap;
1759accf4dfSjdolecek 
176f229ea7fSchristos 	dprintf(("ntfs_getattr: %llu, flags: %d\n",
177f229ea7fSchristos 	    (unsigned long long)ip->i_number, ip->i_flag));
1789accf4dfSjdolecek 
1799accf4dfSjdolecek 	vap->va_fsid = ip->i_dev;
1809accf4dfSjdolecek 	vap->va_fileid = ip->i_number;
1819accf4dfSjdolecek 	vap->va_mode = ip->i_mp->ntm_mode;
1829accf4dfSjdolecek 	vap->va_nlink = ip->i_nlink;
1839accf4dfSjdolecek 	vap->va_uid = ip->i_mp->ntm_uid;
1849accf4dfSjdolecek 	vap->va_gid = ip->i_mp->ntm_gid;
1859accf4dfSjdolecek 	vap->va_rdev = 0;				/* XXX UNODEV ? */
1869accf4dfSjdolecek 	vap->va_size = fp->f_size;
1879accf4dfSjdolecek 	vap->va_bytes = fp->f_allocated;
1889accf4dfSjdolecek 	vap->va_atime = ntfs_nttimetounix(fp->f_times.t_access);
1899accf4dfSjdolecek 	vap->va_mtime = ntfs_nttimetounix(fp->f_times.t_write);
1909accf4dfSjdolecek 	vap->va_ctime = ntfs_nttimetounix(fp->f_times.t_create);
1919accf4dfSjdolecek 	vap->va_flags = ip->i_flag;
1929accf4dfSjdolecek 	vap->va_gen = 0;
1939accf4dfSjdolecek 	vap->va_blocksize = ip->i_mp->ntm_spc * ip->i_mp->ntm_bps;
1949accf4dfSjdolecek 	vap->va_type = vp->v_type;
1959accf4dfSjdolecek 	vap->va_filerev = 0;
1969accf4dfSjdolecek 	return (0);
1979accf4dfSjdolecek }
1989accf4dfSjdolecek 
1999accf4dfSjdolecek 
2009accf4dfSjdolecek /*
2019accf4dfSjdolecek  * Last reference to an ntnode.  If necessary, write or delete it.
2029accf4dfSjdolecek  */
2039accf4dfSjdolecek int
ntfs_inactive(void * v)2044d595fd7Schristos ntfs_inactive(void *v)
2054d595fd7Schristos {
20687fb3229Sriastradh 	struct vop_inactive_v2_args /* {
2079accf4dfSjdolecek 		struct vnode *a_vp;
20887fb3229Sriastradh 		bool *a_recycle;
2094d595fd7Schristos 	} */ *ap = v;
21087fb3229Sriastradh 	struct vnode *vp __unused = ap->a_vp;
2119accf4dfSjdolecek #ifdef NTFS_DEBUG
2129accf4dfSjdolecek 	struct ntnode *ip = VTONT(vp);
2139accf4dfSjdolecek #endif
2149accf4dfSjdolecek 
215f229ea7fSchristos 	dprintf(("ntfs_inactive: vnode: %p, ntnode: %llu\n", vp,
216f229ea7fSchristos 	    (unsigned long long)ip->i_number));
2179accf4dfSjdolecek 
2189accf4dfSjdolecek 	/* XXX since we don't support any filesystem changes
2199accf4dfSjdolecek 	 * right now, nothing more needs to be done
2209accf4dfSjdolecek 	 */
2219accf4dfSjdolecek 	return (0);
2229accf4dfSjdolecek }
2239accf4dfSjdolecek 
2249accf4dfSjdolecek /*
2259accf4dfSjdolecek  * Reclaim an fnode/ntnode so that it can be used for other purposes.
2269accf4dfSjdolecek  */
2279accf4dfSjdolecek int
ntfs_reclaim(void * v)2284d595fd7Schristos ntfs_reclaim(void *v)
2294d595fd7Schristos {
2307f7aad09Sriastradh 	struct vop_reclaim_v2_args /* {
2319accf4dfSjdolecek 		struct vnode *a_vp;
2324d595fd7Schristos 	} */ *ap = v;
2339accf4dfSjdolecek 	struct vnode *vp = ap->a_vp;
2349accf4dfSjdolecek 	struct fnode *fp = VTOF(vp);
2359accf4dfSjdolecek 	struct ntnode *ip = FTONT(fp);
2360bac6265Shannken 	const int attrlen = strlen(fp->f_attrname);
2379accf4dfSjdolecek 	int error;
2389accf4dfSjdolecek 
2397f7aad09Sriastradh 	VOP_UNLOCK(vp);
2407f7aad09Sriastradh 
241f229ea7fSchristos 	dprintf(("ntfs_reclaim: vnode: %p, ntnode: %llu\n", vp,
242f229ea7fSchristos 	    (unsigned long long)ip->i_number));
2439accf4dfSjdolecek 
2449accf4dfSjdolecek 	if ((error = ntfs_ntget(ip)) != 0)
2459accf4dfSjdolecek 		return (error);
2469accf4dfSjdolecek 
2479accf4dfSjdolecek 	if (ip->i_devvp) {
2489accf4dfSjdolecek 		vrele(ip->i_devvp);
2499accf4dfSjdolecek 		ip->i_devvp = NULL;
2509accf4dfSjdolecek 	}
251adbb9ec2Sad 	genfs_node_destroy(vp);
2529accf4dfSjdolecek 	vp->v_data = NULL;
2539accf4dfSjdolecek 
2540bac6265Shannken 	/* Destroy fnode. */
2550bac6265Shannken 	if (fp->f_key != &fp->f_smallkey)
2560bac6265Shannken 		kmem_free(fp->f_key, NTKEY_SIZE(attrlen));
2570bac6265Shannken 	if (fp->f_dirblbuf)
2580bac6265Shannken 		free(fp->f_dirblbuf, M_NTFSDIR);
2590bac6265Shannken 	kmem_free(fp, sizeof(*fp));
2600bac6265Shannken 	ntfs_ntrele(ip);
2610bac6265Shannken 
2620bac6265Shannken 	ntfs_ntput(ip);
2630bac6265Shannken 
2649accf4dfSjdolecek 	return (0);
2659accf4dfSjdolecek }
2669accf4dfSjdolecek 
2679accf4dfSjdolecek static int
ntfs_print(void * v)2684d595fd7Schristos ntfs_print(void *v)
2694d595fd7Schristos {
2709accf4dfSjdolecek 	struct vop_print_args /* {
2719accf4dfSjdolecek 		struct vnode *a_vp;
2724d595fd7Schristos 	} */ *ap = v;
27381d7a920Sjdolecek 	struct ntnode *ip = VTONT(ap->a_vp);
27481d7a920Sjdolecek 
275758a209dSchristos 	printf("tag VT_NTFS, ino %llu, flag %#x, usecount %d, nlink %ld\n",
276758a209dSchristos 	    (unsigned long long)ip->i_number, ip->i_flag, ip->i_usecount,
277758a209dSchristos 	    ip->i_nlink);
27881d7a920Sjdolecek 	printf("       ");
27981d7a920Sjdolecek 	printf("\n");
2809accf4dfSjdolecek 	return (0);
2819accf4dfSjdolecek }
2829accf4dfSjdolecek 
2839accf4dfSjdolecek /*
2849accf4dfSjdolecek  * Calculate the logical to physical mapping if not done already,
2859accf4dfSjdolecek  * then call the device strategy routine.
2869accf4dfSjdolecek  */
2879accf4dfSjdolecek int
ntfs_strategy(void * v)2884d595fd7Schristos ntfs_strategy(void *v)
2894d595fd7Schristos {
2909accf4dfSjdolecek 	struct vop_strategy_args /* {
291d6170777Shannken 		struct vnode *a_vp;
2929accf4dfSjdolecek 		struct buf *a_bp;
2934d595fd7Schristos 	} */ *ap = v;
2949accf4dfSjdolecek 	struct buf *bp = ap->a_bp;
295d6170777Shannken 	struct vnode *vp = ap->a_vp;
2969accf4dfSjdolecek 	struct fnode *fp = VTOF(vp);
2979accf4dfSjdolecek 	struct ntnode *ip = FTONT(fp);
2989accf4dfSjdolecek 	struct ntfsmount *ntmp = ip->i_mp;
2999accf4dfSjdolecek 	int error;
3009accf4dfSjdolecek 
3019accf4dfSjdolecek 	dprintf(("ntfs_strategy: blkno: %d, lblkno: %d\n",
3029accf4dfSjdolecek 		(u_int32_t)bp->b_blkno,
3039accf4dfSjdolecek 		(u_int32_t)bp->b_lblkno));
3049accf4dfSjdolecek 
30528302c22Sjdolecek 	dprintf(("strategy: bcount: %u flags: 0x%x\n",
3069accf4dfSjdolecek 		(u_int32_t)bp->b_bcount,bp->b_flags));
3079accf4dfSjdolecek 
3089accf4dfSjdolecek 	if (bp->b_flags & B_READ) {
3099accf4dfSjdolecek 		u_int32_t toread;
3109accf4dfSjdolecek 
3119accf4dfSjdolecek 		if (ntfs_cntob(bp->b_blkno) >= fp->f_size) {
3129accf4dfSjdolecek 			clrbuf(bp);
3139accf4dfSjdolecek 			error = 0;
3149accf4dfSjdolecek 		} else {
31528302c22Sjdolecek 			toread = MIN(bp->b_bcount,
3169accf4dfSjdolecek 				 fp->f_size - ntfs_cntob(bp->b_blkno));
3179accf4dfSjdolecek 			dprintf(("ntfs_strategy: toread: %d, fsize: %d\n",
3189accf4dfSjdolecek 				toread,(u_int32_t)fp->f_size));
3199accf4dfSjdolecek 
3209accf4dfSjdolecek 			error = ntfs_readattr(ntmp, ip, fp->f_attrtype,
3219accf4dfSjdolecek 				fp->f_attrname, ntfs_cntob(bp->b_blkno),
3229accf4dfSjdolecek 				toread, bp->b_data, NULL);
3239accf4dfSjdolecek 
3249accf4dfSjdolecek 			if (error) {
3259accf4dfSjdolecek 				printf("ntfs_strategy: ntfs_readattr failed\n");
3269accf4dfSjdolecek 				bp->b_error = error;
3279accf4dfSjdolecek 			}
3289accf4dfSjdolecek 
32953524e44Schristos 			memset((char *)bp->b_data + toread, 0,
33053524e44Schristos 			    bp->b_bcount - toread);
3319accf4dfSjdolecek 		}
3329accf4dfSjdolecek 	} else {
3339accf4dfSjdolecek 		size_t tmp;
3349accf4dfSjdolecek 		u_int32_t towrite;
3359accf4dfSjdolecek 
3369accf4dfSjdolecek 		if (ntfs_cntob(bp->b_blkno) + bp->b_bcount >= fp->f_size) {
3379accf4dfSjdolecek 			printf("ntfs_strategy: CAN'T EXTEND FILE\n");
3389accf4dfSjdolecek 			bp->b_error = error = EFBIG;
3399accf4dfSjdolecek 		} else {
34028302c22Sjdolecek 			towrite = MIN(bp->b_bcount,
3419accf4dfSjdolecek 				fp->f_size - ntfs_cntob(bp->b_blkno));
3429accf4dfSjdolecek 			dprintf(("ntfs_strategy: towrite: %d, fsize: %d\n",
3439accf4dfSjdolecek 				towrite,(u_int32_t)fp->f_size));
3449accf4dfSjdolecek 
3459accf4dfSjdolecek 			error = ntfs_writeattr_plain(ntmp, ip, fp->f_attrtype,
3469accf4dfSjdolecek 				fp->f_attrname, ntfs_cntob(bp->b_blkno),towrite,
3479accf4dfSjdolecek 				bp->b_data, &tmp, NULL);
3489accf4dfSjdolecek 
3499accf4dfSjdolecek 			if (error) {
3509accf4dfSjdolecek 				printf("ntfs_strategy: ntfs_writeattr fail\n");
3519accf4dfSjdolecek 				bp->b_error = error;
3529accf4dfSjdolecek 			}
3539accf4dfSjdolecek 		}
3549accf4dfSjdolecek 	}
3559accf4dfSjdolecek 	biodone(bp);
3569accf4dfSjdolecek 	return (error);
3579accf4dfSjdolecek }
3589accf4dfSjdolecek 
3599accf4dfSjdolecek static int
ntfs_write(void * v)3604d595fd7Schristos ntfs_write(void *v)
3614d595fd7Schristos {
3629accf4dfSjdolecek 	struct vop_write_args /* {
3639accf4dfSjdolecek 		struct vnode *a_vp;
3649accf4dfSjdolecek 		struct uio *a_uio;
3659accf4dfSjdolecek 		int  a_ioflag;
366fc9422c9Selad 		kauth_cred_t a_cred;
3674d595fd7Schristos 	} */ *ap = v;
3689accf4dfSjdolecek 	struct vnode *vp = ap->a_vp;
3699accf4dfSjdolecek 	struct fnode *fp = VTOF(vp);
3709accf4dfSjdolecek 	struct ntnode *ip = FTONT(fp);
3719accf4dfSjdolecek 	struct uio *uio = ap->a_uio;
3729accf4dfSjdolecek 	struct ntfsmount *ntmp = ip->i_mp;
3739accf4dfSjdolecek 	u_int64_t towrite;
3749accf4dfSjdolecek 	size_t written;
3759accf4dfSjdolecek 	int error;
3769accf4dfSjdolecek 
377ec5a9318Syamt 	dprintf(("ntfs_write: ino: %llu, off: %qd resid: %qd\n",
378f229ea7fSchristos 	    (unsigned long long)ip->i_number, (long long)uio->uio_offset,
379ec5a9318Syamt 	    (long long)uio->uio_resid));
380aa112c89Schristos 	dprintf(("ntfs_write: filesize: %qu",(long long)fp->f_size));
3819accf4dfSjdolecek 
3829accf4dfSjdolecek 	if (uio->uio_resid + uio->uio_offset > fp->f_size) {
3839accf4dfSjdolecek 		printf("ntfs_write: CAN'T WRITE BEYOND END OF FILE\n");
3849accf4dfSjdolecek 		return (EFBIG);
3859accf4dfSjdolecek 	}
3869accf4dfSjdolecek 
38728302c22Sjdolecek 	towrite = MIN(uio->uio_resid, fp->f_size - uio->uio_offset);
3889accf4dfSjdolecek 
389aa112c89Schristos 	dprintf((", towrite: %qu\n",(long long)towrite));
3909accf4dfSjdolecek 
3919accf4dfSjdolecek 	error = ntfs_writeattr_plain(ntmp, ip, fp->f_attrtype,
3929accf4dfSjdolecek 		fp->f_attrname, uio->uio_offset, towrite, NULL, &written, uio);
3939accf4dfSjdolecek #ifdef NTFS_DEBUG
3949accf4dfSjdolecek 	if (error)
3959accf4dfSjdolecek 		printf("ntfs_write: ntfs_writeattr failed: %d\n", error);
3969accf4dfSjdolecek #endif
3979accf4dfSjdolecek 
3989accf4dfSjdolecek 	return (error);
3999accf4dfSjdolecek }
4009accf4dfSjdolecek 
401009f5d2fSelad static int
ntfs_check_possible(struct vnode * vp,struct ntnode * ip,accmode_t accmode)4029aa2a9c3Schristos ntfs_check_possible(struct vnode *vp, struct ntnode *ip, accmode_t accmode)
4034d595fd7Schristos {
4049accf4dfSjdolecek 
4059accf4dfSjdolecek 	/*
4069accf4dfSjdolecek 	 * Disallow write attempts on read-only file systems;
4079accf4dfSjdolecek 	 * unless the file is a socket, fifo, or a block or
4089accf4dfSjdolecek 	 * character device resident on the file system.
4099accf4dfSjdolecek 	 */
4109aa2a9c3Schristos 	if (accmode & VWRITE) {
4119accf4dfSjdolecek 		switch ((int)vp->v_type) {
4129accf4dfSjdolecek 		case VDIR:
4139accf4dfSjdolecek 		case VLNK:
4149accf4dfSjdolecek 		case VREG:
4159accf4dfSjdolecek 			if (vp->v_mount->mnt_flag & MNT_RDONLY)
4169accf4dfSjdolecek 				return (EROFS);
4179accf4dfSjdolecek 			break;
4189accf4dfSjdolecek 		}
4199accf4dfSjdolecek 	}
4209accf4dfSjdolecek 
421009f5d2fSelad 	return 0;
422009f5d2fSelad }
423009f5d2fSelad 
424009f5d2fSelad static int
ntfs_check_permitted(struct vnode * vp,struct ntnode * ip,accmode_t accmode,kauth_cred_t cred)4259aa2a9c3Schristos ntfs_check_permitted(struct vnode *vp, struct ntnode *ip, accmode_t accmode,
426009f5d2fSelad     kauth_cred_t cred)
427009f5d2fSelad {
428009f5d2fSelad 	mode_t file_mode;
429009f5d2fSelad 
43069db27dcSelad 	file_mode = ip->i_mp->ntm_mode | (S_IXUSR|S_IXGRP|S_IXOTH);
4319accf4dfSjdolecek 
4329aa2a9c3Schristos 	return kauth_authorize_vnode(cred, KAUTH_ACCESS_ACTION(accmode,
4339aa2a9c3Schristos 	    vp->v_type, file_mode), vp, NULL, genfs_can_access(vp, cred,
4349aa2a9c3Schristos 	    ip->i_mp->ntm_uid, ip->i_mp->ntm_gid, file_mode, NULL, accmode));
435009f5d2fSelad }
436009f5d2fSelad 
437009f5d2fSelad int
ntfs_access(void * v)438009f5d2fSelad ntfs_access(void *v)
439009f5d2fSelad {
440009f5d2fSelad 	struct vop_access_args /* {
441009f5d2fSelad 		struct vnode *a_vp;
4429aa2a9c3Schristos 		accmode_t  a_accmode;
443009f5d2fSelad 		kauth_cred_t a_cred;
444009f5d2fSelad 	} */ *ap = v;
445009f5d2fSelad 	struct vnode *vp = ap->a_vp;
446009f5d2fSelad 	struct ntnode *ip = VTONT(vp);
447009f5d2fSelad 	int error;
448009f5d2fSelad 
449009f5d2fSelad 	dprintf(("ntfs_access: %llu\n", (unsigned long long)ip->i_number));
450009f5d2fSelad 
4519aa2a9c3Schristos 	error = ntfs_check_possible(vp, ip, ap->a_accmode);
452009f5d2fSelad 	if (error)
453009f5d2fSelad 		return error;
454009f5d2fSelad 
4559aa2a9c3Schristos 	error = ntfs_check_permitted(vp, ip, ap->a_accmode, ap->a_cred);
456009f5d2fSelad 
457009f5d2fSelad 	return error;
4589accf4dfSjdolecek }
4599accf4dfSjdolecek 
4609accf4dfSjdolecek /*
4619accf4dfSjdolecek  * Open called.
4629accf4dfSjdolecek  *
4639accf4dfSjdolecek  * Nothing to do.
4649accf4dfSjdolecek  */
4659accf4dfSjdolecek /* ARGSUSED */
4669accf4dfSjdolecek static int
ntfs_open(void * v)4674d595fd7Schristos ntfs_open(void *v)
4684d595fd7Schristos {
4699accf4dfSjdolecek 	struct vop_open_args /* {
4709accf4dfSjdolecek 		struct vnode *a_vp;
4719accf4dfSjdolecek 		int  a_mode;
472fc9422c9Selad 		kauth_cred_t a_cred;
4734d595fd7Schristos 	} */ *ap __unused = v;
474f229ea7fSchristos #ifdef NTFS_DEBUG
4759accf4dfSjdolecek 	struct vnode *vp = ap->a_vp;
4769accf4dfSjdolecek 	struct ntnode *ip = VTONT(vp);
4779accf4dfSjdolecek 
4786f8e2ffeShannken 	dprintf(("ntfs_open: %llu\n", (unsigned long long)ip->i_number));
4799accf4dfSjdolecek #endif
4809accf4dfSjdolecek 
4819accf4dfSjdolecek 	/*
4829accf4dfSjdolecek 	 * Files marked append-only must be opened for appending.
4839accf4dfSjdolecek 	 */
4849accf4dfSjdolecek 
4859accf4dfSjdolecek 	return (0);
4869accf4dfSjdolecek }
4879accf4dfSjdolecek 
4889accf4dfSjdolecek /*
4899accf4dfSjdolecek  * Close called.
4909accf4dfSjdolecek  *
4919accf4dfSjdolecek  * Update the times on the inode.
4929accf4dfSjdolecek  */
4939accf4dfSjdolecek /* ARGSUSED */
4949accf4dfSjdolecek static int
ntfs_close(void * v)4954d595fd7Schristos ntfs_close(void *v)
4964d595fd7Schristos {
4979accf4dfSjdolecek 	struct vop_close_args /* {
4989accf4dfSjdolecek 		struct vnode *a_vp;
4999accf4dfSjdolecek 		int  a_fflag;
500fc9422c9Selad 		kauth_cred_t a_cred;
5014d595fd7Schristos 	} */ *ap __unused = v;
502f229ea7fSchristos #ifdef NTFS_DEBUG
5039accf4dfSjdolecek 	struct vnode *vp = ap->a_vp;
5049accf4dfSjdolecek 	struct ntnode *ip = VTONT(vp);
5059accf4dfSjdolecek 
5066f8e2ffeShannken 	dprintf(("ntfs_close: %llu\n", (unsigned long long)ip->i_number));
5079accf4dfSjdolecek #endif
5089accf4dfSjdolecek 
5099accf4dfSjdolecek 	return (0);
5109accf4dfSjdolecek }
5119accf4dfSjdolecek 
5129accf4dfSjdolecek int
ntfs_readdir(void * v)5134d595fd7Schristos ntfs_readdir(void *v)
5144d595fd7Schristos {
5159accf4dfSjdolecek 	struct vop_readdir_args /* {
5169accf4dfSjdolecek 		struct vnode *a_vp;
5179accf4dfSjdolecek 		struct uio *a_uio;
518fc9422c9Selad 		kauth_cred_t a_cred;
5199accf4dfSjdolecek 		int *a_ncookies;
5209accf4dfSjdolecek 		u_int **cookies;
5214d595fd7Schristos 	} */ *ap = v;
5229accf4dfSjdolecek 	struct vnode *vp = ap->a_vp;
5239accf4dfSjdolecek 	struct fnode *fp = VTOF(vp);
5249accf4dfSjdolecek 	struct ntnode *ip = FTONT(fp);
5259accf4dfSjdolecek 	struct uio *uio = ap->a_uio;
5269accf4dfSjdolecek 	struct ntfsmount *ntmp = ip->i_mp;
5279accf4dfSjdolecek 	int i, error = 0;
5289accf4dfSjdolecek 	u_int32_t faked = 0, num;
5299accf4dfSjdolecek 	int ncookies = 0;
5309accf4dfSjdolecek 	struct dirent *cde;
5319accf4dfSjdolecek 	off_t off;
5329accf4dfSjdolecek 
533f229ea7fSchristos 	dprintf(("ntfs_readdir %llu off: %qd resid: %qd\n",
534f229ea7fSchristos 	    (unsigned long long)ip->i_number, (long long)uio->uio_offset,
535f229ea7fSchristos 	    (long long)uio->uio_resid));
5369accf4dfSjdolecek 
5379accf4dfSjdolecek 	off = uio->uio_offset;
5389accf4dfSjdolecek 
5399b87d582Scegger 	cde = malloc(sizeof(struct dirent), M_TEMP, M_WAITOK);
5409accf4dfSjdolecek 
5419accf4dfSjdolecek 	/* Simulate . in every dir except ROOT */
5429accf4dfSjdolecek 	if (ip->i_number != NTFS_ROOTINO
5439accf4dfSjdolecek 	    && uio->uio_offset < sizeof(struct dirent)) {
5449accf4dfSjdolecek 		cde->d_fileno = ip->i_number;
5459accf4dfSjdolecek 		cde->d_reclen = sizeof(struct dirent);
5469accf4dfSjdolecek 		cde->d_type = DT_DIR;
5479accf4dfSjdolecek 		cde->d_namlen = 1;
5489accf4dfSjdolecek 		strncpy(cde->d_name, ".", 2);
5499accf4dfSjdolecek 		error = uiomove((void *)cde, sizeof(struct dirent), uio);
5509accf4dfSjdolecek 		if (error)
5519accf4dfSjdolecek 			goto out;
5529accf4dfSjdolecek 
5539accf4dfSjdolecek 		ncookies++;
5549accf4dfSjdolecek 	}
5559accf4dfSjdolecek 
5569accf4dfSjdolecek 	/* Simulate .. in every dir including ROOT */
5579accf4dfSjdolecek 	if (uio->uio_offset < 2 * sizeof(struct dirent)) {
5589accf4dfSjdolecek 		cde->d_fileno = NTFS_ROOTINO;	/* XXX */
5599accf4dfSjdolecek 		cde->d_reclen = sizeof(struct dirent);
5609accf4dfSjdolecek 		cde->d_type = DT_DIR;
5619accf4dfSjdolecek 		cde->d_namlen = 2;
5629accf4dfSjdolecek 		strncpy(cde->d_name, "..", 3);
5639accf4dfSjdolecek 
5649accf4dfSjdolecek 		error = uiomove((void *) cde, sizeof(struct dirent), uio);
5659accf4dfSjdolecek 		if (error)
5669accf4dfSjdolecek 			goto out;
5679accf4dfSjdolecek 
5689accf4dfSjdolecek 		ncookies++;
5699accf4dfSjdolecek 	}
5709accf4dfSjdolecek 
5719accf4dfSjdolecek 	faked = (ip->i_number == NTFS_ROOTINO) ? 1 : 2;
5729accf4dfSjdolecek 	num = uio->uio_offset / sizeof(struct dirent) - faked;
5739accf4dfSjdolecek 
5749accf4dfSjdolecek 	while (uio->uio_resid >= sizeof(struct dirent)) {
5759accf4dfSjdolecek 		struct attr_indexentry *iep;
5769accf4dfSjdolecek 		char *fname;
5779accf4dfSjdolecek 		size_t remains;
5789accf4dfSjdolecek 		int sz;
5799accf4dfSjdolecek 
5809accf4dfSjdolecek 		error = ntfs_ntreaddir(ntmp, fp, num, &iep);
5819accf4dfSjdolecek 		if (error)
5829accf4dfSjdolecek 			goto out;
5839accf4dfSjdolecek 
5849accf4dfSjdolecek 		if (NULL == iep)
5859accf4dfSjdolecek 			break;
5869accf4dfSjdolecek 
5879accf4dfSjdolecek 		for(; !(iep->ie_flag & NTFS_IEFLAG_LAST) && (uio->uio_resid >= sizeof(struct dirent));
5889accf4dfSjdolecek 			iep = NTFS_NEXTREC(iep, struct attr_indexentry *))
5899accf4dfSjdolecek 		{
5909accf4dfSjdolecek 			if(!ntfs_isnamepermitted(ntmp,iep))
5919accf4dfSjdolecek 				continue;
5929accf4dfSjdolecek 
5939accf4dfSjdolecek 			remains = sizeof(cde->d_name) - 1;
5949accf4dfSjdolecek 			fname = cde->d_name;
5959accf4dfSjdolecek 			for(i=0; i<iep->ie_fnamelen; i++) {
5969accf4dfSjdolecek 				sz = (*ntmp->ntm_wput)(fname, remains,
5979accf4dfSjdolecek 						iep->ie_fname[i]);
5989accf4dfSjdolecek 				fname += sz;
5999accf4dfSjdolecek 				remains -= sz;
6009accf4dfSjdolecek 			}
6019accf4dfSjdolecek 			*fname = '\0';
6029accf4dfSjdolecek 			dprintf(("ntfs_readdir: elem: %d, fname:[%s] type: %d, flag: %d, ",
6039accf4dfSjdolecek 				num, cde->d_name, iep->ie_fnametype,
6049accf4dfSjdolecek 				iep->ie_flag));
6059accf4dfSjdolecek 			cde->d_namlen = fname - (char *) cde->d_name;
6069accf4dfSjdolecek 			cde->d_fileno = iep->ie_number;
6079accf4dfSjdolecek 			cde->d_type = (iep->ie_fflag & NTFS_FFLAG_DIR) ? DT_DIR : DT_REG;
6089accf4dfSjdolecek 			cde->d_reclen = sizeof(struct dirent);
6099accf4dfSjdolecek 			dprintf(("%s\n", (cde->d_type == DT_DIR) ? "dir":"reg"));
6109accf4dfSjdolecek 
6119accf4dfSjdolecek 			error = uiomove((void *)cde, sizeof(struct dirent), uio);
6129accf4dfSjdolecek 			if (error)
6139accf4dfSjdolecek 				goto out;
6149accf4dfSjdolecek 
6159accf4dfSjdolecek 			ncookies++;
6169accf4dfSjdolecek 			num++;
6179accf4dfSjdolecek 		}
6189accf4dfSjdolecek 	}
6199accf4dfSjdolecek 
6209accf4dfSjdolecek 	dprintf(("ntfs_readdir: %d entries (%d bytes) read\n",
6219accf4dfSjdolecek 		ncookies,(u_int)(uio->uio_offset - off)));
622aa112c89Schristos 	dprintf(("ntfs_readdir: off: %qd resid: %qu\n",
623aa112c89Schristos 		(long long)uio->uio_offset,(long long)uio->uio_resid));
6249accf4dfSjdolecek 
6259accf4dfSjdolecek 	if (!error && ap->a_ncookies != NULL) {
6269accf4dfSjdolecek 		struct dirent* dpStart;
6279accf4dfSjdolecek 		struct dirent* dp;
6289accf4dfSjdolecek 		off_t *cookies;
6299accf4dfSjdolecek 		off_t *cookiep;
6309accf4dfSjdolecek 
63187f9bd72Sjdolecek 		dprintf(("ntfs_readdir: %d cookies\n",ncookies));
6329accf4dfSjdolecek 		dpStart = (struct dirent *)
63353524e44Schristos 		     ((char *)uio->uio_iov->iov_base -
6349accf4dfSjdolecek 			 (uio->uio_offset - off));
6359accf4dfSjdolecek 		cookies = malloc(ncookies * sizeof(off_t), M_TEMP, M_WAITOK);
6369accf4dfSjdolecek 		for (dp = dpStart, cookiep = cookies, i=0;
6379accf4dfSjdolecek 		     i < ncookies;
63853524e44Schristos 		     dp = (struct dirent *)((char *) dp + dp->d_reclen), i++) {
6399accf4dfSjdolecek 			off += dp->d_reclen;
6409accf4dfSjdolecek 			*cookiep++ = (u_int) off;
6419accf4dfSjdolecek 		}
6429accf4dfSjdolecek 		*ap->a_ncookies = ncookies;
6439accf4dfSjdolecek 		*ap->a_cookies = cookies;
6449accf4dfSjdolecek 	}
6459accf4dfSjdolecek /*
6469accf4dfSjdolecek 	if (ap->a_eofflag)
6479accf4dfSjdolecek 	    *ap->a_eofflag = VTONT(ap->a_vp)->i_size <= uio->uio_offset;
6489accf4dfSjdolecek */
6499accf4dfSjdolecek     out:
6509b87d582Scegger 	free(cde, M_TEMP);
6519accf4dfSjdolecek 	return (error);
6529accf4dfSjdolecek }
6539accf4dfSjdolecek 
6549accf4dfSjdolecek int
ntfs_lookup(void * v)6554d595fd7Schristos ntfs_lookup(void *v)
6564d595fd7Schristos {
65797834f7bShannken 	struct vop_lookup_v2_args /* {
6589accf4dfSjdolecek 		struct vnode *a_dvp;
6599accf4dfSjdolecek 		struct vnode **a_vpp;
6609accf4dfSjdolecek 		struct componentname *a_cnp;
6614d595fd7Schristos 	} */ *ap = v;
6629accf4dfSjdolecek 	struct vnode *dvp = ap->a_dvp;
6639accf4dfSjdolecek 	struct ntnode *dip = VTONT(dvp);
6649accf4dfSjdolecek 	struct ntfsmount *ntmp = dip->i_mp;
6659accf4dfSjdolecek 	struct componentname *cnp = ap->a_cnp;
666fc9422c9Selad 	kauth_cred_t cred = cnp->cn_cred;
6679accf4dfSjdolecek 	int error;
668c398ae97Schs 
6691498ad22Sad 	dprintf(("ntfs_lookup: \"%.*s\" (%lld bytes) in %llu\n",
6701498ad22Sad 	    (int)cnp->cn_namelen, cnp->cn_nameptr, (long long)cnp->cn_namelen,
671c398ae97Schs 	    (unsigned long long)dip->i_number));
6729accf4dfSjdolecek 
67361e8303eSpooka 	error = VOP_ACCESS(dvp, VEXEC, cred);
6749accf4dfSjdolecek 	if(error)
6759accf4dfSjdolecek 		return (error);
6769accf4dfSjdolecek 
6779accf4dfSjdolecek 	if ((cnp->cn_flags & ISLASTCN) &&
6789accf4dfSjdolecek 	    (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
6799accf4dfSjdolecek 	    (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
6809accf4dfSjdolecek 		return (EROFS);
6819accf4dfSjdolecek 
6829accf4dfSjdolecek 	/*
6839accf4dfSjdolecek 	 * We now have a segment name to search for, and a directory
6849accf4dfSjdolecek 	 * to search.
6859accf4dfSjdolecek 	 *
6869accf4dfSjdolecek 	 * Before tediously performing a linear scan of the directory,
6879accf4dfSjdolecek 	 * check the name cache to see if the directory/name pair
6889accf4dfSjdolecek 	 * we are looking for is known already.
6899accf4dfSjdolecek 	 */
69035ed6905Sdholland 	if (cache_lookup(ap->a_dvp, cnp->cn_nameptr, cnp->cn_namelen,
69135ed6905Sdholland 			 cnp->cn_nameiop, cnp->cn_flags, NULL, ap->a_vpp)) {
6921617a81dSdholland 		return *ap->a_vpp == NULLVP ? ENOENT : 0;
6931617a81dSdholland 	}
6949accf4dfSjdolecek 
6959accf4dfSjdolecek 	if(cnp->cn_namelen == 1 && cnp->cn_nameptr[0] == '.') {
696f229ea7fSchristos 		dprintf(("ntfs_lookup: faking . directory in %llu\n",
697f229ea7fSchristos 		    (unsigned long long)dip->i_number));
6989accf4dfSjdolecek 
699c3183f32Spooka 		vref(dvp);
7009accf4dfSjdolecek 		*ap->a_vpp = dvp;
7019accf4dfSjdolecek 		error = 0;
7029accf4dfSjdolecek 	} else if (cnp->cn_flags & ISDOTDOT) {
7039accf4dfSjdolecek 		struct ntvattr *vap;
7049accf4dfSjdolecek 
705f229ea7fSchristos 		dprintf(("ntfs_lookup: faking .. directory in %llu\n",
706f229ea7fSchristos 		    (unsigned long long)dip->i_number));
7079accf4dfSjdolecek 
7089accf4dfSjdolecek 		error = ntfs_ntvattrget(ntmp, dip, NTFS_A_NAME, NULL, 0, &vap);
709c398ae97Schs 		if (error) {
7109accf4dfSjdolecek 			return (error);
711c398ae97Schs 		}
7129accf4dfSjdolecek 
7139accf4dfSjdolecek 		dprintf(("ntfs_lookup: parentdir: %d\n",
7149accf4dfSjdolecek 			 vap->va_a_name->n_pnumber));
7150bac6265Shannken 		error = ntfs_vgetex(ntmp->ntm_mountp,
7160bac6265Shannken 				 vap->va_a_name->n_pnumber,
7170bac6265Shannken 				 NTFS_A_DATA, "", 0, ap->a_vpp);
7189accf4dfSjdolecek 		ntfs_ntvattrrele(vap);
7199accf4dfSjdolecek 		if (error) {
7209accf4dfSjdolecek 			return (error);
7219accf4dfSjdolecek 		}
7229accf4dfSjdolecek 	} else {
7239accf4dfSjdolecek 		error = ntfs_ntlookupfile(ntmp, dvp, cnp, ap->a_vpp);
7249accf4dfSjdolecek 		if (error) {
7259accf4dfSjdolecek 			dprintf(("ntfs_ntlookupfile: returned %d\n", error));
7269accf4dfSjdolecek 			return (error);
7279accf4dfSjdolecek 		}
7289accf4dfSjdolecek 
729f229ea7fSchristos 		dprintf(("ntfs_lookup: found ino: %llu\n",
730f229ea7fSchristos 		    (unsigned long long)VTONT(*ap->a_vpp)->i_number));
7319accf4dfSjdolecek 	}
7329accf4dfSjdolecek 
73335ed6905Sdholland 	cache_enter(dvp, *ap->a_vpp, cnp->cn_nameptr, cnp->cn_namelen,
73435ed6905Sdholland 		    cnp->cn_flags);
7359accf4dfSjdolecek 
736d65753d9Srmind 	return error;
7379accf4dfSjdolecek }
7389accf4dfSjdolecek 
7399accf4dfSjdolecek /*
7409accf4dfSjdolecek  * Flush the blocks of a file to disk.
7419accf4dfSjdolecek  *
7429accf4dfSjdolecek  * This function is worthless for vnodes that represent directories. Maybe we
7439accf4dfSjdolecek  * could just do a sync if they try an fsync on a directory file.
7449accf4dfSjdolecek  */
7459accf4dfSjdolecek static int
ntfs_fsync(void * v)7464d595fd7Schristos ntfs_fsync(void *v)
7474d595fd7Schristos {
7489accf4dfSjdolecek 	struct vop_fsync_args /* {
7499accf4dfSjdolecek 		struct vnode *a_vp;
750fc9422c9Selad 		kauth_cred_t a_cred;
751a748ea88Syamt 		int a_flags;
7529accf4dfSjdolecek 		off_t offlo;
7539accf4dfSjdolecek 		off_t offhi;
7544d595fd7Schristos 	} */ *ap = v;
755a748ea88Syamt 	struct vnode *vp = ap->a_vp;
756a748ea88Syamt 
757a748ea88Syamt 	if (ap->a_flags & FSYNC_CACHE) {
758a748ea88Syamt 		return EOPNOTSUPP;
7599accf4dfSjdolecek 	}
760a748ea88Syamt 
7618306a9edSchs 	return vflushbuf(vp, ap->a_flags);
762a748ea88Syamt }
7639accf4dfSjdolecek 
7649accf4dfSjdolecek /*
7659accf4dfSjdolecek  * Return POSIX pathconf information applicable to NTFS filesystem
7669accf4dfSjdolecek  */
7676810b562Sjdolecek static int
ntfs_pathconf(void * v)7684d595fd7Schristos ntfs_pathconf(void *v)
7699accf4dfSjdolecek {
7709accf4dfSjdolecek 	struct vop_pathconf_args /* {
7719accf4dfSjdolecek 		struct vnode *a_vp;
7729accf4dfSjdolecek 		int a_name;
7739accf4dfSjdolecek 		register_t *a_retval;
7749accf4dfSjdolecek 	} */ *ap = v;
7759accf4dfSjdolecek 
7769accf4dfSjdolecek 	switch (ap->a_name) {
7779accf4dfSjdolecek 	case _PC_LINK_MAX:
7789accf4dfSjdolecek 		*ap->a_retval = 1;
7799accf4dfSjdolecek 		return (0);
7809accf4dfSjdolecek 	case _PC_NAME_MAX:
781caffd8efSjdolecek 		*ap->a_retval = ap->a_vp->v_mount->mnt_stat.f_namemax;
7829accf4dfSjdolecek 		return (0);
7839accf4dfSjdolecek 	case _PC_PATH_MAX:
7849accf4dfSjdolecek 		*ap->a_retval = PATH_MAX;
7859accf4dfSjdolecek 		return (0);
7869accf4dfSjdolecek 	case _PC_CHOWN_RESTRICTED:
7879accf4dfSjdolecek 		*ap->a_retval = 1;
7889accf4dfSjdolecek 		return (0);
7899accf4dfSjdolecek 	case _PC_NO_TRUNC:
7909accf4dfSjdolecek 		*ap->a_retval = 0;
7919accf4dfSjdolecek 		return (0);
7929accf4dfSjdolecek 	case _PC_SYNC_IO:
7939accf4dfSjdolecek 		*ap->a_retval = 1;
7949accf4dfSjdolecek 		return (0);
7959accf4dfSjdolecek 	case _PC_FILESIZEBITS:
7969accf4dfSjdolecek 		*ap->a_retval = 64;
7979accf4dfSjdolecek 		return (0);
7989accf4dfSjdolecek 	default:
79979e3c74fSchristos 		return genfs_pathconf(ap);
8009accf4dfSjdolecek 	}
8019accf4dfSjdolecek 	/* NOTREACHED */
8029accf4dfSjdolecek }
8039accf4dfSjdolecek 
8049accf4dfSjdolecek /*
8059accf4dfSjdolecek  * Global vfs data structures
8069accf4dfSjdolecek  */
8079accf4dfSjdolecek vop_t **ntfs_vnodeop_p;
8089accf4dfSjdolecek 
8099accf4dfSjdolecek const struct vnodeopv_entry_desc ntfs_vnodeop_entries[] = {
8109accf4dfSjdolecek 	{ &vop_default_desc, (vop_t *) ntfs_bypass },
811*c6c16cd0Sdholland 	{ &vop_parsepath_desc, genfs_parsepath },	/* parsepath */
8129accf4dfSjdolecek 	{ &vop_lookup_desc, (vop_t *) ntfs_lookup },	/* lookup */
8139accf4dfSjdolecek 	{ &vop_create_desc, genfs_eopnotsupp },		/* create */
8149accf4dfSjdolecek 	{ &vop_mknod_desc, genfs_eopnotsupp },		/* mknod */
8159accf4dfSjdolecek 	{ &vop_open_desc, (vop_t *) ntfs_open },	/* open */
8169accf4dfSjdolecek 	{ &vop_close_desc,(vop_t *)  ntfs_close },	/* close */
8179accf4dfSjdolecek 	{ &vop_access_desc, (vop_t *) ntfs_access },	/* access */
8189aa2a9c3Schristos 	{ &vop_accessx_desc, (vop_t *) genfs_accessx },	/* accessx */
8199accf4dfSjdolecek 	{ &vop_getattr_desc, (vop_t *) ntfs_getattr },	/* getattr */
8209accf4dfSjdolecek 	{ &vop_setattr_desc, genfs_eopnotsupp },	/* setattr */
8219accf4dfSjdolecek 	{ &vop_read_desc, (vop_t *) ntfs_read },	/* read */
8229accf4dfSjdolecek 	{ &vop_write_desc, (vop_t *) ntfs_write },	/* write */
82305d075b3Sdholland 	{ &vop_fallocate_desc, genfs_eopnotsupp },	/* fallocate */
82405d075b3Sdholland 	{ &vop_fdiscard_desc, genfs_eopnotsupp },	/* fdiscard */
8259accf4dfSjdolecek 	{ &vop_fcntl_desc, genfs_fcntl },		/* fcntl */
8269accf4dfSjdolecek 	{ &vop_ioctl_desc, genfs_enoioctl },		/* ioctl */
8279accf4dfSjdolecek 	{ &vop_poll_desc, genfs_poll },			/* poll */
8289accf4dfSjdolecek 	{ &vop_kqfilter_desc, genfs_kqfilter },		/* kqfilter */
8299accf4dfSjdolecek 	{ &vop_revoke_desc, genfs_revoke },		/* revoke */
8309accf4dfSjdolecek 	{ &vop_mmap_desc, genfs_mmap },			/* mmap */
831a748ea88Syamt 	{ &vop_fsync_desc, (vop_t *) ntfs_fsync },	/* fsync */
8329accf4dfSjdolecek 	{ &vop_seek_desc, genfs_seek },			/* seek */
83339a063b6Sjdolecek 	{ &vop_remove_desc, genfs_eopnotsupp },		/* remove */
83439a063b6Sjdolecek 	{ &vop_link_desc, genfs_eopnotsupp },		/* link */
83539a063b6Sjdolecek 	{ &vop_rename_desc, genfs_eopnotsupp },		/* rename */
83639a063b6Sjdolecek 	{ &vop_mkdir_desc, genfs_eopnotsupp },		/* mkdir */
83739a063b6Sjdolecek 	{ &vop_rmdir_desc, genfs_eopnotsupp },		/* rmdir */
8389accf4dfSjdolecek 	{ &vop_symlink_desc, genfs_eopnotsupp },	/* symlink */
8399accf4dfSjdolecek 	{ &vop_readdir_desc, (vop_t *) ntfs_readdir },	/* readdir */
8409accf4dfSjdolecek 	{ &vop_readlink_desc, genfs_eopnotsupp },	/* readlink */
8419accf4dfSjdolecek 	{ &vop_abortop_desc, genfs_abortop },		/* abortop */
8429accf4dfSjdolecek 	{ &vop_inactive_desc, (vop_t *) ntfs_inactive },	/* inactive */
8439accf4dfSjdolecek 	{ &vop_reclaim_desc, (vop_t *) ntfs_reclaim },	/* reclaim */
8449accf4dfSjdolecek 	{ &vop_lock_desc, genfs_lock },			/* lock */
8459accf4dfSjdolecek 	{ &vop_unlock_desc, genfs_unlock },		/* unlock */
8469accf4dfSjdolecek 	{ &vop_bmap_desc, (vop_t *) ntfs_bmap },	/* bmap */
8479accf4dfSjdolecek 	{ &vop_strategy_desc, (vop_t *) ntfs_strategy },	/* strategy */
8489accf4dfSjdolecek 	{ &vop_print_desc, (vop_t *) ntfs_print },	/* print */
8499accf4dfSjdolecek 	{ &vop_islocked_desc, genfs_islocked },		/* islocked */
8509accf4dfSjdolecek 	{ &vop_pathconf_desc, ntfs_pathconf },		/* pathconf */
8519accf4dfSjdolecek 	{ &vop_advlock_desc, genfs_nullop },		/* advlock */
8529accf4dfSjdolecek 	{ &vop_bwrite_desc, vn_bwrite },		/* bwrite */
8539accf4dfSjdolecek 	{ &vop_getpages_desc, genfs_compat_getpages },	/* getpages */
8549accf4dfSjdolecek 	{ &vop_putpages_desc, genfs_putpages },		/* putpages */
8559accf4dfSjdolecek 	{ NULL, NULL }
8569accf4dfSjdolecek };
8579accf4dfSjdolecek const struct vnodeopv_desc ntfs_vnodeop_opv_desc =
8589accf4dfSjdolecek 	{ &ntfs_vnodeop_p, ntfs_vnodeop_entries };
859