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