xref: /openbsd-src/sys/ntfs/ntfs_vfsops.c (revision 2b0358df1d88d06ef4139321dd05bd5e05d91eaf)
1 /*	$OpenBSD: ntfs_vfsops.c,v 1.13 2008/05/13 02:24:08 brad 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 #if defined(__FreeBSD__)
101 static int	ntfs_init(struct vfsconf *);
102 static int	ntfs_fhtovp(struct mount *, struct fid *,
103 				 struct sockaddr *, struct vnode **,
104 				 int *, struct ucred **);
105 #elif defined(__NetBSD__)
106 static void	ntfs_init(void);
107 static void	ntfs_reinit(void);
108 static void	ntfs_done(void);
109 static int	ntfs_fhtovp(struct mount *, struct fid *,
110 				 struct vnode **);
111 static int	ntfs_checkexp(struct mount *, struct mbuf *,
112 				   int *, struct ucred **);
113 static int	ntfs_mountroot(void);
114 static int	ntfs_sysctl(int *, u_int, void *, size_t *, void *,
115 				 size_t, struct proc *);
116 #elif defined(__OpenBSD__)
117 static int	ntfs_init(struct vfsconf *);
118 static int	ntfs_fhtovp(struct mount *, struct fid *,
119    			     struct vnode **);
120 static int	ntfs_checkexp(struct mount *, struct mbuf *,
121 			       int *, struct ucred **);
122 static int	ntfs_sysctl(int *, u_int, void *, size_t *, void *,
123  			     size_t, struct proc *);
124 #else
125 static int	ntfs_init(void);
126 static int	ntfs_fhtovp(struct mount *, struct fid *,
127 				 struct mbuf *, struct vnode **,
128 				 int *, struct ucred **);
129 #endif
130 
131 #if defined(__FreeBSD__) || defined(__NetBSD__)
132 struct genfs_ops ntfs_genfsops = {
133 	NULL,
134 	NULL,
135 	genfs_compat_gop_write,
136 };
137 #endif
138 
139 #if defined(__NetBSD__) || defined(__OpenBSD__)
140 /*
141  * Verify a remote client has export rights and return these rights via.
142  * exflagsp and credanonp.
143  */
144 static int
145 ntfs_checkexp(mp, nam, exflagsp, credanonp)
146 	struct mount *mp;
147 	struct mbuf *nam;
148 	int *exflagsp;
149 	struct ucred **credanonp;
150 {
151 	struct netcred *np;
152 	struct ntfsmount *ntm = VFSTONTFS(mp);
153 
154 	/*
155 	 * Get the export permission structure for this <mp, client> tuple.
156 	 */
157 	np = vfs_export_lookup(mp, &ntm->ntm_export, nam);
158 	if (np == NULL)
159 		return (EACCES);
160 
161 	*exflagsp = np->netc_exflags;
162 	*credanonp = &np->netc_anon;
163 	return (0);
164 }
165 
166 /*ARGSUSED*/
167 static int
168 ntfs_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
169 	int *name;
170 	u_int namelen;
171 	void *oldp;
172 	size_t *oldlenp;
173 	void *newp;
174 	size_t newlen;
175 	struct proc *p;
176 {
177 	return (EINVAL);
178 }
179 
180 #endif
181 
182 #ifdef __NetBSD__
183 static int
184 ntfs_mountroot()
185 {
186 	struct mount *mp;
187 	struct proc *p = curproc;	/* XXX */
188 	int error;
189 	struct ntfs_args args;
190 
191 	if (root_device->dv_class != DV_DISK)
192 		return (ENODEV);
193 
194 	/*
195 	 * Get vnodes for rootdev.
196 	 */
197 	if (bdevvp(rootdev, &rootvp))
198 		panic("ntfs_mountroot: can't setup rootvp");
199 
200 	if ((error = vfs_rootmountalloc(MOUNT_NTFS, "root_device", &mp))) {
201 		vrele(rootvp);
202 		return (error);
203 	}
204 
205 	args.flag = 0;
206 	args.uid = 0;
207 	args.gid = 0;
208 	args.mode = 0777;
209 
210 	if ((error = ntfs_mountfs(rootvp, mp, &args, p)) != 0) {
211 		mp->mnt_op->vfs_refcount--;
212 		vfs_unbusy(mp);
213 		free(mp, M_MOUNT);
214 		vrele(rootvp);
215 		return (error);
216 	}
217 
218 	CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
219 	(void)ntfs_statfs(mp, &mp->mnt_stat, p);
220 	vfs_unbusy(mp);
221 
222 	return (0);
223 }
224 
225 static void
226 ntfs_init()
227 {
228 #ifdef _LKM
229 	malloc_type_attach(M_NTFSMNT);
230 	malloc_type_attach(M_NTFSNTNODE);
231 	malloc_type_attach(M_NTFSFNODE);
232 	malloc_type_attach(M_NTFSDIR);
233 	malloc_type_attach(M_NTFSNTHASH);
234 	malloc_type_attach(M_NTFSNTVATTR);
235 	malloc_type_attach(M_NTFSRDATA);
236 	malloc_type_attach(M_NTFSDECOMP);
237 	malloc_type_attach(M_NTFSRUN);
238 #endif
239 	ntfs_nthashinit();
240 	ntfs_toupper_init();
241 }
242 
243 static void
244 ntfs_reinit()
245 {
246 	ntfs_nthashreinit();
247 }
248 
249 static void
250 ntfs_done()
251 {
252 	ntfs_nthashdone();
253 #ifdef _LKM
254 	malloc_type_detach(M_NTFSMNT);
255 	malloc_type_detach(M_NTFSNTNODE);
256 	malloc_type_detach(M_NTFSFNODE);
257 	malloc_type_detach(M_NTFSDIR);
258 	malloc_type_detach(M_NTFSNTHASH);
259 	malloc_type_detach(M_NTFSNTVATTR);
260 	malloc_type_detach(M_NTFSRDATA);
261 	malloc_type_detach(M_NTFSDECOMP);
262 	malloc_type_detach(M_NTFSRUN);
263 #endif
264 }
265 
266 #elif defined(__FreeBSD__) || defined(__OpenBSD__)
267 
268 static int
269 ntfs_init (
270 	struct vfsconf *vcp )
271 {
272 	ntfs_nthashinit();
273 	ntfs_toupper_init();
274 	return 0;
275 }
276 
277 #endif /* NetBSD */
278 
279 static int
280 ntfs_mount(
281 	struct mount *mp,
282 #if defined(__FreeBSD__)
283 	char *path,
284 	caddr_t data,
285 #else
286 	const char *path,
287 	void *data,
288 #endif
289 	struct nameidata *ndp,
290 	struct proc *p )
291 {
292 	int		err = 0;
293 	struct vnode	*devvp;
294 	struct ntfs_args args;
295 	size_t size;
296 	mode_t amode;
297 
298 #ifdef __FreeBSD__
299 	/*
300 	 * Use NULL path to flag a root mount
301 	 */
302 	if( path == NULL) {
303 		/*
304 		 ***
305 		 * Mounting root file system
306 		 ***
307 		 */
308 
309 		/* Get vnode for root device*/
310 		if( bdevvp( rootdev, &rootvp))
311 			panic("ffs_mountroot: can't setup bdevvp for root");
312 
313 		/*
314 		 * FS specific handling
315 		 */
316 		mp->mnt_flag |= MNT_RDONLY;	/* XXX globally applicable?*/
317 
318 		/*
319 		 * Attempt mount
320 		 */
321 		if( ( err = ntfs_mountfs(rootvp, mp, &args, p)) != 0) {
322 			/* fs specific cleanup (if any)*/
323 			goto error_1;
324 		}
325 
326 		goto dostatfs;		/* success*/
327 
328 	}
329 #endif /* FreeBSD */
330 
331 #ifdef __NetBSD__
332 	if (mp->mnt_flag & MNT_GETARGS) {
333 		struct ntfsmount *ntmp = VFSTONTFS(mp);
334 		if (ntmp == NULL)
335 			return EIO;
336 		args.fspec = NULL;
337 		args.uid = ntmp->ntm_uid;
338 		args.gid = ntmp->ntm_gid;
339 		args.mode = ntmp->ntm_mode;
340 		args.flag = ntmp->ntm_flag;
341 		vfs_showexport(mp, &args.export, &ntmp->ntm_export);
342 		return copyout(&args, data, sizeof(args));
343 	}
344 #endif
345 
346 	/*
347 	 ***
348 	 * Mounting non-root file system or updating a file system
349 	 ***
350 	 */
351 
352 	/* copy in user arguments*/
353 	err = copyin(data, (caddr_t)&args, sizeof (struct ntfs_args));
354 	if (err)
355 		goto error_1;		/* can't get arguments*/
356 
357 	/*
358 	 * If updating, check whether changing from read-only to
359 	 * read/write; if there is no device name, that's all we do.
360 	 */
361 	if (mp->mnt_flag & MNT_UPDATE) {
362 		/* if not updating name...*/
363 		if (args.fspec == 0) {
364 			/*
365 			 * Process export requests.  Jumping to "success"
366 			 * will return the vfs_export() error code.
367 			 */
368 			struct ntfsmount *ntm = VFSTONTFS(mp);
369 			err = vfs_export(mp, &ntm->ntm_export, &args.export_info);
370 			goto success;
371 		}
372 
373 		printf("ntfs_mount(): MNT_UPDATE not supported\n");
374 		err = EINVAL;
375 		goto error_1;
376 	}
377 
378 	/*
379 	 * Not an update, or updating the name: look up the name
380 	 * and verify that it refers to a sensible block device.
381 	 */
382 	NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
383 	err = namei(ndp);
384 	if (err) {
385 		/* can't get devvp!*/
386 		goto error_1;
387 	}
388 
389 	devvp = ndp->ni_vp;
390 
391 	if (devvp->v_type != VBLK) {
392 		err = ENOTBLK;
393 		goto error_2;
394 	}
395 
396 #ifdef __FreeBSD__
397 	if (bdevsw(devvp->v_rdev) == NULL) {
398 #elif defined(__NetBSD__)
399 	if (bdevsw_lookup(devvp->v_rdev) == NULL) {
400 #else
401 	if (major(devvp->v_rdev) >= nblkdev) {
402 #endif
403 		err = ENXIO;
404 		goto error_2;
405 	}
406 
407 	/*
408 	 * If we are not root, make sure we have permission to access the
409 	 * requested device.
410 	 */
411 	if (p->p_ucred->cr_uid) {
412 		amode = (mp->mnt_flag & MNT_RDONLY) ? VREAD : (VREAD | VWRITE);
413 		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
414 		err = VOP_ACCESS(devvp, amode, p->p_ucred, p);
415 		VOP_UNLOCK(devvp, 0, p);
416 		if (err)
417 			goto error_2;
418 	}
419 
420 	if (mp->mnt_flag & MNT_UPDATE) {
421 #if 0
422 		/*
423 		 ********************
424 		 * UPDATE
425 		 ********************
426 		 */
427 
428 		if (devvp != ntmp->um_devvp)
429 			err = EINVAL;	/* needs translation */
430 		else
431 			vrele(devvp);
432 		/*
433 		 * Update device name only on success
434 		 */
435 		if( !err) {
436 			err = set_statfs_info(NULL, UIO_USERSPACE, args.fspec,
437 			    UIO_USERSPACE, mp, p);
438 		}
439 #endif
440 	} else {
441 		/*
442 		 ********************
443 		 * NEW MOUNT
444 		 ********************
445 		 */
446 
447 		/*
448 		 * Since this is a new mount, we want the names for
449 		 * the device and the mount point copied in.  If an
450 		 * error occurs,  the mountpoint is discarded by the
451 		 * upper level code.
452 		 */
453 		/* Save "last mounted on" info for mount point (NULL pad)*/
454 #if defined(__FreeBSD__) || defined(__NetBSD__)
455 		err = set_statfs_info(path, UIO_USERSPACE, args.fspec,
456 		    UIO_USERSPACE, mp, p);
457 #else
458 		(void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1,
459 		           &size);
460 		bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
461 		(void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname,
462 		           MNAMELEN - 1, &size);
463 		bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
464 		bcopy(&args, &mp->mnt_stat.mount_info.ntfs_args, sizeof(args));
465 #endif
466 		if ( !err) {
467 			err = ntfs_mountfs(devvp, mp, &args, p);
468 		}
469 	}
470 	if (err) {
471 		goto error_2;
472 	}
473 
474 #ifdef __FreeBSD__
475 dostatfs:
476 #endif
477 	/*
478 	 * Initialize FS stat information in mount struct; uses both
479 	 * mp->mnt_stat.f_mntonname and mp->mnt_stat.f_mntfromname
480 	 *
481 	 * This code is common to root and non-root mounts
482 	 */
483 	(void)VFS_STATFS(mp, &mp->mnt_stat, p);
484 
485 	goto success;
486 
487 
488 error_2:	/* error with devvp held*/
489 
490 	/* release devvp before failing*/
491 	vrele(devvp);
492 
493 error_1:	/* no state to back out*/
494 
495 success:
496 	return(err);
497 }
498 
499 /*
500  * Common code for mount and mountroot
501  */
502 int
503 ntfs_mountfs(devvp, mp, argsp, p)
504 	struct vnode *devvp;
505 	struct mount *mp;
506 	struct ntfs_args *argsp;
507 	struct proc *p;
508 {
509 	struct buf *bp;
510 	struct ntfsmount *ntmp = NULL;
511 	dev_t dev = devvp->v_rdev;
512 	int error, ronly, ncount, i;
513 	struct vnode *vp;
514 
515 	/*
516 	 * Disallow multiple mounts of the same device.
517 	 * Disallow mounting of a device that is currently in use
518 	 * (except for root, which might share swap device for miniroot).
519 	 * Flush out any old buffers remaining from a previous use.
520 	 */
521 	error = vfs_mountedon(devvp);
522 	if (error)
523 		return (error);
524 	ncount = vcount(devvp);
525 	if (ncount > 1 && devvp != rootvp)
526 		return (EBUSY);
527 	error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0);
528 	if (error)
529 		return (error);
530 
531 	ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
532 	error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p);
533 	if (error)
534 		return (error);
535 
536 	bp = NULL;
537 
538 	error = bread(devvp, BBLOCK, BBSIZE, NOCRED, &bp);
539 	if (error)
540 		goto out;
541 	ntmp = malloc(sizeof *ntmp, M_NTFSMNT, M_WAITOK | M_ZERO);
542 	bcopy(bp->b_data, &ntmp->ntm_bootfile, sizeof(struct bootfile));
543 	brelse(bp);
544 	bp = NULL;
545 
546 	if (strncmp(ntmp->ntm_bootfile.bf_sysid, NTFS_BBID, NTFS_BBIDLEN)) {
547 		error = EINVAL;
548 		dprintf(("ntfs_mountfs: invalid boot block\n"));
549 		goto out;
550 	}
551 
552 	{
553 		int8_t cpr = ntmp->ntm_mftrecsz;
554 		if( cpr > 0 )
555 			ntmp->ntm_bpmftrec = ntmp->ntm_spc * cpr;
556 		else
557 			ntmp->ntm_bpmftrec = (1 << (-cpr)) / ntmp->ntm_bps;
558 	}
559 	dprintf(("ntfs_mountfs(): bps: %d, spc: %d, media: %x, mftrecsz: %d (%d sects)\n",
560 		ntmp->ntm_bps,ntmp->ntm_spc,ntmp->ntm_bootfile.bf_media,
561 		ntmp->ntm_mftrecsz,ntmp->ntm_bpmftrec));
562 	dprintf(("ntfs_mountfs(): mftcn: 0x%x|0x%x\n",
563 		(u_int32_t)ntmp->ntm_mftcn,(u_int32_t)ntmp->ntm_mftmirrcn));
564 
565 	ntmp->ntm_mountp = mp;
566 	ntmp->ntm_dev = dev;
567 	ntmp->ntm_devvp = devvp;
568 	ntmp->ntm_uid = argsp->uid;
569 	ntmp->ntm_gid = argsp->gid;
570 	ntmp->ntm_mode = argsp->mode;
571 	ntmp->ntm_flag = argsp->flag;
572 #ifdef __OpenBSD__
573 	mp->mnt_data = (qaddr_t) ntmp;
574 #else
575 	mp->mnt_data = ntmp;
576 #endif
577 
578 	/* set file name encode/decode hooks XXX utf-8 only for now */
579 	ntmp->ntm_wget = ntfs_utf8_wget;
580 	ntmp->ntm_wput = ntfs_utf8_wput;
581 	ntmp->ntm_wcmp = ntfs_utf8_wcmp;
582 
583 	dprintf(("ntfs_mountfs(): case-%s,%s uid: %d, gid: %d, mode: %o\n",
584 		(ntmp->ntm_flag & NTFS_MFLAG_CASEINS)?"insens.":"sens.",
585 		(ntmp->ntm_flag & NTFS_MFLAG_ALLNAMES)?" allnames,":"",
586 		ntmp->ntm_uid, ntmp->ntm_gid, ntmp->ntm_mode));
587 
588 	/*
589 	 * We read in some system nodes to do not allow
590 	 * reclaim them and to have everytime access to them.
591 	 */
592 	{
593 		int pi[3] = { NTFS_MFTINO, NTFS_ROOTINO, NTFS_BITMAPINO };
594 		for (i=0; i<3; i++) {
595 			error = VFS_VGET(mp, pi[i], &(ntmp->ntm_sysvn[pi[i]]));
596 			if(error)
597 				goto out1;
598 			ntmp->ntm_sysvn[pi[i]]->v_flag |= VSYSTEM;
599 			VREF(ntmp->ntm_sysvn[pi[i]]);
600 			vput(ntmp->ntm_sysvn[pi[i]]);
601 		}
602 	}
603 
604 	/* read the Unicode lowercase --> uppercase translation table,
605 	 * if necessary */
606 #ifndef __OpenBSD__
607 	if ((error = ntfs_toupper_use(mp, ntmp)))
608 #else
609 	if ((error = ntfs_toupper_use(mp, ntmp, p)))
610 #endif
611 		goto out1;
612 
613 	/*
614 	 * Scan $BitMap and count free clusters
615 	 */
616 	error = ntfs_calccfree(ntmp, &ntmp->ntm_cfree);
617 	if(error)
618 		goto out1;
619 
620 	/*
621 	 * Read and translate to internal format attribute
622 	 * definition file.
623 	 */
624 	{
625 		int num,j;
626 		struct attrdef ad;
627 
628 		/* Open $AttrDef */
629 		error = VFS_VGET(mp, NTFS_ATTRDEFINO, &vp );
630 		if(error)
631 			goto out1;
632 
633 		/* Count valid entries */
634 		for(num=0;;num++) {
635 			error = ntfs_readattr(ntmp, VTONT(vp),
636 					NTFS_A_DATA, NULL,
637 					num * sizeof(ad), sizeof(ad),
638 					&ad, NULL);
639 			if (error)
640 				goto out1;
641 			if (ad.ad_name[0] == 0)
642 				break;
643 		}
644 
645 		/* Alloc memory for attribute definitions */
646 		ntmp->ntm_ad = (struct ntvattrdef *) malloc(
647 			num * sizeof(struct ntvattrdef),
648 			M_NTFSMNT, M_WAITOK);
649 
650 		ntmp->ntm_adnum = num;
651 
652 		/* Read them and translate */
653 		for(i=0;i<num;i++){
654 			error = ntfs_readattr(ntmp, VTONT(vp),
655 					NTFS_A_DATA, NULL,
656 					i * sizeof(ad), sizeof(ad),
657 					&ad, NULL);
658 			if (error)
659 				goto out1;
660 			j = 0;
661 			do {
662 				ntmp->ntm_ad[i].ad_name[j] = ad.ad_name[j];
663 			} while(ad.ad_name[j++]);
664 			ntmp->ntm_ad[i].ad_namelen = j - 1;
665 			ntmp->ntm_ad[i].ad_type = ad.ad_type;
666 		}
667 
668 		vput(vp);
669 	}
670 
671 #if defined(__FreeBSD__)
672 	mp->mnt_stat.f_fsid.val[0] = dev2udev(dev);
673 	mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
674 #else
675 	mp->mnt_stat.f_fsid.val[0] = dev;
676 	mp->mnt_stat.f_fsid.val[1] = makefstype(MOUNT_NTFS);
677 #endif
678 	mp->mnt_maxsymlinklen = 0;
679 	mp->mnt_flag |= MNT_LOCAL;
680 	devvp->v_specmountpoint = mp;
681 	return (0);
682 
683 out1:
684 	for (i = 0; i < NTFS_SYSNODESNUM; i++)
685 		if (ntmp->ntm_sysvn[i])
686 			vrele(ntmp->ntm_sysvn[i]);
687 
688 	if (vflush(mp,NULLVP,0))
689 		dprintf(("ntfs_mountfs: vflush failed\n"));
690 
691 out:
692 	devvp->v_specmountpoint = NULL;
693 	if (bp)
694 		brelse(bp);
695 
696 	if (ntmp != NULL) {
697 		if (ntmp->ntm_ad != NULL)
698 			free(ntmp->ntm_ad, M_NTFSMNT);
699 		free(ntmp, M_NTFSMNT);
700 		mp->mnt_data = NULL;
701 	}
702 
703 	/* lock the device vnode before calling VOP_CLOSE() */
704 	VN_LOCK(devvp, LK_EXCLUSIVE | LK_RETRY, p);
705 	(void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p);
706 	VOP__UNLOCK(devvp, 0, p);
707 
708 	return (error);
709 }
710 
711 static int
712 ntfs_start (
713 	struct mount *mp,
714 	int flags,
715 	struct proc *p )
716 {
717 	return (0);
718 }
719 
720 static int
721 ntfs_unmount(
722 	struct mount *mp,
723 	int mntflags,
724 	struct proc *p)
725 {
726 	struct ntfsmount *ntmp;
727 	int error, ronly = 0, flags, i;
728 
729 	dprintf(("ntfs_unmount: unmounting...\n"));
730 	ntmp = VFSTONTFS(mp);
731 
732 	flags = 0;
733 	if(mntflags & MNT_FORCE)
734 		flags |= FORCECLOSE;
735 
736 	dprintf(("ntfs_unmount: vflushing...\n"));
737 	error = vflush(mp,NULLVP,flags | SKIPSYSTEM);
738 	if (error) {
739 		dprintf(("ntfs_unmount: vflush failed: %d\n",error));
740 		return (error);
741 	}
742 
743 	/* Check if only system vnodes are rest */
744 	for(i=0;i<NTFS_SYSNODESNUM;i++)
745 		 if((ntmp->ntm_sysvn[i]) &&
746 		    (ntmp->ntm_sysvn[i]->v_usecount > 1)) return (EBUSY);
747 
748 	/* Dereference all system vnodes */
749 	for(i=0;i<NTFS_SYSNODESNUM;i++)
750 		 if(ntmp->ntm_sysvn[i]) vrele(ntmp->ntm_sysvn[i]);
751 
752 	/* vflush system vnodes */
753 	error = vflush(mp,NULLVP,flags);
754 	if (error) {
755 		/* XXX should this be panic() ? */
756 		printf("ntfs_unmount: vflush failed(sysnodes): %d\n",error);
757 	}
758 
759 	/* Check if the type of device node isn't VBAD before
760 	 * touching v_specinfo.  If the device vnode is revoked, the
761 	 * field is NULL and touching it causes null pointer derefercence.
762 	 */
763 	if (ntmp->ntm_devvp->v_type != VBAD)
764 		ntmp->ntm_devvp->v_specmountpoint = NULL;
765 
766 	vinvalbuf(ntmp->ntm_devvp, V_SAVE, NOCRED, p, 0, 0);
767 
768 	/* lock the device vnode before calling VOP_CLOSE() */
769 #ifndef __OpenBSD__
770 	VOP_LOCK(ntmp->ntm_devvp, LK_EXCLUSIVE | LK_RETRY);
771 #else
772 	VOP_LOCK(ntmp->ntm_devvp, LK_EXCLUSIVE | LK_RETRY, p);
773 #endif
774 	error = VOP_CLOSE(ntmp->ntm_devvp, ronly ? FREAD : FREAD|FWRITE,
775 		NOCRED, p);
776 	VOP__UNLOCK(ntmp->ntm_devvp, 0, p);
777 
778 	vrele(ntmp->ntm_devvp);
779 
780 	/* free the toupper table, if this has been last mounted ntfs volume */
781 #ifndef __OpenBSD__
782 	ntfs_toupper_unuse();
783 #else
784 	ntfs_toupper_unuse(p);
785 #endif
786 
787 	dprintf(("ntfs_umount: freeing memory...\n"));
788 	mp->mnt_data = NULL;
789 	mp->mnt_flag &= ~MNT_LOCAL;
790 	free(ntmp->ntm_ad, M_NTFSMNT);
791 	free(ntmp, M_NTFSMNT);
792 	return (error);
793 }
794 
795 static int
796 ntfs_root(
797 	struct mount *mp,
798 	struct vnode **vpp )
799 {
800 	struct vnode *nvp;
801 	int error = 0;
802 
803 	dprintf(("ntfs_root(): sysvn: %p\n",
804 		VFSTONTFS(mp)->ntm_sysvn[NTFS_ROOTINO]));
805 	error = VFS_VGET(mp, (ino_t)NTFS_ROOTINO, &nvp);
806 	if(error) {
807 		printf("ntfs_root: VFS_VGET failed: %d\n",error);
808 		return (error);
809 	}
810 
811 	*vpp = nvp;
812 	return (0);
813 }
814 
815 /*
816  * Do operations associated with quotas, not supported
817  */
818 /* ARGSUSED */
819 static int
820 ntfs_quotactl (
821 	struct mount *mp,
822 	int cmds,
823 	uid_t uid,
824 	caddr_t arg,
825 	struct proc *p)
826 {
827 
828 	return EOPNOTSUPP;
829 }
830 
831 int
832 ntfs_calccfree(
833 	struct ntfsmount *ntmp,
834 	cn_t *cfreep)
835 {
836 	struct vnode *vp;
837 	u_int8_t *tmp;
838 	int j, error;
839 	cn_t cfree = 0;
840 	size_t bmsize, i;
841 
842 	vp = ntmp->ntm_sysvn[NTFS_BITMAPINO];
843 
844 	bmsize = VTOF(vp)->f_size;
845 
846 	tmp = (u_int8_t *) malloc(bmsize, M_TEMP, M_WAITOK);
847 
848 	error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL,
849 			       0, bmsize, tmp, NULL);
850 	if (error)
851 		goto out;
852 
853 	for(i=0;i<bmsize;i++)
854 		for(j=0;j<8;j++)
855 			if(~tmp[i] & (1 << j)) cfree++;
856 	*cfreep = cfree;
857 
858     out:
859 	free(tmp, M_TEMP);
860 	return(error);
861 }
862 
863 static int
864 ntfs_statfs(
865 	struct mount *mp,
866 	struct statfs *sbp,
867 	struct proc *p)
868 {
869 	struct ntfsmount *ntmp = VFSTONTFS(mp);
870 	u_int64_t mftallocated;
871 
872 	dprintf(("ntfs_statfs():\n"));
873 
874 	mftallocated = VTOF(ntmp->ntm_sysvn[NTFS_MFTINO])->f_allocated;
875 
876 #if defined(__FreeBSD__)
877 	sbp->f_type = mp->mnt_vfc->vfc_typenum;
878 #elif defined(__NetBSD__)
879 	sbp->f_type = 0;
880 #elif !defined(__OpenBSD__)
881 	sbp->f_type = MOUNT_NTFS;
882 #endif
883 	sbp->f_bsize = ntmp->ntm_bps;
884 	sbp->f_iosize = ntmp->ntm_bps * ntmp->ntm_spc;
885 	sbp->f_blocks = ntmp->ntm_bootfile.bf_spv;
886 	sbp->f_bfree = sbp->f_bavail = ntfs_cntobn(ntmp->ntm_cfree);
887 	sbp->f_ffree = sbp->f_bfree / ntmp->ntm_bpmftrec;
888 	sbp->f_files = mftallocated / ntfs_bntob(ntmp->ntm_bpmftrec) +
889 		       sbp->f_ffree;
890 	sbp->f_flags = mp->mnt_flag;
891 #if !defined(__OpenBSD__)
892 	copy_statfs_info(sbp, mp);
893 #else
894 	if (sbp != &mp->mnt_stat) {
895 		bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
896 		bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
897 		bcopy(&mp->mnt_stat.mount_info.msdosfs_args,
898 		    &sbp->mount_info.msdosfs_args, sizeof(struct msdosfs_args));
899 	}
900 	strncpy(sbp->f_fstypename, mp->mnt_vfc->vfc_name, MFSNAMELEN);
901 #endif
902 	return (0);
903 }
904 
905 static int
906 ntfs_sync (
907 	struct mount *mp,
908 	int waitfor,
909 	struct ucred *cred,
910 	struct proc *p)
911 {
912 	/*dprintf(("ntfs_sync():\n"));*/
913 	return (0);
914 }
915 
916 /*ARGSUSED*/
917 static int
918 ntfs_fhtovp(
919 #if defined(__FreeBSD__)
920 	struct mount *mp,
921 	struct fid *fhp,
922 	struct sockaddr *nam,
923 	struct vnode **vpp,
924 	int *exflagsp,
925 	struct ucred **credanonp)
926 #elif defined(__NetBSD__) || defined(__OpenBSD__)
927 	struct mount *mp,
928 	struct fid *fhp,
929 	struct vnode **vpp)
930 #else
931 	struct mount *mp,
932 	struct fid *fhp,
933 	struct mbuf *nam,
934 	struct vnode **vpp,
935 	int *exflagsp,
936 	struct ucred **credanonp)
937 #endif
938 {
939 	struct ntfid *ntfhp = (struct ntfid *)fhp;
940 	int error;
941 
942 	ddprintf(("ntfs_fhtovp(): %s: %d\n", mp->mnt_stat.f_mntonname,
943 		ntfhp->ntfid_ino));
944 
945 	error = ntfs_vgetex(mp, ntfhp->ntfid_ino, ntfhp->ntfid_attr, NULL,
946 			LK_EXCLUSIVE | LK_RETRY, 0, curproc, vpp); /* XXX */
947 	if (error != 0) {
948 		*vpp = NULLVP;
949 		return (error);
950 	}
951 
952 	/* XXX as unlink/rmdir/mkdir/creat are not currently possible
953 	 * with NTFS, we don't need to check anything else for now */
954 	return (0);
955 }
956 
957 static int
958 ntfs_vptofh(
959 	struct vnode *vp,
960 	struct fid *fhp)
961 {
962 	struct ntnode *ntp;
963 	struct ntfid *ntfhp;
964 	struct fnode *fn;
965 
966 	ddprintf(("ntfs_fhtovp(): %s: %p\n", vp->v_mount->mnt_stat.f_mntonname,
967 		vp));
968 
969 	fn = VTOF(vp);
970 	ntp = VTONT(vp);
971 	ntfhp = (struct ntfid *)fhp;
972 	ntfhp->ntfid_len = sizeof(struct ntfid);
973 	ntfhp->ntfid_ino = ntp->i_number;
974 	ntfhp->ntfid_attr = fn->f_attrtype;
975 #ifdef notyet
976 	ntfhp->ntfid_gen = ntp->i_gen;
977 #endif
978 	return (0);
979 }
980 
981 int
982 ntfs_vgetex(
983 	struct mount *mp,
984 	ino_t ino,
985 	u_int32_t attrtype,
986 	char *attrname,
987 	u_long lkflags,
988 	u_long flags,
989 	struct proc *p,
990 	struct vnode **vpp)
991 {
992 	int error;
993 	struct ntfsmount *ntmp;
994 	struct ntnode *ip;
995 	struct fnode *fp;
996 	struct vnode *vp;
997 	enum vtype f_type;
998 
999 	dprintf(("ntfs_vgetex: ino: %d, attr: 0x%x:%s, lkf: 0x%lx, f: 0x%lx\n",
1000 		ino, attrtype, attrname?attrname:"", (u_long)lkflags,
1001 		(u_long)flags ));
1002 
1003 	ntmp = VFSTONTFS(mp);
1004 	*vpp = NULL;
1005 
1006 	/* Get ntnode */
1007 #ifndef __OpenBSD__
1008 	error = ntfs_ntlookup(ntmp, ino, &ip);
1009 #else
1010 	error = ntfs_ntlookup(ntmp, ino, &ip, p);
1011 #endif
1012 	if (error) {
1013 		printf("ntfs_vget: ntfs_ntget failed\n");
1014 		return (error);
1015 	}
1016 
1017 	/* It may be not initialized fully, so force load it */
1018 	if (!(flags & VG_DONTLOADIN) && !(ip->i_flag & IN_LOADED)) {
1019 		error = ntfs_loadntnode(ntmp, ip);
1020 		if(error) {
1021 			printf("ntfs_vget: CAN'T LOAD ATTRIBUTES FOR INO: %d\n",
1022 			       ip->i_number);
1023 #ifndef __OpenBSD__
1024 			ntfs_ntput(ip);
1025 #else
1026 			ntfs_ntput(ip, p);
1027 #endif
1028 			return (error);
1029 		}
1030 	}
1031 
1032 	error = ntfs_fget(ntmp, ip, attrtype, attrname, &fp);
1033 	if (error) {
1034 		printf("ntfs_vget: ntfs_fget failed\n");
1035 #ifndef __OpenBSD__
1036 		ntfs_ntput(ip);
1037 #else
1038 		ntfs_ntput(ip, p);
1039 #endif
1040 		return (error);
1041 	}
1042 
1043 	if (!(flags & VG_DONTVALIDFN) && !(fp->f_flag & FN_VALID)) {
1044 		if ((ip->i_frflag & NTFS_FRFLAG_DIR) &&
1045 		    (fp->f_attrtype == NTFS_A_DATA && fp->f_attrname == NULL)) {
1046 			f_type = VDIR;
1047 		} else if (flags & VG_EXT) {
1048 			f_type = VNON;
1049 			fp->f_size = fp->f_allocated = 0;
1050 		} else {
1051 			f_type = VREG;
1052 
1053 			error = ntfs_filesize(ntmp, fp,
1054 					      &fp->f_size, &fp->f_allocated);
1055 			if (error) {
1056 #ifndef __OpenBSD__
1057 				ntfs_ntput(ip);
1058 #else
1059 				ntfs_ntput(ip, p);
1060 #endif
1061 				return (error);
1062 			}
1063 		}
1064 
1065 		fp->f_flag |= FN_VALID;
1066 	}
1067 
1068 	/*
1069 	 * We may be calling vget() now. To avoid potential deadlock, we need
1070 	 * to release ntnode lock, since due to locking order vnode
1071 	 * lock has to be acquired first.
1072 	 * ntfs_fget() bumped ntnode usecount, so ntnode won't be recycled
1073 	 * prematurely.
1074 	 */
1075 #ifndef __OpenBSD__
1076 	ntfs_ntput(ip);
1077 #else
1078 	ntfs_ntput(ip, p);
1079 #endif
1080 
1081 	if (FTOV(fp)) {
1082 		/* vget() returns error if the vnode has been recycled */
1083 		if (VGET(FTOV(fp), lkflags, p) == 0) {
1084 			*vpp = FTOV(fp);
1085 			return (0);
1086 		}
1087 	}
1088 
1089 	error = getnewvnode(VT_NTFS, ntmp->ntm_mountp, ntfs_vnodeop_p, &vp);
1090 	if(error) {
1091 		ntfs_frele(fp);
1092 #ifndef __OpenBSD__
1093 		ntfs_ntput(ip);
1094 #else
1095 		ntfs_ntput(ip, p);
1096 #endif
1097 		return (error);
1098 	}
1099 	dprintf(("ntfs_vget: vnode: %p for ntnode: %d\n", vp,ino));
1100 
1101 #ifdef __FreeBSD__
1102 	lockinit(&fp->f_lock, PINOD, "fnode", 0, 0);
1103 #endif
1104 	fp->f_vp = vp;
1105 	vp->v_data = fp;
1106 	vp->v_type = f_type;
1107 
1108 	if (ino == NTFS_ROOTINO)
1109 		vp->v_flag |= VROOT;
1110 
1111 	if (lkflags & LK_TYPE_MASK) {
1112 		error = VN_LOCK(vp, lkflags, p);
1113 		if (error) {
1114 			vput(vp);
1115 			return (error);
1116 		}
1117 	}
1118 
1119 #if defined(__FreeBSD__) || defined(__NetBSD__)
1120 	genfs_node_init(vp, &ntfs_genfsops);
1121 #endif
1122 	*vpp = vp;
1123 	return (0);
1124 }
1125 
1126 static int
1127 ntfs_vget(
1128 	struct mount *mp,
1129 	ino_t ino,
1130 	struct vnode **vpp)
1131 {
1132 	return ntfs_vgetex(mp, ino, NTFS_A_DATA, NULL,
1133 			LK_EXCLUSIVE | LK_RETRY, 0, curproc, vpp); /* XXX */
1134 }
1135 
1136 #if defined(__FreeBSD__)
1137 static struct vfsops ntfs_vfsops = {
1138 	ntfs_mount,
1139 	ntfs_start,
1140 	ntfs_unmount,
1141 	ntfs_root,
1142 	ntfs_quotactl,
1143 	ntfs_statfs,
1144 	ntfs_sync,
1145 	ntfs_vget,
1146 	ntfs_fhtovp,
1147 	ntfs_vptofh,
1148 	ntfs_init,
1149 	NULL
1150 };
1151 VFS_SET(ntfs_vfsops, ntfs, 0);
1152 #elif defined(__NetBSD__)
1153 extern const struct vnodeopv_desc ntfs_vnodeop_opv_desc;
1154 
1155 const struct vnodeopv_desc * const ntfs_vnodeopv_descs[] = {
1156 	&ntfs_vnodeop_opv_desc,
1157 	NULL,
1158 };
1159 
1160 struct vfsops ntfs_vfsops = {
1161 	MOUNT_NTFS,
1162 	ntfs_mount,
1163 	ntfs_start,
1164 	ntfs_unmount,
1165 	ntfs_root,
1166 	ntfs_quotactl,
1167 	ntfs_statfs,
1168 	ntfs_sync,
1169 	ntfs_vget,
1170 	ntfs_fhtovp,
1171 	ntfs_vptofh,
1172 	ntfs_init,
1173 	ntfs_reinit,
1174 	ntfs_done,
1175 	ntfs_sysctl,
1176 	ntfs_mountroot,
1177 	ntfs_checkexp,
1178 	ntfs_vnodeopv_descs,
1179 };
1180 #elif defined(__OpenBSD__)
1181 extern const struct vnodeopv_desc ntfs_vnodeop_opv_desc;
1182 
1183 const struct vnodeopv_desc * const ntfs_vnodeopv_descs[] = {
1184 	&ntfs_vnodeop_opv_desc,
1185 	NULL,
1186 };
1187 
1188 const struct vfsops ntfs_vfsops = {
1189 	ntfs_mount,
1190 	ntfs_start,
1191 	ntfs_unmount,
1192 	ntfs_root,
1193 	ntfs_quotactl,
1194 	ntfs_statfs,
1195 	ntfs_sync,
1196 	ntfs_vget,
1197 	ntfs_fhtovp,
1198 	ntfs_vptofh,
1199 	ntfs_init,
1200 	ntfs_sysctl,
1201 	ntfs_checkexp,
1202 };
1203 
1204 #endif
1205