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