1*9593dc34Smglocker /* $OpenBSD: ntfs_vfsops.c,v 1.66 2024/09/04 07:54:53 mglocker Exp $ */ 226f3deacStedu /* $NetBSD: ntfs_vfsops.c,v 1.7 2003/04/24 07:50:19 christos Exp $ */ 326f3deacStedu 426f3deacStedu /*- 526f3deacStedu * Copyright (c) 1998, 1999 Semen Ustimenko 626f3deacStedu * All rights reserved. 726f3deacStedu * 826f3deacStedu * Redistribution and use in source and binary forms, with or without 926f3deacStedu * modification, are permitted provided that the following conditions 1026f3deacStedu * are met: 1126f3deacStedu * 1. Redistributions of source code must retain the above copyright 1226f3deacStedu * notice, this list of conditions and the following disclaimer. 1326f3deacStedu * 2. Redistributions in binary form must reproduce the above copyright 1426f3deacStedu * notice, this list of conditions and the following disclaimer in the 1526f3deacStedu * documentation and/or other materials provided with the distribution. 1626f3deacStedu * 1726f3deacStedu * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1826f3deacStedu * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1926f3deacStedu * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2026f3deacStedu * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2126f3deacStedu * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2226f3deacStedu * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2326f3deacStedu * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2426f3deacStedu * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2526f3deacStedu * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2626f3deacStedu * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2726f3deacStedu * SUCH DAMAGE. 2826f3deacStedu * 2926f3deacStedu * Id: ntfs_vfsops.c,v 1.7 1999/05/31 11:28:30 phk Exp 3026f3deacStedu */ 3126f3deacStedu 3226f3deacStedu #include <sys/param.h> 3326f3deacStedu #include <sys/systm.h> 3426f3deacStedu #include <sys/namei.h> 3526f3deacStedu #include <sys/proc.h> 3626f3deacStedu #include <sys/kernel.h> 3726f3deacStedu #include <sys/vnode.h> 380ae9dfeaStedu #include <sys/lock.h> 3926f3deacStedu #include <sys/mount.h> 4026f3deacStedu #include <sys/buf.h> 41ca666729Sjsing #include <sys/disk.h> 4226f3deacStedu #include <sys/fcntl.h> 4326f3deacStedu #include <sys/malloc.h> 4426f3deacStedu #include <sys/device.h> 4526f3deacStedu #include <sys/conf.h> 46544451c3Sderaadt #include <sys/specdev.h> 4726f3deacStedu 4826f3deacStedu /*#define NTFS_DEBUG 1*/ 4926f3deacStedu #include <ntfs/ntfs.h> 5026f3deacStedu #include <ntfs/ntfs_inode.h> 5126f3deacStedu #include <ntfs/ntfs_subr.h> 5226f3deacStedu #include <ntfs/ntfs_vfsops.h> 5326f3deacStedu #include <ntfs/ntfs_ihash.h> 5426f3deacStedu 5505c5dae5Sjsing int ntfs_mount(struct mount *, const char *, void *, 5690337d88Stedu struct nameidata *, struct proc *); 5705c5dae5Sjsing int ntfs_quotactl(struct mount *, int, uid_t, caddr_t, 5890337d88Stedu struct proc *); 5905c5dae5Sjsing int ntfs_root(struct mount *, struct vnode **); 6005c5dae5Sjsing int ntfs_start(struct mount *, int, struct proc *); 6105c5dae5Sjsing int ntfs_statfs(struct mount *, struct statfs *, 6290337d88Stedu struct proc *); 63976e9839Sderaadt int ntfs_sync(struct mount *, int, int, struct ucred *, 6490337d88Stedu struct proc *); 6505c5dae5Sjsing int ntfs_unmount(struct mount *, int, struct proc *); 6605c5dae5Sjsing int ntfs_vget(struct mount *mp, ino_t ino, 6790337d88Stedu struct vnode **vpp); 6805c5dae5Sjsing int ntfs_mountfs(struct vnode *, struct mount *, 6990337d88Stedu struct ntfs_args *, struct proc *); 7005c5dae5Sjsing int ntfs_vptofh(struct vnode *, struct fid *); 7126f3deacStedu 7205c5dae5Sjsing int ntfs_init(struct vfsconf *); 7305c5dae5Sjsing int ntfs_fhtovp(struct mount *, struct fid *, 7426f3deacStedu struct vnode **); 7505c5dae5Sjsing int ntfs_checkexp(struct mount *, struct mbuf *, 7626f3deacStedu int *, struct ucred **); 7705c5dae5Sjsing int ntfs_sysctl(int *, u_int, void *, size_t *, void *, 7826f3deacStedu size_t, struct proc *); 7926f3deacStedu 8026f3deacStedu /* 8126f3deacStedu * Verify a remote client has export rights and return these rights via. 8226f3deacStedu * exflagsp and credanonp. 8326f3deacStedu */ 8405c5dae5Sjsing int 851cc0505dSjsing ntfs_checkexp(struct mount *mp, struct mbuf *nam, int *exflagsp, 861cc0505dSjsing struct ucred **credanonp) 8726f3deacStedu { 8826f3deacStedu struct netcred *np; 8926f3deacStedu struct ntfsmount *ntm = VFSTONTFS(mp); 9026f3deacStedu 9126f3deacStedu /* 9226f3deacStedu * Get the export permission structure for this <mp, client> tuple. 9326f3deacStedu */ 9426f3deacStedu np = vfs_export_lookup(mp, &ntm->ntm_export, nam); 9526f3deacStedu if (np == NULL) 9626f3deacStedu return (EACCES); 9726f3deacStedu 9826f3deacStedu *exflagsp = np->netc_exflags; 9926f3deacStedu *credanonp = &np->netc_anon; 10026f3deacStedu return (0); 10126f3deacStedu } 10226f3deacStedu 10305c5dae5Sjsing int 1041cc0505dSjsing ntfs_sysctl(int *name, u_int namelen, void *oldp, size_t *oldlenp, void *newp, 1051cc0505dSjsing size_t newlen, struct proc *p) 10626f3deacStedu { 10726f3deacStedu return (EINVAL); 10826f3deacStedu } 10926f3deacStedu 11005c5dae5Sjsing int 1111cc0505dSjsing ntfs_init(struct vfsconf *vcp) 11226f3deacStedu { 11326f3deacStedu return 0; 11426f3deacStedu } 11526f3deacStedu 11605c5dae5Sjsing int 1171cc0505dSjsing ntfs_mount(struct mount *mp, const char *path, void *data, 1181cc0505dSjsing struct nameidata *ndp, struct proc *p) 11926f3deacStedu { 12026f3deacStedu int err = 0; 12126f3deacStedu struct vnode *devvp; 1227efda1a1Sderaadt struct ntfs_args *args = data; 123aec3986eSjsing char fname[MNAMELEN]; 124a93bb724Sjsing char fspec[MNAMELEN]; 12526f3deacStedu 1262bbed251Stedu ntfs_nthashinit(); 1272bbed251Stedu 12826f3deacStedu /* 12926f3deacStedu *** 13026f3deacStedu * Mounting non-root file system or updating a file system 13126f3deacStedu *** 13226f3deacStedu */ 13326f3deacStedu 13426f3deacStedu /* 13526f3deacStedu * If updating, check whether changing from read-only to 13626f3deacStedu * read/write; if there is no device name, that's all we do. 13726f3deacStedu */ 13826f3deacStedu if (mp->mnt_flag & MNT_UPDATE) { 13926f3deacStedu /* if not updating name...*/ 1407efda1a1Sderaadt if (args && args->fspec == NULL) { 14126f3deacStedu /* 14226f3deacStedu * Process export requests. Jumping to "success" 14326f3deacStedu * will return the vfs_export() error code. 14426f3deacStedu */ 14526f3deacStedu struct ntfsmount *ntm = VFSTONTFS(mp); 1467efda1a1Sderaadt err = vfs_export(mp, &ntm->ntm_export, &args->export_info); 14726f3deacStedu goto success; 14826f3deacStedu } 14926f3deacStedu 15026f3deacStedu printf("ntfs_mount(): MNT_UPDATE not supported\n"); 15126f3deacStedu err = EINVAL; 15226f3deacStedu goto error_1; 15326f3deacStedu } 15426f3deacStedu 15526f3deacStedu /* 15626f3deacStedu * Not an update, or updating the name: look up the name 15726f3deacStedu * and verify that it refers to a sensible block device. 15826f3deacStedu */ 1597efda1a1Sderaadt err = copyinstr(args->fspec, fspec, sizeof(fspec), NULL); 160ca666729Sjsing if (err) 161ca666729Sjsing goto error_1; 162ca666729Sjsing 163aec3986eSjsing if (disk_map(fspec, fname, sizeof(fname), DM_OPENBLCK) == -1) 164aec3986eSjsing bcopy(fspec, fname, sizeof(fname)); 165aec3986eSjsing 166aec3986eSjsing NDINIT(ndp, LOOKUP, FOLLOW, UIO_SYSSPACE, fname, p); 16726f3deacStedu err = namei(ndp); 16826f3deacStedu if (err) { 16926f3deacStedu /* can't get devvp!*/ 17026f3deacStedu goto error_1; 17126f3deacStedu } 17226f3deacStedu 17326f3deacStedu devvp = ndp->ni_vp; 17426f3deacStedu 17526f3deacStedu if (devvp->v_type != VBLK) { 17626f3deacStedu err = ENOTBLK; 17726f3deacStedu goto error_2; 17826f3deacStedu } 179ca1018d5Spedro 18026f3deacStedu if (major(devvp->v_rdev) >= nblkdev) { 18126f3deacStedu err = ENXIO; 18226f3deacStedu goto error_2; 18326f3deacStedu } 184ca1018d5Spedro 18526f3deacStedu if (mp->mnt_flag & MNT_UPDATE) { 18626f3deacStedu #if 0 18726f3deacStedu /* 18826f3deacStedu ******************** 18926f3deacStedu * UPDATE 19026f3deacStedu ******************** 19126f3deacStedu */ 19226f3deacStedu 19326f3deacStedu if (devvp != ntmp->um_devvp) 19426f3deacStedu err = EINVAL; /* needs translation */ 19526f3deacStedu else 19626f3deacStedu vrele(devvp); 19726f3deacStedu /* 19826f3deacStedu * Update device name only on success 19926f3deacStedu */ 20026f3deacStedu if( !err) { 2017efda1a1Sderaadt err = set_statfs_info(NULL, UIO_USERSPACE, args->fspec, 20226f3deacStedu UIO_USERSPACE, mp, p); 20326f3deacStedu } 20426f3deacStedu #endif 20526f3deacStedu } else { 20626f3deacStedu /* 20726f3deacStedu ******************** 20826f3deacStedu * NEW MOUNT 20926f3deacStedu ******************** 21026f3deacStedu */ 21126f3deacStedu 21226f3deacStedu /* 21326f3deacStedu * Since this is a new mount, we want the names for 21426f3deacStedu * the device and the mount point copied in. If an 21526f3deacStedu * error occurs, the mountpoint is discarded by the 21626f3deacStedu * upper level code. 21726f3deacStedu */ 21826f3deacStedu /* Save "last mounted on" info for mount point (NULL pad)*/ 219a93bb724Sjsing bzero(mp->mnt_stat.f_mntonname, MNAMELEN); 220a93bb724Sjsing strlcpy(mp->mnt_stat.f_mntonname, path, MNAMELEN); 221a93bb724Sjsing bzero(mp->mnt_stat.f_mntfromname, MNAMELEN); 222aec3986eSjsing strlcpy(mp->mnt_stat.f_mntfromname, fname, MNAMELEN); 223aec3986eSjsing bzero(mp->mnt_stat.f_mntfromspec, MNAMELEN); 224aec3986eSjsing strlcpy(mp->mnt_stat.f_mntfromspec, fspec, MNAMELEN); 2257efda1a1Sderaadt bcopy(args, &mp->mnt_stat.mount_info.ntfs_args, sizeof(*args)); 22626f3deacStedu if ( !err) { 2277efda1a1Sderaadt err = ntfs_mountfs(devvp, mp, args, p); 22826f3deacStedu } 22926f3deacStedu } 23026f3deacStedu if (err) { 23126f3deacStedu goto error_2; 23226f3deacStedu } 23326f3deacStedu 23426f3deacStedu /* 23526f3deacStedu * Initialize FS stat information in mount struct; uses both 23626f3deacStedu * mp->mnt_stat.f_mntonname and mp->mnt_stat.f_mntfromname 23726f3deacStedu * 23826f3deacStedu * This code is common to root and non-root mounts 23926f3deacStedu */ 24026f3deacStedu (void)VFS_STATFS(mp, &mp->mnt_stat, p); 24126f3deacStedu 24226f3deacStedu goto success; 24326f3deacStedu 24426f3deacStedu 24526f3deacStedu error_2: /* error with devvp held*/ 24626f3deacStedu 24726f3deacStedu /* release devvp before failing*/ 24826f3deacStedu vrele(devvp); 24926f3deacStedu 25026f3deacStedu error_1: /* no state to back out*/ 25126f3deacStedu 25226f3deacStedu success: 25326f3deacStedu return(err); 25426f3deacStedu } 25526f3deacStedu 25626f3deacStedu /* 25726f3deacStedu * Common code for mount and mountroot 25826f3deacStedu */ 25926f3deacStedu int 2601cc0505dSjsing ntfs_mountfs(struct vnode *devvp, struct mount *mp, struct ntfs_args *argsp, 2611cc0505dSjsing struct proc *p) 26226f3deacStedu { 26326f3deacStedu struct buf *bp; 264bf3b3870Spat struct ntfsmount *ntmp = NULL; 26526f3deacStedu dev_t dev = devvp->v_rdev; 266288c69e0Snatano int error, ncount, i; 26726f3deacStedu struct vnode *vp; 26826f3deacStedu 26926f3deacStedu /* 27026f3deacStedu * Disallow multiple mounts of the same device. 27126f3deacStedu * Disallow mounting of a device that is currently in use 27226f3deacStedu * (except for root, which might share swap device for miniroot). 27326f3deacStedu * Flush out any old buffers remaining from a previous use. 27426f3deacStedu */ 27526f3deacStedu error = vfs_mountedon(devvp); 27626f3deacStedu if (error) 27726f3deacStedu return (error); 27826f3deacStedu ncount = vcount(devvp); 27926f3deacStedu if (ncount > 1 && devvp != rootvp) 28026f3deacStedu return (EBUSY); 2816e880534Svisa vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 282a8d7c3beScheloha error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, INFSLP); 28336bb23f1Svisa VOP_UNLOCK(devvp); 28426f3deacStedu if (error) 28526f3deacStedu return (error); 28626f3deacStedu 287288c69e0Snatano error = VOP_OPEN(devvp, FREAD, FSCRED, p); 28826f3deacStedu if (error) 28926f3deacStedu return (error); 29026f3deacStedu 29126f3deacStedu bp = NULL; 29226f3deacStedu 29393f62a9eStedu error = bread(devvp, BBLOCK, BBSIZE, &bp); 29426f3deacStedu if (error) 29526f3deacStedu goto out; 296bc9397c2Skrw ntmp = malloc(sizeof *ntmp, M_NTFSMNT, M_WAITOK | M_ZERO); 29726f3deacStedu bcopy(bp->b_data, &ntmp->ntm_bootfile, sizeof(struct bootfile)); 29826f3deacStedu brelse(bp); 29926f3deacStedu bp = NULL; 30026f3deacStedu 30126f3deacStedu if (strncmp(ntmp->ntm_bootfile.bf_sysid, NTFS_BBID, NTFS_BBIDLEN)) { 30226f3deacStedu error = EINVAL; 303a1ea65c6Sjsing DPRINTF("ntfs_mountfs: invalid boot block\n"); 30426f3deacStedu goto out; 30526f3deacStedu } 30626f3deacStedu 30726f3deacStedu { 30826f3deacStedu int8_t cpr = ntmp->ntm_mftrecsz; 30926f3deacStedu if( cpr > 0 ) 31026f3deacStedu ntmp->ntm_bpmftrec = ntmp->ntm_spc * cpr; 31126f3deacStedu else 31226f3deacStedu ntmp->ntm_bpmftrec = (1 << (-cpr)) / ntmp->ntm_bps; 31326f3deacStedu } 314f2997212Sjsing DPRINTF("ntfs_mountfs(): bps: %u, spc: %u, media: %x, " 315f2997212Sjsing "mftrecsz: %u (%u sects)\n", ntmp->ntm_bps, ntmp->ntm_spc, 316a1ea65c6Sjsing ntmp->ntm_bootfile.bf_media, ntmp->ntm_mftrecsz, 317a1ea65c6Sjsing ntmp->ntm_bpmftrec); 318f2997212Sjsing DPRINTF("ntfs_mountfs(): mftcn: 0x%llx|0x%llx\n", 319f2997212Sjsing ntmp->ntm_mftcn, ntmp->ntm_mftmirrcn); 32026f3deacStedu 32126f3deacStedu ntmp->ntm_mountp = mp; 32226f3deacStedu ntmp->ntm_dev = dev; 32326f3deacStedu ntmp->ntm_devvp = devvp; 32426f3deacStedu ntmp->ntm_uid = argsp->uid; 32526f3deacStedu ntmp->ntm_gid = argsp->gid; 32626f3deacStedu ntmp->ntm_mode = argsp->mode; 32726f3deacStedu ntmp->ntm_flag = argsp->flag; 32841e0c475Sguenther mp->mnt_data = ntmp; 3298fc6378aSjsing TAILQ_INIT(&ntmp->ntm_ntnodeq); 33026f3deacStedu 33126f3deacStedu /* set file name encode/decode hooks XXX utf-8 only for now */ 33226f3deacStedu ntmp->ntm_wget = ntfs_utf8_wget; 33326f3deacStedu ntmp->ntm_wput = ntfs_utf8_wput; 33426f3deacStedu ntmp->ntm_wcmp = ntfs_utf8_wcmp; 33526f3deacStedu 336a1ea65c6Sjsing DPRINTF("ntfs_mountfs(): case-%s,%s uid: %d, gid: %d, mode: %o\n", 33726f3deacStedu (ntmp->ntm_flag & NTFS_MFLAG_CASEINS) ? "insens." : "sens.", 33826f3deacStedu (ntmp->ntm_flag & NTFS_MFLAG_ALLNAMES) ? " allnames," : "", 339a1ea65c6Sjsing ntmp->ntm_uid, ntmp->ntm_gid, ntmp->ntm_mode); 34026f3deacStedu 34126f3deacStedu /* 34226f3deacStedu * We read in some system nodes to do not allow 34326f3deacStedu * reclaim them and to have every time access to them. 34426f3deacStedu */ 34526f3deacStedu { 34626f3deacStedu int pi[3] = { NTFS_MFTINO, NTFS_ROOTINO, NTFS_BITMAPINO }; 34726f3deacStedu for (i=0; i<3; i++) { 34826f3deacStedu error = VFS_VGET(mp, pi[i], &(ntmp->ntm_sysvn[pi[i]])); 34926f3deacStedu if(error) 35026f3deacStedu goto out1; 35126f3deacStedu ntmp->ntm_sysvn[pi[i]]->v_flag |= VSYSTEM; 352627b2c48Sthib vref(ntmp->ntm_sysvn[pi[i]]); 35326f3deacStedu vput(ntmp->ntm_sysvn[pi[i]]); 35426f3deacStedu } 35526f3deacStedu } 35626f3deacStedu 35726f3deacStedu /* read the Unicode lowercase --> uppercase translation table, 35826f3deacStedu * if necessary */ 359274476fcStedu if ((error = ntfs_toupper_use(mp, ntmp, p))) 36026f3deacStedu goto out1; 36126f3deacStedu 36226f3deacStedu /* 36326f3deacStedu * Scan $BitMap and count free clusters 36426f3deacStedu */ 36526f3deacStedu error = ntfs_calccfree(ntmp, &ntmp->ntm_cfree); 36626f3deacStedu if(error) 36726f3deacStedu goto out1; 36826f3deacStedu 36926f3deacStedu /* 37026f3deacStedu * Read and translate to internal format attribute 37126f3deacStedu * definition file. 37226f3deacStedu */ 37326f3deacStedu { 37426f3deacStedu int num,j; 37526f3deacStedu struct attrdef ad; 37626f3deacStedu 37726f3deacStedu /* Open $AttrDef */ 37826f3deacStedu error = VFS_VGET(mp, NTFS_ATTRDEFINO, &vp ); 37926f3deacStedu if(error) 38026f3deacStedu goto out1; 38126f3deacStedu 38226f3deacStedu /* Count valid entries */ 38326f3deacStedu for(num = 0; ; num++) { 38426f3deacStedu error = ntfs_readattr(ntmp, VTONT(vp), 385c6c302e5Stedu NTFS_A_DATA, NULL, num * sizeof(ad), sizeof(ad), 38626f3deacStedu &ad, NULL); 38726f3deacStedu if (error) 38826f3deacStedu goto out1; 38926f3deacStedu if (ad.ad_name[0] == 0) 39026f3deacStedu break; 39126f3deacStedu } 39226f3deacStedu 39326f3deacStedu /* Alloc memory for attribute definitions */ 394540e394aSdoug ntmp->ntm_ad = mallocarray(num, sizeof(struct ntvattrdef), 39526f3deacStedu M_NTFSMNT, M_WAITOK); 39626f3deacStedu 39726f3deacStedu ntmp->ntm_adnum = num; 39826f3deacStedu 39926f3deacStedu /* Read them and translate */ 40026f3deacStedu for(i = 0; i < num; i++){ 40126f3deacStedu error = ntfs_readattr(ntmp, VTONT(vp), 402c6c302e5Stedu NTFS_A_DATA, NULL, i * sizeof(ad), sizeof(ad), 40326f3deacStedu &ad, NULL); 40426f3deacStedu if (error) 40526f3deacStedu goto out1; 40626f3deacStedu j = 0; 40726f3deacStedu do { 40826f3deacStedu ntmp->ntm_ad[i].ad_name[j] = ad.ad_name[j]; 40926f3deacStedu } while(ad.ad_name[j++]); 41026f3deacStedu ntmp->ntm_ad[i].ad_namelen = j - 1; 41126f3deacStedu ntmp->ntm_ad[i].ad_type = ad.ad_type; 41226f3deacStedu } 41326f3deacStedu 41426f3deacStedu vput(vp); 41526f3deacStedu } 41626f3deacStedu 41726f3deacStedu mp->mnt_stat.f_fsid.val[0] = dev; 4187d8a2b95Stedu mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; 419f28dec03Snatano mp->mnt_stat.f_namemax = NTFS_MAXFILENAME; 42026f3deacStedu mp->mnt_flag |= MNT_LOCAL; 42126f3deacStedu devvp->v_specmountpoint = mp; 42226f3deacStedu return (0); 42326f3deacStedu 42426f3deacStedu out1: 42526f3deacStedu for (i = 0; i < NTFS_SYSNODESNUM; i++) 426bf3b3870Spat if (ntmp->ntm_sysvn[i]) 427bf3b3870Spat vrele(ntmp->ntm_sysvn[i]); 42826f3deacStedu 42926f3deacStedu if (vflush(mp,NULLVP,0)) 430a1ea65c6Sjsing DPRINTF("ntfs_mountfs: vflush failed\n"); 43126f3deacStedu 43226f3deacStedu out: 4339ee302b8Sbluhm if (devvp->v_specinfo) 43426f3deacStedu devvp->v_specmountpoint = NULL; 43526f3deacStedu if (bp) 43626f3deacStedu brelse(bp); 43726f3deacStedu 438bf3b3870Spat if (ntmp != NULL) { 439bf3b3870Spat if (ntmp->ntm_ad != NULL) 440825c4e6aStedu free(ntmp->ntm_ad, M_NTFSMNT, 0); 441825c4e6aStedu free(ntmp, M_NTFSMNT, 0); 442bf3b3870Spat mp->mnt_data = NULL; 443bf3b3870Spat } 444bf3b3870Spat 44526f3deacStedu /* lock the device vnode before calling VOP_CLOSE() */ 4466e880534Svisa vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 447288c69e0Snatano (void)VOP_CLOSE(devvp, FREAD, NOCRED, p); 44836bb23f1Svisa VOP_UNLOCK(devvp); 44926f3deacStedu 45026f3deacStedu return (error); 45126f3deacStedu } 45226f3deacStedu 45305c5dae5Sjsing int 4541cc0505dSjsing ntfs_start(struct mount *mp, int flags, struct proc *p) 45526f3deacStedu { 45626f3deacStedu return (0); 45726f3deacStedu } 45826f3deacStedu 45905c5dae5Sjsing int 4601cc0505dSjsing ntfs_unmount(struct mount *mp, int mntflags, struct proc *p) 46126f3deacStedu { 46226f3deacStedu struct ntfsmount *ntmp; 463288c69e0Snatano int error, flags, i; 46426f3deacStedu 465a1ea65c6Sjsing DPRINTF("ntfs_unmount: unmounting...\n"); 46626f3deacStedu ntmp = VFSTONTFS(mp); 46726f3deacStedu 46826f3deacStedu flags = 0; 46926f3deacStedu if(mntflags & MNT_FORCE) 47026f3deacStedu flags |= FORCECLOSE; 47126f3deacStedu 472a1ea65c6Sjsing DPRINTF("ntfs_unmount: vflushing...\n"); 47326f3deacStedu error = vflush(mp,NULLVP,flags | SKIPSYSTEM); 47426f3deacStedu if (error) { 475a1ea65c6Sjsing DPRINTF("ntfs_unmount: vflush failed: %d\n", error); 47626f3deacStedu return (error); 47726f3deacStedu } 47826f3deacStedu 47969a62ea9Smikeb /* Check if system vnodes are still referenced */ 48069a62ea9Smikeb for(i=0;i<NTFS_SYSNODESNUM;i++) { 48169a62ea9Smikeb if(((mntflags & MNT_FORCE) == 0) && (ntmp->ntm_sysvn[i] && 48269a62ea9Smikeb ntmp->ntm_sysvn[i]->v_usecount > 1)) 48369a62ea9Smikeb return (EBUSY); 48469a62ea9Smikeb } 48526f3deacStedu 48626f3deacStedu /* Dereference all system vnodes */ 48726f3deacStedu for(i=0;i<NTFS_SYSNODESNUM;i++) 48826f3deacStedu if(ntmp->ntm_sysvn[i]) vrele(ntmp->ntm_sysvn[i]); 48926f3deacStedu 49026f3deacStedu /* vflush system vnodes */ 49126f3deacStedu error = vflush(mp,NULLVP,flags); 49226f3deacStedu if (error) { 49326f3deacStedu /* XXX should this be panic() ? */ 49426f3deacStedu printf("ntfs_unmount: vflush failed(sysnodes): %d\n",error); 49526f3deacStedu } 49626f3deacStedu 49726f3deacStedu /* Check if the type of device node isn't VBAD before 49826f3deacStedu * touching v_specinfo. If the device vnode is revoked, the 4990d297f47Sjsg * field is NULL and touching it causes null pointer dereference. 50026f3deacStedu */ 50126f3deacStedu if (ntmp->ntm_devvp->v_type != VBAD) 50226f3deacStedu ntmp->ntm_devvp->v_specmountpoint = NULL; 50326f3deacStedu 50426f3deacStedu /* lock the device vnode before calling VOP_CLOSE() */ 5056e880534Svisa vn_lock(ntmp->ntm_devvp, LK_EXCLUSIVE | LK_RETRY); 506a8d7c3beScheloha vinvalbuf(ntmp->ntm_devvp, V_SAVE, NOCRED, p, 0, INFSLP); 507288c69e0Snatano (void)VOP_CLOSE(ntmp->ntm_devvp, FREAD, NOCRED, p); 5083542ec7aSkrw vput(ntmp->ntm_devvp); 50926f3deacStedu 510274476fcStedu /* free the toupper table, if this has been last mounted ntfs volume */ 511274476fcStedu ntfs_toupper_unuse(p); 512274476fcStedu 513a1ea65c6Sjsing DPRINTF("ntfs_unmount: freeing memory...\n"); 514825c4e6aStedu free(ntmp->ntm_ad, M_NTFSMNT, 0); 515825c4e6aStedu free(ntmp, M_NTFSMNT, 0); 516200e77f4Sbluhm mp->mnt_data = NULL; 517200e77f4Sbluhm mp->mnt_flag &= ~MNT_LOCAL; 5184b1ae25eSbluhm return (0); 51926f3deacStedu } 52026f3deacStedu 52105c5dae5Sjsing int 5221cc0505dSjsing ntfs_root(struct mount *mp, struct vnode **vpp) 52326f3deacStedu { 52426f3deacStedu struct vnode *nvp; 52526f3deacStedu int error = 0; 52626f3deacStedu 527a1ea65c6Sjsing DPRINTF("ntfs_root(): sysvn: %p\n", 528a1ea65c6Sjsing VFSTONTFS(mp)->ntm_sysvn[NTFS_ROOTINO]); 52926f3deacStedu error = VFS_VGET(mp, (ino_t)NTFS_ROOTINO, &nvp); 53026f3deacStedu if(error) { 53126f3deacStedu printf("ntfs_root: VFS_VGET failed: %d\n",error); 53226f3deacStedu return (error); 53326f3deacStedu } 53426f3deacStedu 53526f3deacStedu *vpp = nvp; 53626f3deacStedu return (0); 53726f3deacStedu } 53826f3deacStedu 539835c1779Sbrad /* 540835c1779Sbrad * Do operations associated with quotas, not supported 541835c1779Sbrad */ 54205c5dae5Sjsing int 5431cc0505dSjsing ntfs_quotactl(struct mount *mp, int cmds, uid_t uid, caddr_t arg, 54426f3deacStedu struct proc *p) 54526f3deacStedu { 54626f3deacStedu return EOPNOTSUPP; 54726f3deacStedu } 54826f3deacStedu 54926f3deacStedu int 5501cc0505dSjsing ntfs_calccfree(struct ntfsmount *ntmp, cn_t *cfreep) 55126f3deacStedu { 55226f3deacStedu struct vnode *vp; 55326f3deacStedu u_int8_t *tmp; 55426f3deacStedu int j, error; 555835c1779Sbrad cn_t cfree = 0; 5569414ecb5Sjca uint64_t bmsize, offset; 5579414ecb5Sjca size_t chunksize, i; 55826f3deacStedu 55926f3deacStedu vp = ntmp->ntm_sysvn[NTFS_BITMAPINO]; 56026f3deacStedu 56126f3deacStedu bmsize = VTOF(vp)->f_size; 56226f3deacStedu 5639414ecb5Sjca if (bmsize > 1024 * 1024) 5649414ecb5Sjca chunksize = 1024 * 1024; 5659414ecb5Sjca else 5669414ecb5Sjca chunksize = bmsize; 5679414ecb5Sjca 5689414ecb5Sjca tmp = malloc(chunksize, M_TEMP, M_WAITOK); 5699414ecb5Sjca 5709414ecb5Sjca for (offset = 0; offset < bmsize; offset += chunksize) { 5719414ecb5Sjca if (chunksize > bmsize - offset) 5729414ecb5Sjca chunksize = bmsize - offset; 57326f3deacStedu 57426f3deacStedu error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL, 5759414ecb5Sjca offset, chunksize, tmp, NULL); 57626f3deacStedu if (error) 57726f3deacStedu goto out; 57826f3deacStedu 5799414ecb5Sjca for (i = 0; i < chunksize; i++) 58026f3deacStedu for (j = 0; j < 8; j++) 5819414ecb5Sjca if (~tmp[i] & (1 << j)) 5829414ecb5Sjca cfree++; 5839414ecb5Sjca } 5849414ecb5Sjca 58526f3deacStedu *cfreep = cfree; 58626f3deacStedu 58726f3deacStedu out: 588825c4e6aStedu free(tmp, M_TEMP, 0); 58926f3deacStedu return(error); 59026f3deacStedu } 59126f3deacStedu 59205c5dae5Sjsing int 5931cc0505dSjsing ntfs_statfs(struct mount *mp, struct statfs *sbp, struct proc *p) 59426f3deacStedu { 59526f3deacStedu struct ntfsmount *ntmp = VFSTONTFS(mp); 59626f3deacStedu u_int64_t mftallocated; 59726f3deacStedu 598a1ea65c6Sjsing DPRINTF("ntfs_statfs():\n"); 59926f3deacStedu 60026f3deacStedu mftallocated = VTOF(ntmp->ntm_sysvn[NTFS_MFTINO])->f_allocated; 60126f3deacStedu 60226f3deacStedu sbp->f_bsize = ntmp->ntm_bps; 60326f3deacStedu sbp->f_iosize = ntmp->ntm_bps * ntmp->ntm_spc; 60426f3deacStedu sbp->f_blocks = ntmp->ntm_bootfile.bf_spv; 60526f3deacStedu sbp->f_bfree = sbp->f_bavail = ntfs_cntobn(ntmp->ntm_cfree); 606f28dec03Snatano sbp->f_ffree = sbp->f_favail = sbp->f_bfree / ntmp->ntm_bpmftrec; 60726f3deacStedu sbp->f_files = mftallocated / ntfs_bntob(ntmp->ntm_bpmftrec) + 60826f3deacStedu sbp->f_ffree; 609f28dec03Snatano copy_statfs_info(sbp, mp); 6101ad3841aSjasper 61126f3deacStedu return (0); 61226f3deacStedu } 61326f3deacStedu 61405c5dae5Sjsing int 615976e9839Sderaadt ntfs_sync(struct mount *mp, int waitfor, int stall, struct ucred *cred, struct proc *p) 61626f3deacStedu { 617a1ea65c6Sjsing /*DPRINTF("ntfs_sync():\n");*/ 61826f3deacStedu return (0); 61926f3deacStedu } 62026f3deacStedu 62105c5dae5Sjsing int 6221cc0505dSjsing ntfs_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp) 62326f3deacStedu { 62426f3deacStedu struct ntfid *ntfhp = (struct ntfid *)fhp; 62526f3deacStedu int error; 62626f3deacStedu 627f2997212Sjsing DDPRINTF("ntfs_fhtovp(): %s: %u\n", 628a1ea65c6Sjsing mp->mnt_stat.f_mntonname, ntfhp->ntfid_ino); 62926f3deacStedu 63026f3deacStedu error = ntfs_vgetex(mp, ntfhp->ntfid_ino, ntfhp->ntfid_attr, NULL, 631db7aa982Smpi LK_EXCLUSIVE | LK_RETRY, 0, vpp); /* XXX */ 63226f3deacStedu if (error != 0) { 63326f3deacStedu *vpp = NULLVP; 63426f3deacStedu return (error); 63526f3deacStedu } 63626f3deacStedu 63726f3deacStedu /* XXX as unlink/rmdir/mkdir/creat are not currently possible 63826f3deacStedu * with NTFS, we don't need to check anything else for now */ 63926f3deacStedu return (0); 64026f3deacStedu } 64126f3deacStedu 64205c5dae5Sjsing int 6431cc0505dSjsing ntfs_vptofh(struct vnode *vp, struct fid *fhp) 64426f3deacStedu { 64526f3deacStedu struct ntnode *ntp; 64626f3deacStedu struct ntfid *ntfhp; 64726f3deacStedu struct fnode *fn; 64826f3deacStedu 649a1ea65c6Sjsing DDPRINTF("ntfs_fhtovp(): %s: %p\n", 650a1ea65c6Sjsing vp->v_mount->mnt_stat.f_mntonname, vp); 65126f3deacStedu 65226f3deacStedu fn = VTOF(vp); 65326f3deacStedu ntp = VTONT(vp); 65426f3deacStedu ntfhp = (struct ntfid *)fhp; 65526f3deacStedu ntfhp->ntfid_len = sizeof(struct ntfid); 65626f3deacStedu ntfhp->ntfid_ino = ntp->i_number; 65726f3deacStedu ntfhp->ntfid_attr = fn->f_attrtype; 65826f3deacStedu #ifdef notyet 65926f3deacStedu ntfhp->ntfid_gen = ntp->i_gen; 66026f3deacStedu #endif 66126f3deacStedu return (0); 66226f3deacStedu } 66326f3deacStedu 66426f3deacStedu int 66595a73601Sguenther ntfs_vgetex(struct mount *mp, ntfsino_t ino, u_int32_t attrtype, char *attrname, 666db7aa982Smpi u_long lkflags, u_long flags, struct vnode **vpp) 66726f3deacStedu { 66826f3deacStedu int error; 66926f3deacStedu struct ntfsmount *ntmp; 67026f3deacStedu struct ntnode *ip; 67126f3deacStedu struct fnode *fp; 67226f3deacStedu struct vnode *vp; 67326f3deacStedu enum vtype f_type; 67426f3deacStedu 675f2997212Sjsing DPRINTF("ntfs_vgetex: ino: %u, attr: 0x%x:%s, lkf: 0x%lx, f: 0x%lx\n", 676f2997212Sjsing ino, attrtype, attrname ? attrname : "", lkflags, flags); 67726f3deacStedu 67826f3deacStedu ntmp = VFSTONTFS(mp); 67926f3deacStedu *vpp = NULL; 68026f3deacStedu 68126f3deacStedu /* Get ntnode */ 682db7aa982Smpi error = ntfs_ntlookup(ntmp, ino, &ip); 68326f3deacStedu if (error) { 68426f3deacStedu printf("ntfs_vget: ntfs_ntget failed\n"); 68526f3deacStedu return (error); 68626f3deacStedu } 68726f3deacStedu 68826f3deacStedu /* It may be not initialized fully, so force load it */ 68926f3deacStedu if (!(flags & VG_DONTLOADIN) && !(ip->i_flag & IN_LOADED)) { 69026f3deacStedu error = ntfs_loadntnode(ntmp, ip); 69126f3deacStedu if(error) { 69226f3deacStedu printf("ntfs_vget: CAN'T LOAD ATTRIBUTES FOR INO: %d\n", 69326f3deacStedu ip->i_number); 694db7aa982Smpi ntfs_ntput(ip); 6951ad3841aSjasper 69626f3deacStedu return (error); 69726f3deacStedu } 69826f3deacStedu } 69926f3deacStedu 70026f3deacStedu error = ntfs_fget(ntmp, ip, attrtype, attrname, &fp); 70126f3deacStedu if (error) { 70226f3deacStedu printf("ntfs_vget: ntfs_fget failed\n"); 703db7aa982Smpi ntfs_ntput(ip); 7041ad3841aSjasper 70526f3deacStedu return (error); 70626f3deacStedu } 70726f3deacStedu 70826f3deacStedu if (!(flags & VG_DONTVALIDFN) && !(fp->f_flag & FN_VALID)) { 70926f3deacStedu if ((ip->i_frflag & NTFS_FRFLAG_DIR) && 71026f3deacStedu (fp->f_attrtype == NTFS_A_DATA && fp->f_attrname == NULL)) { 71126f3deacStedu f_type = VDIR; 71226f3deacStedu } else if (flags & VG_EXT) { 71326f3deacStedu f_type = VNON; 71426f3deacStedu fp->f_size = fp->f_allocated = 0; 71526f3deacStedu } else { 71626f3deacStedu f_type = VREG; 71726f3deacStedu 71826f3deacStedu error = ntfs_filesize(ntmp, fp, 71926f3deacStedu &fp->f_size, &fp->f_allocated); 72026f3deacStedu if (error) { 721db7aa982Smpi ntfs_ntput(ip); 7221ad3841aSjasper 72326f3deacStedu return (error); 72426f3deacStedu } 72526f3deacStedu } 72626f3deacStedu 72726f3deacStedu fp->f_flag |= FN_VALID; 72826f3deacStedu } 72926f3deacStedu 73026f3deacStedu /* 73126f3deacStedu * We may be calling vget() now. To avoid potential deadlock, we need 73226f3deacStedu * to release ntnode lock, since due to locking order vnode 73326f3deacStedu * lock has to be acquired first. 73426f3deacStedu * ntfs_fget() bumped ntnode usecount, so ntnode won't be recycled 73526f3deacStedu * prematurely. 73626f3deacStedu */ 737db7aa982Smpi ntfs_ntput(ip); 73826f3deacStedu 73926f3deacStedu if (FTOV(fp)) { 74026f3deacStedu /* vget() returns error if the vnode has been recycled */ 74108107a0bSvisa if (vget(FTOV(fp), lkflags) == 0) { 74226f3deacStedu *vpp = FTOV(fp); 74326f3deacStedu return (0); 74426f3deacStedu } 74526f3deacStedu } 74626f3deacStedu 747dc81e71aSthib error = getnewvnode(VT_NTFS, ntmp->ntm_mountp, &ntfs_vops, &vp); 74826f3deacStedu if(error) { 74926f3deacStedu ntfs_frele(fp); 750db7aa982Smpi ntfs_ntput(ip); 7511ad3841aSjasper 75226f3deacStedu return (error); 75326f3deacStedu } 754f2997212Sjsing DPRINTF("ntfs_vget: vnode: %p for ntnode: %u\n", vp, ino); 75526f3deacStedu 75626f3deacStedu fp->f_vp = vp; 75726f3deacStedu vp->v_data = fp; 75826f3deacStedu vp->v_type = f_type; 75926f3deacStedu 76026f3deacStedu if (ino == NTFS_ROOTINO) 76126f3deacStedu vp->v_flag |= VROOT; 76226f3deacStedu 76326f3deacStedu if (lkflags & LK_TYPE_MASK) { 7646e880534Svisa error = vn_lock(vp, lkflags); 76526f3deacStedu if (error) { 76626f3deacStedu vput(vp); 76726f3deacStedu return (error); 76826f3deacStedu } 76926f3deacStedu } 77026f3deacStedu 77126f3deacStedu *vpp = vp; 77226f3deacStedu return (0); 77326f3deacStedu } 77426f3deacStedu 77505c5dae5Sjsing int 7761cc0505dSjsing ntfs_vget(struct mount *mp, ino_t ino, struct vnode **vpp) 77726f3deacStedu { 77895a73601Sguenther if (ino > (ntfsino_t)-1) 77995a73601Sguenther panic("ntfs_vget: alien ino_t %llu", (unsigned long long)ino); 78026f3deacStedu return ntfs_vgetex(mp, ino, NTFS_A_DATA, NULL, 781db7aa982Smpi LK_EXCLUSIVE | LK_RETRY, 0, vpp); /* XXX */ 78226f3deacStedu } 78326f3deacStedu 784e4b1e213Smickey const struct vfsops ntfs_vfsops = { 78541f642fcSbluhm .vfs_mount = ntfs_mount, 78641f642fcSbluhm .vfs_start = ntfs_start, 78741f642fcSbluhm .vfs_unmount = ntfs_unmount, 78841f642fcSbluhm .vfs_root = ntfs_root, 78941f642fcSbluhm .vfs_quotactl = ntfs_quotactl, 79041f642fcSbluhm .vfs_statfs = ntfs_statfs, 79141f642fcSbluhm .vfs_sync = ntfs_sync, 79241f642fcSbluhm .vfs_vget = ntfs_vget, 79341f642fcSbluhm .vfs_fhtovp = ntfs_fhtovp, 79441f642fcSbluhm .vfs_vptofh = ntfs_vptofh, 79541f642fcSbluhm .vfs_init = ntfs_init, 79641f642fcSbluhm .vfs_sysctl = ntfs_sysctl, 79741f642fcSbluhm .vfs_checkexp = ntfs_checkexp, 79826f3deacStedu }; 799