2 * Copyright (c) 1998, 1999 Semen Ustimenko
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * $Id: ntfs_vfsops.c,v 1.9 1999/02/02 01:54:54 semen Exp $
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/namei.h>
35 #include <sys/kernel.h>
36 #include <sys/vnode.h>
37 #include <sys/mount.h>
39 #include <sys/fcntl.h>
40 #include <sys/malloc.h>
43 #include <vm/vm_param.h>
44 #include <vm/vm_prot.h>
45 #include <vm/vm_page.h>
46 #include <vm/vm_object.h>
47 #include <vm/vm_extern.h>
49 #include <miscfs/specfs/specdev.h>
51 /*#define NTFS_DEBUG 1*/
52 #include <ntfs/ntfs.h>
53 #include <ntfs/ntfs_inode.h>
54 #include <ntfs/ntfs_subr.h>
55 #include <ntfs/ntfs_extern.h>
56 #include <ntfs/ntfsmount.h>
58 #if __FreeBSD_version >= 300000
59 MALLOC_DEFINE(M_NTFSMNT, "NTFS mount", "NTFS mount structure");
60 MALLOC_DEFINE(M_NTFSNODE,"NTFS node", "NTFS node information");
61 MALLOC_DEFINE(M_NTFSDIR,"NTFS dir", "NTFS dir buffer");
64 static int ntfs_mount __P((struct mount *, char *, caddr_t,
65 struct nameidata *, struct proc *));
66 static int ntfs_quotactl __P((struct mount *, int, uid_t, caddr_t,
68 static int ntfs_root __P((struct mount *, struct vnode **));
69 static int ntfs_start __P((struct mount *, int, struct proc *));
70 static int ntfs_statfs __P((struct mount *, struct statfs *,
72 static int ntfs_sync __P((struct mount *, int, struct ucred *,
74 static int ntfs_unmount __P((struct mount *, int, struct proc *));
75 static int ntfs_vget __P((struct mount *mp, ino_t ino,
77 static int ntfs_mountfs __P((register struct vnode *, struct mount *,
78 struct ntfs_args *, struct proc *));
79 static int ntfs_vptofh __P((struct vnode *, struct fid *));
81 #if __FreeBSD_version >= 300000
82 static int ntfs_init __P((struct vfsconf *));
83 static int ntfs_fhtovp __P((struct mount *, struct fid *,
84 struct sockaddr *, struct vnode **,
85 int *, struct ucred **));
87 static int ntfs_init __P((void));
88 static int ntfs_fhtovp __P((struct mount *, struct fid *,
89 struct mbuf *, struct vnode **,
90 int *, struct ucred **));
93 #if __FreeBSD_version >= 300000
104 if(!first) return (0);
107 printf("ntfs_init(): \n");
119 struct nameidata *ndp,
125 struct ntfs_args args;
128 * Use NULL path to flag a root mount
133 * Mounting root file system
137 /* Get vnode for root device*/
138 if( bdevvp( rootdev, &rootvp))
139 panic("ffs_mountroot: can't setup bdevvp for root");
142 * FS specific handling
144 mp->mnt_flag |= MNT_RDONLY; /* XXX globally applicable?*/
149 if( ( err = ntfs_mountfs(rootvp, mp, &args, p)) != 0) {
150 /* fs specific cleanup (if any)*/
154 goto dostatfs; /* success*/
160 * Mounting non-root file system or updating a file system
164 /* copy in user arguments*/
165 err = copyin(data, (caddr_t)&args, sizeof (struct ntfs_args));
167 goto error_1; /* can't get arguments*/
170 * If updating, check whether changing from read-only to
171 * read/write; if there is no device name, that's all we do.
173 if (mp->mnt_flag & MNT_UPDATE) {
174 printf("ntfs_mount(): MNT_UPDATE not supported\n");
182 if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
184 if (mp->mnt_flag & MNT_FORCE)
190 err = ffs_flushfiles(mp, flags, p);
193 if (!err && (mp->mnt_flag & MNT_RELOAD))
194 err = ffs_reload(mp, ndp->ni_cnd.cn_cred, p);
198 if (fs->fs_ronly && (mp->mnt_flag & MNT_WANTRDWR)) {
200 if (mp->mnt_flag & MNT_FORCE) {
201 printf("WARNING: %s was not properly dismounted.\n",fs->fs_fsmnt);
203 printf("WARNING: R/W mount of %s denied. Filesystem is not clean - run fsck.\n",
211 if (fs->fs_ronly == 0) {
213 ffs_sbupdate(ump, MNT_WAIT);
215 /* if not updating name...*/
216 if (args.fspec == 0) {
218 * Process export requests. Jumping to "success"
219 * will return the vfs_export() error code.
221 err = vfs_export(mp, &ump->um_export, &args.export);
228 * Not an update, or updating the name: look up the name
229 * and verify that it refers to a sensible block device.
231 NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
234 /* can't get devvp!*/
240 if (devvp->v_type != VBLK) {
244 if (major(devvp->v_rdev) >= nblkdev) {
248 if (mp->mnt_flag & MNT_UPDATE) {
256 if (devvp != ntmp->um_devvp)
257 err = EINVAL; /* needs translation */
261 * Update device name only on success
264 /* Save "mounted from" info for mount point (NULL pad)*/
265 copyinstr( args.fspec,
266 mp->mnt_stat.f_mntfromname,
269 bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
280 * Since this is a new mount, we want the names for
281 * the device and the mount point copied in. If an
282 * error occurs, the mountpoint is discarded by the
285 /* Save "last mounted on" info for mount point (NULL pad)*/
286 copyinstr( path, /* mount point*/
287 mp->mnt_stat.f_mntonname, /* save area*/
288 MNAMELEN - 1, /* max size*/
289 &size); /* real size*/
290 bzero( mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
292 /* Save "mounted from" info for mount point (NULL pad)*/
293 copyinstr( args.fspec, /* device name*/
294 mp->mnt_stat.f_mntfromname, /* save area*/
295 MNAMELEN - 1, /* max size*/
296 &size); /* real size*/
297 bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
299 err = ntfs_mountfs(devvp, mp, &args, p);
307 * Initialize FS stat information in mount struct; uses both
308 * mp->mnt_stat.f_mntonname and mp->mnt_stat.f_mntfromname
310 * This code is common to root and non-root mounts
312 (void)VFS_STATFS(mp, &mp->mnt_stat, p);
317 error_2: /* error with devvp held*/
319 /* release devvp before failing*/
322 error_1: /* no state to back out*/
329 * Common code for mount and mountroot
332 ntfs_mountfs(devvp, mp, argsp, p)
333 register struct vnode *devvp;
335 struct ntfs_args *argsp;
339 struct ntfsmount *ntmp;
340 dev_t dev = devvp->v_rdev;
341 int error, ronly, ncount, i;
345 * Disallow multiple mounts of the same device.
346 * Disallow mounting of a device that is currently in use
347 * (except for root, which might share swap device for miniroot).
348 * Flush out any old buffers remaining from a previous use.
350 error = vfs_mountedon(devvp);
353 ncount = vcount(devvp);
356 if (ncount > 1 && devvp != rootvp)
358 #if __FreeBSD_version >= 300000
359 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
360 error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0);
361 VOP_UNLOCK(devvp, 0, p);
363 error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0);
368 ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
369 error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p);
375 error = bread(devvp, BBLOCK, BBSIZE, NOCRED, &bp);
378 ntmp = malloc( sizeof *ntmp, M_NTFSMNT, M_WAITOK );
379 bzero( ntmp, sizeof *ntmp );
380 bcopy( bp->b_data, &ntmp->ntm_bootfile, sizeof(struct bootfile) );
385 int8_t cpr = ntmp->ntm_mftrecsz;
387 ntmp->ntm_bpmftrec = ntmp->ntm_spc * cpr;
389 ntmp->ntm_bpmftrec = (1 << (-cpr)) / ntmp->ntm_bps;
391 printf("ntfs_mountfs(): bps: %d, spc: %d, media: %x, mftrecsz: %d (%d sects)\n",
392 ntmp->ntm_bps,ntmp->ntm_spc,ntmp->ntm_bootfile.bf_media,
393 ntmp->ntm_mftrecsz,ntmp->ntm_bpmftrec);
394 printf("ntfs_mountfs(): mftcn: 0x%x|0x%x\n",
395 (u_int32_t)ntmp->ntm_mftcn,(u_int32_t)ntmp->ntm_mftmirrcn);
397 ntmp->ntm_mountp = mp;
399 ntmp->ntm_devvp = devvp;
400 ntmp->ntm_uid = argsp->uid;
401 ntmp->ntm_gid = argsp->gid;
402 ntmp->ntm_mode = argsp->mode;
403 ntmp->ntm_flag = argsp->flag;
404 mp->mnt_data = (qaddr_t)ntmp;
406 printf("ntfs_mountfs(): case-%s,%s uid: %d, gid: %d, mode: %o\n",
407 (ntmp->ntm_flag & NTFS_MFLAG_CASEINS)?"insens.":"sens.",
408 (ntmp->ntm_flag & NTFS_MFLAG_ALLNAMES)?" allnames,":"",
409 ntmp->ntm_uid, ntmp->ntm_gid, ntmp->ntm_mode);
411 printf("ntfs_mountfs(): reading system nodes...\n");
414 error = VFS_VGET(mp, i, &ntmp->ntm_sysvn[i]);
417 VREF(ntmp->ntm_sysvn[i]);
418 vput(ntmp->ntm_sysvn[i]);
421 MALLOC( ntmp->ntm_upcase, wchar *, 65536 * sizeof(wchar),
422 M_NTFSMNT, M_WAITOK);
424 printf("ntfs_mountfs(): opening $UpCase\n");
425 error = VFS_VGET(mp, NTFS_UPCASEINO, &vp );
428 printf("ntfs_mountfs(): reading $UpCase\n");
429 error = ntfs_breadattr( ntmp, VTONT(vp), NTFS_A_DATA, NULL,
430 0, 65536*sizeof(wchar), ntmp->ntm_upcase);
431 printf("ntfs_mountfs(): closing $UpCase\n");
440 printf("ntfs_mountfs(): opening $AttrDef\n");
441 error = VFS_VGET(mp, NTFS_ATTRDEFINO, &vp );
446 error = ntfs_breadattr(ntmp, VTONT(vp),
448 num * sizeof(ad), sizeof(ad),
452 if (ad.ad_name[0] == 0)
455 printf("ntfs_mountfs(): reading %d attrdefs\n",num);
457 MALLOC(ntmp->ntm_ad, struct ntvattrdef *,
458 num * sizeof(struct ntvattrdef),
459 M_NTFSMNT, M_WAITOK);
461 ntmp->ntm_adnum = num;
464 error = ntfs_breadattr(ntmp, VTONT(vp),
466 i * sizeof(ad), sizeof(ad),
472 ntmp->ntm_ad[i].ad_name[j] = ad.ad_name[j];
473 } while(ad.ad_name[j++]);
474 ntmp->ntm_ad[i].ad_namelen = j - 1;
475 ntmp->ntm_ad[i].ad_type = ad.ad_type;
476 printf("ntfs_mountfs(): attribute: %s, type: 0x%x\n",
477 ntmp->ntm_ad[i].ad_name,
478 ntmp->ntm_ad[i].ad_type);
480 printf("ntfs_mountfs(): closing $AttrDef\n");
484 mp->mnt_stat.f_fsid.val[0] = (long)dev;
485 #if __FreeBSD_version >= 300000
486 mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
488 mp->mnt_stat.f_fsid.val[1] = MOUNT_NTFS;
490 mp->mnt_maxsymlinklen = 0;
491 mp->mnt_flag |= MNT_LOCAL;
492 #if __FreeBSD_version >= 300000
493 devvp->v_specmountpoint = mp;
495 devvp->v_specflags |= SI_MOUNTEDON;
499 for(i=0;i<NTFS_SYSNODESNUM;i++)
500 if(ntmp->ntm_sysvn[i]) vrele(ntmp->ntm_sysvn[i]);
502 #if __FreeBSD_version >= 300000
503 devvp->v_specmountpoint = NULL;
505 devvp->v_specflags |= SI_MOUNTEDON;
509 (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p);
519 printf("\nntfs_start():\n");
529 register struct ntfsmount *ntmp;
530 int error, ronly = 0, flags, i;
532 printf("ntfs_unmount: unmounting...\n");
533 ntmp = VFSTONTFS(mp);
536 if(mntflags & MNT_FORCE)
539 printf("ntfs_unmount: vflushing...\n");
540 for(i=0;i<NTFS_SYSNODESNUM;i++)
541 if(ntmp->ntm_sysvn[i]) vrele(ntmp->ntm_sysvn[i]);
542 error = vflush(mp,NULLVP,flags);
544 printf("ntfs_unmount: vflush failed: %d\n",error);
548 #if __FreeBSD_version >= 300000
549 ntmp->ntm_devvp->v_specmountpoint = NULL;
551 ntmp->ntm_devvp->v_specflags &= ~SI_MOUNTEDON;
553 VOP_LOCK(ntmp->ntm_devvp);
554 vnode_pager_uncache(ntmp->ntm_devvp);
555 VOP_UNLOCK(ntmp->ntm_devvp);
558 vinvalbuf(ntmp->ntm_devvp, V_SAVE, NOCRED, p, 0, 0);
559 error = VOP_CLOSE(ntmp->ntm_devvp, ronly ? FREAD : FREAD|FWRITE,
562 vrele(ntmp->ntm_devvp);
564 printf("ntfs_umount: freeing memory...\n");
565 mp->mnt_data = (qaddr_t)0;
566 mp->mnt_flag &= ~MNT_LOCAL;
567 FREE(ntmp->ntm_ad, M_NTFSMNT);
568 FREE(ntmp->ntm_upcase, M_NTFSMNT);
569 FREE(ntmp, M_NTFSMNT);
581 dprintf(("ntfs_root():\n"));
582 error = VFS_VGET(mp, (ino_t)NTFS_ROOTINO, &nvp);
584 printf("ntfs_root: VFS_VGET failed: %d\n",error);
600 printf("\nntfs_quotactl():\n");
610 struct ntfsmount *ntmp = VFSTONTFS(mp);
611 u_int64_t mftsize,mftallocated,bmsize,bmallocated;
616 dprintf(("ntfs_statfs():"));
618 ntfs_filesize(ntmp, VTONT(ntmp->ntm_sysvn[NTFS_MFTINO]),
619 &mftsize, &mftallocated);
621 error = VFS_VGET(mp, NTFS_BITMAPINO, &vp);
625 ntfs_filesize(ntmp, VTONT(vp), &bmsize, &bmallocated);
627 MALLOC(tmp, u_int8_t *, bmsize,M_TEMP, M_WAITOK);
629 error = ntfs_breadattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL,
639 for(i=0;i<bmsize;i++)
641 if(~tmp[i] & (1 << j)) sbp->f_bfree++;
645 #if __FreeBSD_version >= 300000
646 sbp->f_type = mp->mnt_vfc->vfc_typenum;
648 sbp->f_type = MOUNT_NTFS;
650 sbp->f_bsize = ntmp->ntm_bps;
651 sbp->f_iosize = ntmp->ntm_bps * ntmp->ntm_spc;
652 sbp->f_blocks = ntmp->ntm_bootfile.bf_spv;
653 sbp->f_bfree = sbp->f_bavail = ntfs_cntobn(sbp->f_bfree);
654 sbp->f_ffree = sbp->f_bfree / ntmp->ntm_bpmftrec;
655 sbp->f_files = mftallocated / ntfs_bntob(ntmp->ntm_bpmftrec) +
657 if (sbp != &mp->mnt_stat) {
658 bcopy((caddr_t)mp->mnt_stat.f_mntonname,
659 (caddr_t)&sbp->f_mntonname[0], MNAMELEN);
660 bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
661 (caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
674 /*dprintf(("ntfs_sync():\n"));*/
678 #if __FreeBSD_version >= 300000
683 struct sockaddr *nam,
686 struct ucred **credanonp)
695 struct ucred **credanonp)
698 printf("\ntfs_fhtovp():\n");
707 printf("ntfs_vptofh():\n");
719 register struct ntfsmount *ntmp;
722 dprintf(("ntfs_vget: ino: %d\n",ino));
724 ntmp = VFSTONTFS(mp);
728 dprintf(("ntfs_ntvget: ihashlookup\n"));
729 if( (*vpp = ntfs_ihashget(ntmp->ntm_dev, ino)) != NULL )
732 error = ntfs_ntget(ntmp,ino,&ip);
734 printf("ntfs_vget: ntfs_ntget failed\n");
738 error = getnewvnode(VT_NTFS, ntmp->ntm_mountp, ntfs_vnodeop_p, &vp);
746 vp->v_type = ip->i_type;
752 error = ntfs_loadnode(ntmp, ip);
754 printf("ntfs_vget: CAN'T LOAD ATTRIBUTES FOR INO: %d\n",
765 #if __FreeBSD_version >= 300000
766 static struct vfsops ntfs_vfsops = {
781 VFS_SET(ntfs_vfsops, ntfs, 0);
783 static struct vfsops ntfs_vfsops = {
797 VFS_SET(ntfs_vfsops, ntfs, MOUNT_NTFS, 0);