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