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_vfsops.h>
56 #include <ntfs/ntfs_ihash.h>
57 #include <ntfs/ntfs_extern.h>
58 #include <ntfs/ntfsmount.h>
60 #if __FreeBSD_version >= 300000
61 MALLOC_DEFINE(M_NTFSMNT, "NTFS mount", "NTFS mount structure");
62 MALLOC_DEFINE(M_NTFSNTNODE,"NTFS ntnode", "NTFS ntnode information");
63 MALLOC_DEFINE(M_NTFSFNODE,"NTFS fnode", "NTFS fnode information");
64 MALLOC_DEFINE(M_NTFSDIR,"NTFS dir", "NTFS dir buffer");
67 static int ntfs_mount __P((struct mount *, char *, caddr_t,
68 struct nameidata *, struct proc *));
69 static int ntfs_quotactl __P((struct mount *, int, uid_t, caddr_t,
71 static int ntfs_root __P((struct mount *, struct vnode **));
72 static int ntfs_start __P((struct mount *, int, struct proc *));
73 static int ntfs_statfs __P((struct mount *, struct statfs *,
75 static int ntfs_sync __P((struct mount *, int, struct ucred *,
77 static int ntfs_unmount __P((struct mount *, int, struct proc *));
78 static int ntfs_vget __P((struct mount *mp, ino_t ino,
80 static int ntfs_mountfs __P((register struct vnode *, struct mount *,
81 struct ntfs_args *, struct proc *));
82 static int ntfs_vptofh __P((struct vnode *, struct fid *));
84 #if __FreeBSD_version >= 300000
85 static int ntfs_init __P((struct vfsconf *));
86 static int ntfs_fhtovp __P((struct mount *, struct fid *,
87 struct sockaddr *, struct vnode **,
88 int *, struct ucred **));
90 static int ntfs_init __P((void));
91 static int ntfs_fhtovp __P((struct mount *, struct fid *,
92 struct mbuf *, struct vnode **,
93 int *, struct ucred **));
96 #if __FreeBSD_version >= 300000
107 if(!first) return (0);
110 printf("ntfs_init(): \n");
122 struct nameidata *ndp,
128 struct ntfs_args args;
131 * Use NULL path to flag a root mount
136 * Mounting root file system
140 /* Get vnode for root device*/
141 if( bdevvp( rootdev, &rootvp))
142 panic("ffs_mountroot: can't setup bdevvp for root");
145 * FS specific handling
147 mp->mnt_flag |= MNT_RDONLY; /* XXX globally applicable?*/
152 if( ( err = ntfs_mountfs(rootvp, mp, &args, p)) != 0) {
153 /* fs specific cleanup (if any)*/
157 goto dostatfs; /* success*/
163 * Mounting non-root file system or updating a file system
167 /* copy in user arguments*/
168 err = copyin(data, (caddr_t)&args, sizeof (struct ntfs_args));
170 goto error_1; /* can't get arguments*/
173 * If updating, check whether changing from read-only to
174 * read/write; if there is no device name, that's all we do.
176 if (mp->mnt_flag & MNT_UPDATE) {
177 printf("ntfs_mount(): MNT_UPDATE not supported\n");
185 if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) {
187 if (mp->mnt_flag & MNT_FORCE)
193 err = ffs_flushfiles(mp, flags, p);
196 if (!err && (mp->mnt_flag & MNT_RELOAD))
197 err = ffs_reload(mp, ndp->ni_cnd.cn_cred, p);
201 if (fs->fs_ronly && (mp->mnt_flag & MNT_WANTRDWR)) {
203 if (mp->mnt_flag & MNT_FORCE) {
204 printf("WARNING: %s was not properly dismounted.\n",fs->fs_fsmnt);
206 printf("WARNING: R/W mount of %s denied. Filesystem is not clean - run fsck.\n",
214 if (fs->fs_ronly == 0) {
216 ffs_sbupdate(ump, MNT_WAIT);
218 /* if not updating name...*/
219 if (args.fspec == 0) {
221 * Process export requests. Jumping to "success"
222 * will return the vfs_export() error code.
224 err = vfs_export(mp, &ump->um_export, &args.export);
231 * Not an update, or updating the name: look up the name
232 * and verify that it refers to a sensible block device.
234 NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
237 /* can't get devvp!*/
243 if (devvp->v_type != VBLK) {
247 if (major(devvp->v_rdev) >= nblkdev) {
251 if (mp->mnt_flag & MNT_UPDATE) {
259 if (devvp != ntmp->um_devvp)
260 err = EINVAL; /* needs translation */
264 * Update device name only on success
267 /* Save "mounted from" info for mount point (NULL pad)*/
268 copyinstr( args.fspec,
269 mp->mnt_stat.f_mntfromname,
272 bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
283 * Since this is a new mount, we want the names for
284 * the device and the mount point copied in. If an
285 * error occurs, the mountpoint is discarded by the
288 /* Save "last mounted on" info for mount point (NULL pad)*/
289 copyinstr( path, /* mount point*/
290 mp->mnt_stat.f_mntonname, /* save area*/
291 MNAMELEN - 1, /* max size*/
292 &size); /* real size*/
293 bzero( mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
295 /* Save "mounted from" info for mount point (NULL pad)*/
296 copyinstr( args.fspec, /* device name*/
297 mp->mnt_stat.f_mntfromname, /* save area*/
298 MNAMELEN - 1, /* max size*/
299 &size); /* real size*/
300 bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
302 err = ntfs_mountfs(devvp, mp, &args, p);
310 * Initialize FS stat information in mount struct; uses both
311 * mp->mnt_stat.f_mntonname and mp->mnt_stat.f_mntfromname
313 * This code is common to root and non-root mounts
315 (void)VFS_STATFS(mp, &mp->mnt_stat, p);
320 error_2: /* error with devvp held*/
322 /* release devvp before failing*/
325 error_1: /* no state to back out*/
332 * Common code for mount and mountroot
335 ntfs_mountfs(devvp, mp, argsp, p)
336 register struct vnode *devvp;
338 struct ntfs_args *argsp;
342 struct ntfsmount *ntmp;
343 dev_t dev = devvp->v_rdev;
344 int error, ronly, ncount, i;
348 * Disallow multiple mounts of the same device.
349 * Disallow mounting of a device that is currently in use
350 * (except for root, which might share swap device for miniroot).
351 * Flush out any old buffers remaining from a previous use.
353 error = vfs_mountedon(devvp);
356 ncount = vcount(devvp);
359 if (ncount > 1 && devvp != rootvp)
361 #if __FreeBSD_version >= 300000
362 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
363 error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0);
364 VOP_UNLOCK(devvp, 0, p);
366 error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0);
371 ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
372 error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p);
378 error = bread(devvp, BBLOCK, BBSIZE, NOCRED, &bp);
381 ntmp = malloc( sizeof *ntmp, M_NTFSMNT, M_WAITOK );
382 bzero( ntmp, sizeof *ntmp );
383 bcopy( bp->b_data, &ntmp->ntm_bootfile, sizeof(struct bootfile) );
388 int8_t cpr = ntmp->ntm_mftrecsz;
390 ntmp->ntm_bpmftrec = ntmp->ntm_spc * cpr;
392 ntmp->ntm_bpmftrec = (1 << (-cpr)) / ntmp->ntm_bps;
394 printf("ntfs_mountfs(): bps: %d, spc: %d, media: %x, mftrecsz: %d (%d sects)\n",
395 ntmp->ntm_bps,ntmp->ntm_spc,ntmp->ntm_bootfile.bf_media,
396 ntmp->ntm_mftrecsz,ntmp->ntm_bpmftrec);
397 printf("ntfs_mountfs(): mftcn: 0x%x|0x%x\n",
398 (u_int32_t)ntmp->ntm_mftcn,(u_int32_t)ntmp->ntm_mftmirrcn);
400 ntmp->ntm_mountp = mp;
402 ntmp->ntm_devvp = devvp;
403 ntmp->ntm_uid = argsp->uid;
404 ntmp->ntm_gid = argsp->gid;
405 ntmp->ntm_mode = argsp->mode;
406 ntmp->ntm_flag = argsp->flag;
407 mp->mnt_data = (qaddr_t)ntmp;
409 printf("ntfs_mountfs(): case-%s,%s uid: %d, gid: %d, mode: %o\n",
410 (ntmp->ntm_flag & NTFS_MFLAG_CASEINS)?"insens.":"sens.",
411 (ntmp->ntm_flag & NTFS_MFLAG_ALLNAMES)?" allnames,":"",
412 ntmp->ntm_uid, ntmp->ntm_gid, ntmp->ntm_mode);
414 printf("ntfs_mountfs(): reading system nodes...\n");
417 error = VFS_VGET(mp, i, &(ntmp->ntm_sysvn[i]));
420 VREF(ntmp->ntm_sysvn[i]);
421 vput(ntmp->ntm_sysvn[i]);
423 error = VFS_VGET(mp, i, &(ntmp->ntm_sysvn[i]));
426 VREF(ntmp->ntm_sysvn[i]);
427 vput(ntmp->ntm_sysvn[i]);
430 MALLOC( ntmp->ntm_upcase, wchar *, 65536 * sizeof(wchar),
431 M_NTFSMNT, M_WAITOK);
433 printf("ntfs_mountfs(): opening $UpCase\n");
434 error = VFS_VGET(mp, NTFS_UPCASEINO, &vp );
437 printf("ntfs_mountfs(): reading $UpCase\n");
438 error = ntfs_readattr( ntmp, VTONT(vp), NTFS_A_DATA, NULL,
439 0, 65536*sizeof(wchar), ntmp->ntm_upcase);
440 printf("ntfs_mountfs(): closing $UpCase\n");
449 printf("ntfs_mountfs(): opening $AttrDef\n");
450 error = VFS_VGET(mp, NTFS_ATTRDEFINO, &vp );
455 error = ntfs_readattr(ntmp, VTONT(vp),
457 num * sizeof(ad), sizeof(ad),
461 if (ad.ad_name[0] == 0)
464 printf("ntfs_mountfs(): reading %d attrdefs\n",num);
466 MALLOC(ntmp->ntm_ad, struct ntvattrdef *,
467 num * sizeof(struct ntvattrdef),
468 M_NTFSMNT, M_WAITOK);
470 ntmp->ntm_adnum = num;
473 error = ntfs_readattr(ntmp, VTONT(vp),
475 i * sizeof(ad), sizeof(ad),
481 ntmp->ntm_ad[i].ad_name[j] = ad.ad_name[j];
482 } while(ad.ad_name[j++]);
483 ntmp->ntm_ad[i].ad_namelen = j - 1;
484 ntmp->ntm_ad[i].ad_type = ad.ad_type;
485 printf("ntfs_mountfs(): attribute: %s, type: 0x%x\n",
486 ntmp->ntm_ad[i].ad_name,
487 ntmp->ntm_ad[i].ad_type);
489 printf("ntfs_mountfs(): closing $AttrDef\n");
493 mp->mnt_stat.f_fsid.val[0] = (long)dev;
494 #if __FreeBSD_version >= 300000
495 mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
497 mp->mnt_stat.f_fsid.val[1] = MOUNT_NTFS;
499 mp->mnt_maxsymlinklen = 0;
500 mp->mnt_flag |= MNT_LOCAL;
501 #if __FreeBSD_version >= 300000
502 devvp->v_specmountpoint = mp;
504 devvp->v_specflags |= SI_MOUNTEDON;
508 for(i=0;i<NTFS_SYSNODESNUM;i++)
509 if(ntmp->ntm_sysvn[i]) vrele(ntmp->ntm_sysvn[i]);
511 #if __FreeBSD_version >= 300000
512 devvp->v_specmountpoint = NULL;
514 devvp->v_specflags |= SI_MOUNTEDON;
518 (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p);
528 printf("\nntfs_start():\n");
538 register struct ntfsmount *ntmp;
539 int error, ronly = 0, flags, i;
541 printf("ntfs_unmount: unmounting...\n");
542 ntmp = VFSTONTFS(mp);
545 if(mntflags & MNT_FORCE)
548 printf("ntfs_unmount: vflushing...\n");
549 error = vflush(mp,NULLVP,flags | SKIPSYSTEM);
551 printf("ntfs_unmount: vflush failed: %d\n",error);
554 for(i=0;i<NTFS_SYSNODESNUM;i++)
555 if(ntmp->ntm_sysvn[i]) vrele(ntmp->ntm_sysvn[i]);
556 error = vflush(mp,NULLVP,flags);
558 printf("ntfs_unmount: vflush failed: %d\n",error);
560 #if __FreeBSD_version >= 300000
561 ntmp->ntm_devvp->v_specmountpoint = NULL;
563 ntmp->ntm_devvp->v_specflags &= ~SI_MOUNTEDON;
565 VOP_LOCK(ntmp->ntm_devvp);
566 vnode_pager_uncache(ntmp->ntm_devvp);
567 VOP_UNLOCK(ntmp->ntm_devvp);
570 vinvalbuf(ntmp->ntm_devvp, V_SAVE, NOCRED, p, 0, 0);
571 error = VOP_CLOSE(ntmp->ntm_devvp, ronly ? FREAD : FREAD|FWRITE,
574 vrele(ntmp->ntm_devvp);
576 printf("ntfs_umount: freeing memory...\n");
577 mp->mnt_data = (qaddr_t)0;
578 mp->mnt_flag &= ~MNT_LOCAL;
579 FREE(ntmp->ntm_ad, M_NTFSMNT);
580 FREE(ntmp->ntm_upcase, M_NTFSMNT);
581 FREE(ntmp, M_NTFSMNT);
593 dprintf(("ntfs_root(): sysvn: %p\n",
594 VFSTONTFS(mp)->ntm_sysvn[NTFS_ROOTINO]));
595 error = VFS_VGET(mp, (ino_t)NTFS_ROOTINO, &nvp);
597 printf("ntfs_root: VFS_VGET failed: %d\n",error);
613 printf("\nntfs_quotactl():\n");
623 struct ntfsmount *ntmp = VFSTONTFS(mp);
624 u_int64_t mftsize,mftallocated,bmsize,bmallocated;
629 dprintf(("ntfs_statfs():"));
631 ntfs_filesize(ntmp, VTOF(ntmp->ntm_sysvn[NTFS_MFTINO]),
632 &mftsize, &mftallocated);
634 error = VFS_VGET(mp, NTFS_BITMAPINO, &vp);
638 ntfs_filesize(ntmp, VTOF(vp), &bmsize, &bmallocated);
640 MALLOC(tmp, u_int8_t *, bmsize,M_TEMP, M_WAITOK);
642 error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL,
652 for(i=0;i<bmsize;i++)
654 if(~tmp[i] & (1 << j)) sbp->f_bfree++;
658 #if __FreeBSD_version >= 300000
659 sbp->f_type = mp->mnt_vfc->vfc_typenum;
661 sbp->f_type = MOUNT_NTFS;
663 sbp->f_bsize = ntmp->ntm_bps;
664 sbp->f_iosize = ntmp->ntm_bps * ntmp->ntm_spc;
665 sbp->f_blocks = ntmp->ntm_bootfile.bf_spv;
666 sbp->f_bfree = sbp->f_bavail = ntfs_cntobn(sbp->f_bfree);
667 sbp->f_ffree = sbp->f_bfree / ntmp->ntm_bpmftrec;
668 sbp->f_files = mftallocated / ntfs_bntob(ntmp->ntm_bpmftrec) +
670 if (sbp != &mp->mnt_stat) {
671 bcopy((caddr_t)mp->mnt_stat.f_mntonname,
672 (caddr_t)&sbp->f_mntonname[0], MNAMELEN);
673 bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
674 (caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
676 sbp->f_flags = mp->mnt_flag;
688 /*dprintf(("ntfs_sync():\n"));*/
692 #if __FreeBSD_version >= 300000
697 struct sockaddr *nam,
700 struct ucred **credanonp)
709 struct ucred **credanonp)
712 printf("\ntfs_fhtovp():\n");
721 printf("ntfs_vptofh():\n");
737 register struct ntfsmount *ntmp;
742 dprintf(("ntfs_vgetex: ino: %d, attr: 0x%x:%s, lkf: 0x%x, f: 0x%x\n",
743 ino, attrtype, attrname?attrname:"", lkflags, flags ));
745 ntmp = VFSTONTFS(mp);
749 error = ntfs_ntget(ntmp, ino, &ip);
751 printf("ntfs_vget: ntfs_ntget failed\n");
755 error = ntfs_fget(ntmp, ip, attrtype, attrname, &fp);
757 printf("ntfs_vget: ntfs_fget failed\n");
763 vget(FTOV(fp), lkflags, p);
769 /* It may be not initialized fully, so force load it */
770 if (!(flags & VG_DONTLOAD) && !(ip->i_flag & IN_LOADED)) {
771 error = ntfs_loadntnode(ntmp, ip);
773 printf("ntfs_vget: CAN'T LOAD ATTRIBUTES FOR INO: %d\n",
780 error = getnewvnode(VT_NTFS, ntmp->ntm_mountp, ntfs_vnodeop_p, &vp);
786 dprintf(("ntfs_vget: vnode: %p for ntnode: %d\n", vp,ino));
788 lockinit(&fp->f_lock, PINOD, "fnode", 0, 0);
792 if (ip->i_frflag & NTFS_FRFLAG_DIR)
793 vp->v_type = fp->f_type = VDIR;
795 vp->v_type = fp->f_type = VREG;
797 if (ino == NTFS_ROOTINO)
799 if (ino < NTFS_SYSNODESNUM)
800 vp->v_flag |= VSYSTEM;
804 if (lkflags & LK_TYPE_MASK) {
805 error = vn_lock(vp, lkflags, p);
824 return ntfs_vgetex(mp, ino, NTFS_A_DATA, NULL,
825 LK_EXCLUSIVE, 0, curproc, vpp);
828 #if __FreeBSD_version >= 300000
829 static struct vfsops ntfs_vfsops = {
844 VFS_SET(ntfs_vfsops, ntfs, 0);
846 static struct vfsops ntfs_vfsops = {
860 VFS_SET(ntfs_vfsops, ntfs, MOUNT_NTFS, 0);