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