1/*	$OpenBSD: ntfs_vfsops.c,v 1.65 2022/01/11 03:13:59 jsg Exp $	*/
2/*	$NetBSD: ntfs_vfsops.c,v 1.7 2003/04/24 07:50:19 christos Exp $	*/
3
4/*-
5 * Copyright (c) 1998, 1999 Semen Ustimenko
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 *	Id: ntfs_vfsops.c,v 1.7 1999/05/31 11:28:30 phk Exp
30 */
31
32#include <sys/param.h>
33#include <sys/systm.h>
34#include <sys/namei.h>
35#include <sys/proc.h>
36#include <sys/kernel.h>
37#include <sys/vnode.h>
38#include <sys/lock.h>
39#include <sys/mount.h>
40#include <sys/buf.h>
41#include <sys/disk.h>
42#include <sys/fcntl.h>
43#include <sys/malloc.h>
44#include <sys/device.h>
45#include <sys/conf.h>
46#include <sys/specdev.h>
47
48/*#define NTFS_DEBUG 1*/
49#include <ntfs/ntfs.h>
50#include <ntfs/ntfs_inode.h>
51#include <ntfs/ntfs_subr.h>
52#include <ntfs/ntfs_vfsops.h>
53#include <ntfs/ntfs_ihash.h>
54
55int	ntfs_mount(struct mount *, const char *, void *,
56				struct nameidata *, struct proc *);
57int	ntfs_quotactl(struct mount *, int, uid_t, caddr_t,
58				   struct proc *);
59int	ntfs_root(struct mount *, struct vnode **);
60int	ntfs_start(struct mount *, int, struct proc *);
61int	ntfs_statfs(struct mount *, struct statfs *,
62				 struct proc *);
63int	ntfs_sync(struct mount *, int, int, struct ucred *,
64			       struct proc *);
65int	ntfs_unmount(struct mount *, int, struct proc *);
66int	ntfs_vget(struct mount *mp, ino_t ino,
67			       struct vnode **vpp);
68int	ntfs_mountfs(struct vnode *, struct mount *,
69				  struct ntfs_args *, struct proc *);
70int	ntfs_vptofh(struct vnode *, struct fid *);
71
72int	ntfs_init(struct vfsconf *);
73int	ntfs_fhtovp(struct mount *, struct fid *,
74   			     struct vnode **);
75int	ntfs_checkexp(struct mount *, struct mbuf *,
76			       int *, struct ucred **);
77int	ntfs_sysctl(int *, u_int, void *, size_t *, void *,
78 			     size_t, struct proc *);
79
80/*
81 * Verify a remote client has export rights and return these rights via.
82 * exflagsp and credanonp.
83 */
84int
85ntfs_checkexp(struct mount *mp, struct mbuf *nam, int *exflagsp,
86    struct ucred **credanonp)
87{
88	struct netcred *np;
89	struct ntfsmount *ntm = VFSTONTFS(mp);
90
91	/*
92	 * Get the export permission structure for this <mp, client> tuple.
93	 */
94	np = vfs_export_lookup(mp, &ntm->ntm_export, nam);
95	if (np == NULL)
96		return (EACCES);
97
98	*exflagsp = np->netc_exflags;
99	*credanonp = &np->netc_anon;
100	return (0);
101}
102
103int
104ntfs_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp,
105    size_t newlen, struct proc *p)
106{
107	return (EINVAL);
108}
109
110int
111ntfs_init(struct vfsconf *vcp)
112{
113	return 0;
114}
115
116int
117ntfs_mount(struct mount *mp, const char *path, void *data,
118    struct nameidata *ndp, struct proc *p)
119{
120	int		err = 0;
121	struct vnode	*devvp;
122	struct ntfs_args *args = data;
123	char fname[MNAMELEN];
124	char fspec[MNAMELEN];
125
126	ntfs_nthashinit();
127
128	/*
129	 ***
130	 * Mounting non-root file system or updating a file system
131	 ***
132	 */
133
134	/*
135	 * If updating, check whether changing from read-only to
136	 * read/write; if there is no device name, that's all we do.
137	 */
138	if (mp->mnt_flag & MNT_UPDATE) {
139		/* if not updating name...*/
140		if (args && args->fspec == NULL) {
141			/*
142			 * Process export requests.  Jumping to "success"
143			 * will return the vfs_export() error code.
144			 */
145			struct ntfsmount *ntm = VFSTONTFS(mp);
146			err = vfs_export(mp, &ntm->ntm_export, &args->export_info);
147			goto success;
148		}
149
150		printf("ntfs_mount(): MNT_UPDATE not supported\n");
151		err = EINVAL;
152		goto error_1;
153	}
154
155	/*
156	 * Not an update, or updating the name: look up the name
157	 * and verify that it refers to a sensible block device.
158	 */
159	err = copyinstr(args->fspec, fspec, sizeof(fspec), NULL);
160	if (err)
161		goto error_1;
162
163	if (disk_map(fspec, fname, sizeof(fname), DM_OPENBLCK) == -1)
164		bcopy(fspec, fname, sizeof(fname));
165
166	NDINIT(ndp, LOOKUP, FOLLOW, UIO_SYSSPACE, fname, p);
167	err = namei(ndp);
168	if (err) {
169		/* can't get devvp!*/
170		goto error_1;
171	}
172
173	devvp = ndp->ni_vp;
174
175	if (devvp->v_type != VBLK) {
176		err = ENOTBLK;
177		goto error_2;
178	}
179
180	if (major(devvp->v_rdev) >= nblkdev) {
181		err = ENXIO;
182		goto error_2;
183	}
184
185	if (mp->mnt_flag & MNT_UPDATE) {
186#if 0
187		/*
188		 ********************
189		 * UPDATE
190		 ********************
191		 */
192
193		if (devvp != ntmp->um_devvp)
194			err = EINVAL;	/* needs translation */
195		else
196			vrele(devvp);
197		/*
198		 * Update device name only on success
199		 */
200		if( !err) {
201			err = set_statfs_info(NULL, UIO_USERSPACE, args->fspec,
202			    UIO_USERSPACE, mp, p);
203		}
204#endif
205	} else {
206		/*
207		 ********************
208		 * NEW MOUNT
209		 ********************
210		 */
211
212		/*
213		 * Since this is a new mount, we want the names for
214		 * the device and the mount point copied in.  If an
215		 * error occurs,  the mountpoint is discarded by the
216		 * upper level code.
217		 */
218		/* Save "last mounted on" info for mount point (NULL pad)*/
219		bzero(mp->mnt_stat.f_mntonname, MNAMELEN);
220		strlcpy(mp->mnt_stat.f_mntonname, path, MNAMELEN);
221		bzero(mp->mnt_stat.f_mntfromname, MNAMELEN);
222		strlcpy(mp->mnt_stat.f_mntfromname, fname, MNAMELEN);
223		bzero(mp->mnt_stat.f_mntfromspec, MNAMELEN);
224		strlcpy(mp->mnt_stat.f_mntfromspec, fspec, MNAMELEN);
225		bcopy(args, &mp->mnt_stat.mount_info.ntfs_args, sizeof(*args));
226		if ( !err) {
227			err = ntfs_mountfs(devvp, mp, args, p);
228		}
229	}
230	if (err) {
231		goto error_2;
232	}
233
234	/*
235	 * Initialize FS stat information in mount struct; uses both
236	 * mp->mnt_stat.f_mntonname and mp->mnt_stat.f_mntfromname
237	 *
238	 * This code is common to root and non-root mounts
239	 */
240	(void)VFS_STATFS(mp, &mp->mnt_stat, p);
241
242	goto success;
243
244
245error_2:	/* error with devvp held*/
246
247	/* release devvp before failing*/
248	vrele(devvp);
249
250error_1:	/* no state to back out*/
251
252success:
253	return(err);
254}
255
256/*
257 * Common code for mount and mountroot
258 */
259int
260ntfs_mountfs(struct vnode *devvp, struct mount *mp, struct ntfs_args *argsp,
261    struct proc *p)
262{
263	struct buf *bp;
264	struct ntfsmount *ntmp = NULL;
265	dev_t dev = devvp->v_rdev;
266	int error, ncount, i;
267	struct vnode *vp;
268
269	/*
270	 * Disallow multiple mounts of the same device.
271	 * Disallow mounting of a device that is currently in use
272	 * (except for root, which might share swap device for miniroot).
273	 * Flush out any old buffers remaining from a previous use.
274	 */
275	error = vfs_mountedon(devvp);
276	if (error)
277		return (error);
278	ncount = vcount(devvp);
279	if (ncount > 1 && devvp != rootvp)
280		return (EBUSY);
281	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
282	error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, INFSLP);
283	VOP_UNLOCK(devvp);
284	if (error)
285		return (error);
286
287	error = VOP_OPEN(devvp, FREAD, FSCRED, p);
288	if (error)
289		return (error);
290
291	bp = NULL;
292
293	error = bread(devvp, BBLOCK, BBSIZE, &bp);
294	if (error)
295		goto out;
296	ntmp = malloc(sizeof *ntmp, M_NTFSMNT, M_WAITOK | M_ZERO);
297	bcopy(bp->b_data, &ntmp->ntm_bootfile, sizeof(struct bootfile));
298	brelse(bp);
299	bp = NULL;
300
301	if (strncmp(ntmp->ntm_bootfile.bf_sysid, NTFS_BBID, NTFS_BBIDLEN)) {
302		error = EINVAL;
303		DPRINTF("ntfs_mountfs: invalid boot block\n");
304		goto out;
305	}
306
307	{
308		int8_t cpr = ntmp->ntm_mftrecsz;
309		if( cpr > 0 )
310			ntmp->ntm_bpmftrec = ntmp->ntm_spc * cpr;
311		else
312			ntmp->ntm_bpmftrec = (1 << (-cpr)) / ntmp->ntm_bps;
313	}
314	DPRINTF("ntfs_mountfs(): bps: %u, spc: %u, media: %x, "
315	    "mftrecsz: %u (%u sects)\n", ntmp->ntm_bps, ntmp->ntm_spc,
316	    ntmp->ntm_bootfile.bf_media, ntmp->ntm_mftrecsz,
317	    ntmp->ntm_bpmftrec);
318	DPRINTF("ntfs_mountfs(): mftcn: 0x%llx|0x%llx\n",
319	    ntmp->ntm_mftcn, ntmp->ntm_mftmirrcn);
320
321	ntmp->ntm_mountp = mp;
322	ntmp->ntm_dev = dev;
323	ntmp->ntm_devvp = devvp;
324	ntmp->ntm_uid = argsp->uid;
325	ntmp->ntm_gid = argsp->gid;
326	ntmp->ntm_mode = argsp->mode;
327	ntmp->ntm_flag = argsp->flag;
328	mp->mnt_data = ntmp;
329	TAILQ_INIT(&ntmp->ntm_ntnodeq);
330
331	/* set file name encode/decode hooks XXX utf-8 only for now */
332	ntmp->ntm_wget = ntfs_utf8_wget;
333	ntmp->ntm_wput = ntfs_utf8_wput;
334	ntmp->ntm_wcmp = ntfs_utf8_wcmp;
335
336	DPRINTF("ntfs_mountfs(): case-%s,%s uid: %d, gid: %d, mode: %o\n",
337	    (ntmp->ntm_flag & NTFS_MFLAG_CASEINS) ? "insens." : "sens.",
338	    (ntmp->ntm_flag & NTFS_MFLAG_ALLNAMES) ? " allnames," : "",
339	    ntmp->ntm_uid, ntmp->ntm_gid, ntmp->ntm_mode);
340
341	/*
342	 * We read in some system nodes to do not allow
343	 * reclaim them and to have everytime access to them.
344	 */
345	{
346		int pi[3] = { NTFS_MFTINO, NTFS_ROOTINO, NTFS_BITMAPINO };
347		for (i=0; i<3; i++) {
348			error = VFS_VGET(mp, pi[i], &(ntmp->ntm_sysvn[pi[i]]));
349			if(error)
350				goto out1;
351			ntmp->ntm_sysvn[pi[i]]->v_flag |= VSYSTEM;
352			vref(ntmp->ntm_sysvn[pi[i]]);
353			vput(ntmp->ntm_sysvn[pi[i]]);
354		}
355	}
356
357	/* read the Unicode lowercase --> uppercase translation table,
358	 * if necessary */
359	if ((error = ntfs_toupper_use(mp, ntmp, p)))
360		goto out1;
361
362	/*
363	 * Scan $BitMap and count free clusters
364	 */
365	error = ntfs_calccfree(ntmp, &ntmp->ntm_cfree);
366	if(error)
367		goto out1;
368
369	/*
370	 * Read and translate to internal format attribute
371	 * definition file.
372	 */
373	{
374		int num,j;
375		struct attrdef ad;
376
377		/* Open $AttrDef */
378		error = VFS_VGET(mp, NTFS_ATTRDEFINO, &vp );
379		if(error)
380			goto out1;
381
382		/* Count valid entries */
383		for(num = 0; ; num++) {
384			error = ntfs_readattr(ntmp, VTONT(vp),
385			    NTFS_A_DATA, NULL, num * sizeof(ad), sizeof(ad),
386			    &ad, NULL);
387			if (error)
388				goto out1;
389			if (ad.ad_name[0] == 0)
390				break;
391		}
392
393		/* Alloc memory for attribute definitions */
394		ntmp->ntm_ad = mallocarray(num, sizeof(struct ntvattrdef),
395		    M_NTFSMNT, M_WAITOK);
396
397		ntmp->ntm_adnum = num;
398
399		/* Read them and translate */
400		for(i = 0; i < num; i++){
401			error = ntfs_readattr(ntmp, VTONT(vp),
402			    NTFS_A_DATA, NULL, i * sizeof(ad), sizeof(ad),
403			    &ad, NULL);
404			if (error)
405				goto out1;
406			j = 0;
407			do {
408				ntmp->ntm_ad[i].ad_name[j] = ad.ad_name[j];
409			} while(ad.ad_name[j++]);
410			ntmp->ntm_ad[i].ad_namelen = j - 1;
411			ntmp->ntm_ad[i].ad_type = ad.ad_type;
412		}
413
414		vput(vp);
415	}
416
417	mp->mnt_stat.f_fsid.val[0] = dev;
418	mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
419	mp->mnt_stat.f_namemax = NTFS_MAXFILENAME;
420	mp->mnt_flag |= MNT_LOCAL;
421	devvp->v_specmountpoint = mp;
422	return (0);
423
424out1:
425	for (i = 0; i < NTFS_SYSNODESNUM; i++)
426		if (ntmp->ntm_sysvn[i])
427			vrele(ntmp->ntm_sysvn[i]);
428
429	if (vflush(mp,NULLVP,0))
430		DPRINTF("ntfs_mountfs: vflush failed\n");
431
432out:
433	if (devvp->v_specinfo)
434		devvp->v_specmountpoint = NULL;
435	if (bp)
436		brelse(bp);
437
438	if (ntmp != NULL) {
439		if (ntmp->ntm_ad != NULL)
440			free(ntmp->ntm_ad, M_NTFSMNT, 0);
441		free(ntmp, M_NTFSMNT, 0);
442		mp->mnt_data = NULL;
443	}
444
445	/* lock the device vnode before calling VOP_CLOSE() */
446	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
447	(void)VOP_CLOSE(devvp, FREAD, NOCRED, p);
448	VOP_UNLOCK(devvp);
449
450	return (error);
451}
452
453int
454ntfs_start(struct mount *mp, int flags, struct proc *p)
455{
456	return (0);
457}
458
459int
460ntfs_unmount(struct mount *mp, int mntflags, struct proc *p)
461{
462	struct ntfsmount *ntmp;
463	int error, flags, i;
464
465	DPRINTF("ntfs_unmount: unmounting...\n");
466	ntmp = VFSTONTFS(mp);
467
468	flags = 0;
469	if(mntflags & MNT_FORCE)
470		flags |= FORCECLOSE;
471
472	DPRINTF("ntfs_unmount: vflushing...\n");
473	error = vflush(mp,NULLVP,flags | SKIPSYSTEM);
474	if (error) {
475		DPRINTF("ntfs_unmount: vflush failed: %d\n", error);
476		return (error);
477	}
478
479	/* Check if system vnodes are still referenced */
480	for(i=0;i<NTFS_SYSNODESNUM;i++) {
481		if(((mntflags & MNT_FORCE) == 0) && (ntmp->ntm_sysvn[i] &&
482		    ntmp->ntm_sysvn[i]->v_usecount > 1))
483			return (EBUSY);
484	}
485
486	/* Dereference all system vnodes */
487	for(i=0;i<NTFS_SYSNODESNUM;i++)
488		 if(ntmp->ntm_sysvn[i]) vrele(ntmp->ntm_sysvn[i]);
489
490	/* vflush system vnodes */
491	error = vflush(mp,NULLVP,flags);
492	if (error) {
493		/* XXX should this be panic() ? */
494		printf("ntfs_unmount: vflush failed(sysnodes): %d\n",error);
495	}
496
497	/* Check if the type of device node isn't VBAD before
498	 * touching v_specinfo.  If the device vnode is revoked, the
499	 * field is NULL and touching it causes null pointer dereference.
500	 */
501	if (ntmp->ntm_devvp->v_type != VBAD)
502		ntmp->ntm_devvp->v_specmountpoint = NULL;
503
504	/* lock the device vnode before calling VOP_CLOSE() */
505	vn_lock(ntmp->ntm_devvp, LK_EXCLUSIVE | LK_RETRY);
506	vinvalbuf(ntmp->ntm_devvp, V_SAVE, NOCRED, p, 0, INFSLP);
507	(void)VOP_CLOSE(ntmp->ntm_devvp, FREAD, NOCRED, p);
508	vput(ntmp->ntm_devvp);
509
510	/* free the toupper table, if this has been last mounted ntfs volume */
511	ntfs_toupper_unuse(p);
512
513	DPRINTF("ntfs_unmount: freeing memory...\n");
514	free(ntmp->ntm_ad, M_NTFSMNT, 0);
515	free(ntmp, M_NTFSMNT, 0);
516	mp->mnt_data = NULL;
517	mp->mnt_flag &= ~MNT_LOCAL;
518	return (0);
519}
520
521int
522ntfs_root(struct mount *mp, struct vnode **vpp)
523{
524	struct vnode *nvp;
525	int error = 0;
526
527	DPRINTF("ntfs_root(): sysvn: %p\n",
528	    VFSTONTFS(mp)->ntm_sysvn[NTFS_ROOTINO]);
529	error = VFS_VGET(mp, (ino_t)NTFS_ROOTINO, &nvp);
530	if(error) {
531		printf("ntfs_root: VFS_VGET failed: %d\n",error);
532		return (error);
533	}
534
535	*vpp = nvp;
536	return (0);
537}
538
539/*
540 * Do operations associated with quotas, not supported
541 */
542int
543ntfs_quotactl(struct mount *mp, int cmds, uid_t uid, caddr_t arg,
544    struct proc *p)
545{
546	return EOPNOTSUPP;
547}
548
549int
550ntfs_calccfree(struct ntfsmount *ntmp, cn_t *cfreep)
551{
552	struct vnode *vp;
553	u_int8_t *tmp;
554	int j, error;
555	cn_t cfree = 0;
556	uint64_t bmsize, offset;
557	size_t chunksize, i;
558
559	vp = ntmp->ntm_sysvn[NTFS_BITMAPINO];
560
561	bmsize = VTOF(vp)->f_size;
562
563	if (bmsize > 1024 * 1024)
564		chunksize = 1024 * 1024;
565	else
566		chunksize = bmsize;
567
568	tmp = malloc(chunksize, M_TEMP, M_WAITOK);
569
570	for (offset = 0; offset < bmsize; offset += chunksize) {
571		if (chunksize > bmsize - offset)
572			chunksize = bmsize - offset;
573
574		error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL,
575		    offset, chunksize, tmp, NULL);
576		if (error)
577			goto out;
578
579		for (i = 0; i < chunksize; i++)
580			for (j = 0; j < 8; j++)
581				if (~tmp[i] & (1 << j))
582					cfree++;
583	}
584
585	*cfreep = cfree;
586
587    out:
588	free(tmp, M_TEMP, 0);
589	return(error);
590}
591
592int
593ntfs_statfs(struct mount *mp, struct statfs *sbp, struct proc *p)
594{
595	struct ntfsmount *ntmp = VFSTONTFS(mp);
596	u_int64_t mftallocated;
597
598	DPRINTF("ntfs_statfs():\n");
599
600	mftallocated = VTOF(ntmp->ntm_sysvn[NTFS_MFTINO])->f_allocated;
601
602	sbp->f_bsize = ntmp->ntm_bps;
603	sbp->f_iosize = ntmp->ntm_bps * ntmp->ntm_spc;
604	sbp->f_blocks = ntmp->ntm_bootfile.bf_spv;
605	sbp->f_bfree = sbp->f_bavail = ntfs_cntobn(ntmp->ntm_cfree);
606	sbp->f_ffree = sbp->f_favail = sbp->f_bfree / ntmp->ntm_bpmftrec;
607	sbp->f_files = mftallocated / ntfs_bntob(ntmp->ntm_bpmftrec) +
608		       sbp->f_ffree;
609	copy_statfs_info(sbp, mp);
610
611	return (0);
612}
613
614int
615ntfs_sync(struct mount *mp, int waitfor, int stall, struct ucred *cred, struct proc *p)
616{
617	/*DPRINTF("ntfs_sync():\n");*/
618	return (0);
619}
620
621int
622ntfs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
623{
624	struct ntfid *ntfhp = (struct ntfid *)fhp;
625	int error;
626
627	DDPRINTF("ntfs_fhtovp(): %s: %u\n",
628	    mp->mnt_stat.f_mntonname, ntfhp->ntfid_ino);
629
630	error = ntfs_vgetex(mp, ntfhp->ntfid_ino, ntfhp->ntfid_attr, NULL,
631			LK_EXCLUSIVE | LK_RETRY, 0, vpp); /* XXX */
632	if (error != 0) {
633		*vpp = NULLVP;
634		return (error);
635	}
636
637	/* XXX as unlink/rmdir/mkdir/creat are not currently possible
638	 * with NTFS, we don't need to check anything else for now */
639	return (0);
640}
641
642int
643ntfs_vptofh(struct vnode *vp, struct fid *fhp)
644{
645	struct ntnode *ntp;
646	struct ntfid *ntfhp;
647	struct fnode *fn;
648
649	DDPRINTF("ntfs_fhtovp(): %s: %p\n",
650	    vp->v_mount->mnt_stat.f_mntonname, vp);
651
652	fn = VTOF(vp);
653	ntp = VTONT(vp);
654	ntfhp = (struct ntfid *)fhp;
655	ntfhp->ntfid_len = sizeof(struct ntfid);
656	ntfhp->ntfid_ino = ntp->i_number;
657	ntfhp->ntfid_attr = fn->f_attrtype;
658#ifdef notyet
659	ntfhp->ntfid_gen = ntp->i_gen;
660#endif
661	return (0);
662}
663
664int
665ntfs_vgetex(struct mount *mp, ntfsino_t ino, u_int32_t attrtype, char *attrname,
666    u_long lkflags, u_long flags, struct vnode **vpp)
667{
668	int error;
669	struct ntfsmount *ntmp;
670	struct ntnode *ip;
671	struct fnode *fp;
672	struct vnode *vp;
673	enum vtype f_type;
674
675	DPRINTF("ntfs_vgetex: ino: %u, attr: 0x%x:%s, lkf: 0x%lx, f: 0x%lx\n",
676	    ino, attrtype, attrname ? attrname : "", lkflags, flags);
677
678	ntmp = VFSTONTFS(mp);
679	*vpp = NULL;
680
681	/* Get ntnode */
682	error = ntfs_ntlookup(ntmp, ino, &ip);
683	if (error) {
684		printf("ntfs_vget: ntfs_ntget failed\n");
685		return (error);
686	}
687
688	/* It may be not initialized fully, so force load it */
689	if (!(flags & VG_DONTLOADIN) && !(ip->i_flag & IN_LOADED)) {
690		error = ntfs_loadntnode(ntmp, ip);
691		if(error) {
692			printf("ntfs_vget: CAN'T LOAD ATTRIBUTES FOR INO: %d\n",
693			       ip->i_number);
694			ntfs_ntput(ip);
695
696			return (error);
697		}
698	}
699
700	error = ntfs_fget(ntmp, ip, attrtype, attrname, &fp);
701	if (error) {
702		printf("ntfs_vget: ntfs_fget failed\n");
703		ntfs_ntput(ip);
704
705		return (error);
706	}
707
708	if (!(flags & VG_DONTVALIDFN) && !(fp->f_flag & FN_VALID)) {
709		if ((ip->i_frflag & NTFS_FRFLAG_DIR) &&
710		    (fp->f_attrtype == NTFS_A_DATA && fp->f_attrname == NULL)) {
711			f_type = VDIR;
712		} else if (flags & VG_EXT) {
713			f_type = VNON;
714			fp->f_size = fp->f_allocated = 0;
715		} else {
716			f_type = VREG;
717
718			error = ntfs_filesize(ntmp, fp,
719					      &fp->f_size, &fp->f_allocated);
720			if (error) {
721				ntfs_ntput(ip);
722
723				return (error);
724			}
725		}
726
727		fp->f_flag |= FN_VALID;
728	}
729
730	/*
731	 * We may be calling vget() now. To avoid potential deadlock, we need
732	 * to release ntnode lock, since due to locking order vnode
733	 * lock has to be acquired first.
734	 * ntfs_fget() bumped ntnode usecount, so ntnode won't be recycled
735	 * prematurely.
736	 */
737	ntfs_ntput(ip);
738
739	if (FTOV(fp)) {
740		/* vget() returns error if the vnode has been recycled */
741		if (vget(FTOV(fp), lkflags) == 0) {
742			*vpp = FTOV(fp);
743			return (0);
744		}
745	}
746
747	error = getnewvnode(VT_NTFS, ntmp->ntm_mountp, &ntfs_vops, &vp);
748	if(error) {
749		ntfs_frele(fp);
750		ntfs_ntput(ip);
751
752		return (error);
753	}
754	DPRINTF("ntfs_vget: vnode: %p for ntnode: %u\n", vp, ino);
755
756	fp->f_vp = vp;
757	vp->v_data = fp;
758	vp->v_type = f_type;
759
760	if (ino == NTFS_ROOTINO)
761		vp->v_flag |= VROOT;
762
763	if (lkflags & LK_TYPE_MASK) {
764		error = vn_lock(vp, lkflags);
765		if (error) {
766			vput(vp);
767			return (error);
768		}
769	}
770
771	*vpp = vp;
772	return (0);
773}
774
775int
776ntfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
777{
778	if (ino > (ntfsino_t)-1)
779		panic("ntfs_vget: alien ino_t %llu", (unsigned long long)ino);
780	return ntfs_vgetex(mp, ino, NTFS_A_DATA, NULL,
781			LK_EXCLUSIVE | LK_RETRY, 0, vpp); /* XXX */
782}
783
784const struct vfsops ntfs_vfsops = {
785	.vfs_mount	= ntfs_mount,
786	.vfs_start	= ntfs_start,
787	.vfs_unmount	= ntfs_unmount,
788	.vfs_root	= ntfs_root,
789	.vfs_quotactl	= ntfs_quotactl,
790	.vfs_statfs	= ntfs_statfs,
791	.vfs_sync	= ntfs_sync,
792	.vfs_vget	= ntfs_vget,
793	.vfs_fhtovp	= ntfs_fhtovp,
794	.vfs_vptofh	= ntfs_vptofh,
795	.vfs_init	= ntfs_init,
796	.vfs_sysctl	= ntfs_sysctl,
797	.vfs_checkexp	= ntfs_checkexp,
798};
799