/* * Common code for mount and mountroot */ int ntfs_mountfs(struct vnode *devvp, struct mount *mp, struct ntfs_args *argsp, struct ucred *cred) { struct buf *bp; struct ntfsmount *ntmp; cdev_t dev; int error, ronly, ncount, i; struct vnode *vp; char cs_local[ICONV_CSNMAXLEN]; char cs_ntfs[ICONV_CSNMAXLEN]; /* * Disallow multiple mounts of the same device. * Disallow mounting of a device that is currently in use * (except for root, which might share swap device for miniroot). * Flush out any old buffers remaining from a previous use. */ error = vfs_mountedon(devvp); if (error) return (error); ncount = vcount(devvp); if (devvp->v_object) ncount -= 1; if (ncount > 1) return (EBUSY); VN_LOCK(devvp, LK_EXCLUSIVE | LK_RETRY); error = vinvalbuf(devvp, V_SAVE, 0, 0); VOP__UNLOCK(devvp, 0); if (error) return (error); ronly = (mp->mnt_flag & MNT_RDONLY) != 0; VN_LOCK(devvp, LK_EXCLUSIVE | LK_RETRY); error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, NULL); VOP__UNLOCK(devvp, 0); if (error) return (error); dev = devvp->v_rdev; bp = NULL; error = bread(devvp, BBLOCK, BBSIZE, &bp); if (error) goto out; ntmp = kmalloc(sizeof *ntmp, M_NTFSMNT, M_WAITOK | M_ZERO); bcopy( bp->b_data, &ntmp->ntm_bootfile, sizeof(struct bootfile) ); /* * We must not cache the boot block if its size is not exactly * one cluster in order to avoid confusing the buffer cache when * the boot file is read later by ntfs_readntvattr_plain(), which * reads a cluster at a time. */ if (ntfs_cntob(1) != BBSIZE) bp->b_flags |= B_NOCACHE; brelse( bp ); bp = NULL; if (strncmp(ntmp->ntm_bootfile.bf_sysid, NTFS_BBID, NTFS_BBIDLEN)) { error = EINVAL; dprintf(("ntfs_mountfs: invalid boot block\n")); goto out; } { int8_t cpr = ntmp->ntm_mftrecsz; if( cpr > 0 ) ntmp->ntm_bpmftrec = ntmp->ntm_spc * cpr; else ntmp->ntm_bpmftrec = (1 << (-cpr)) / ntmp->ntm_bps; } dprintf(("ntfs_mountfs(): bps: %d, spc: %d, media: %x, mftrecsz: %d (%d sects)\n", ntmp->ntm_bps,ntmp->ntm_spc,ntmp->ntm_bootfile.bf_media, ntmp->ntm_mftrecsz,ntmp->ntm_bpmftrec)); dprintf(("ntfs_mountfs(): mftcn: 0x%x|0x%x\n", (u_int32_t)ntmp->ntm_mftcn,(u_int32_t)ntmp->ntm_mftmirrcn)); ntmp->ntm_mountp = mp; ntmp->ntm_dev = dev; ntmp->ntm_devvp = devvp; ntmp->ntm_uid = argsp->uid; ntmp->ntm_gid = argsp->gid; ntmp->ntm_mode = argsp->mode; ntmp->ntm_flag = argsp->flag; if (argsp->flag & NTFS_MFLAG_KICONV && ntfs_iconv) { bcopy(argsp->cs_local, cs_local, sizeof(cs_local)); bcopy(argsp->cs_ntfs, cs_ntfs, sizeof(cs_ntfs)); ntfs_82u_init(ntmp, cs_local, cs_ntfs); ntfs_u28_init(ntmp, NULL, cs_local, cs_ntfs); } else { ntfs_82u_init(ntmp, NULL, NULL); ntfs_u28_init(ntmp, ntmp->ntm_82u, NULL, NULL); } mp->mnt_data = (qaddr_t)ntmp; dprintf(("ntfs_mountfs(): case-%s,%s uid: %d, gid: %d, mode: %o\n", (ntmp->ntm_flag & NTFS_MFLAG_CASEINS)?"insens.":"sens.", (ntmp->ntm_flag & NTFS_MFLAG_ALLNAMES)?" allnames,":"", ntmp->ntm_uid, ntmp->ntm_gid, ntmp->ntm_mode)); vfs_add_vnodeops(mp, &ntfs_vnode_vops, &mp->mnt_vn_norm_ops); /* * We read in some system nodes to do not allow * reclaim them and to have everytime access to them. */ { int pi[3] = { NTFS_MFTINO, NTFS_ROOTINO, NTFS_BITMAPINO }; for (i=0; i<3; i++) { error = VFS_VGET(mp, NULL, pi[i], &(ntmp->ntm_sysvn[pi[i]])); if(error) goto out1; vsetflags(ntmp->ntm_sysvn[pi[i]], VSYSTEM); vref(ntmp->ntm_sysvn[pi[i]]); vput(ntmp->ntm_sysvn[pi[i]]); } } /* read the Unicode lowercase --> uppercase translation table, * if necessary */ if ((error = ntfs_toupper_use(mp, ntmp))) goto out1; /* * Scan $BitMap and count free clusters */ error = ntfs_calccfree(ntmp, &ntmp->ntm_cfree); if(error) goto out1; /* * Read and translate to internal format attribute * definition file. */ { int num,j; struct attrdef ad; /* Open $AttrDef */ error = VFS_VGET(mp, NULL, NTFS_ATTRDEFINO, &vp); if(error) goto out1; /* Count valid entries */ for(num=0;;num++) { error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL, num * sizeof(ad), sizeof(ad), &ad, NULL); if (error) goto out1; if (ad.ad_name[0] == 0) break; } /* Alloc memory for attribute definitions */ ntmp->ntm_ad = kmalloc(num * sizeof(struct ntvattrdef), M_NTFSMNT, M_WAITOK); ntmp->ntm_adnum = num; /* Read them and translate */ for(i=0;i<num;i++){ error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL, i * sizeof(ad), sizeof(ad), &ad, NULL); if (error) goto out1; j = 0; do { ntmp->ntm_ad[i].ad_name[j] = ad.ad_name[j]; } while(ad.ad_name[j++]); ntmp->ntm_ad[i].ad_namelen = j - 1; ntmp->ntm_ad[i].ad_type = ad.ad_type; } vput(vp); } mp->mnt_stat.f_fsid.val[0] = dev2udev(dev); mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; mp->mnt_maxsymlinklen = 0; mp->mnt_flag |= MNT_LOCAL; dev->si_mountpoint = mp; return (0); out1: for(i=0;i<NTFS_SYSNODESNUM;i++) if(ntmp->ntm_sysvn[i]) vrele(ntmp->ntm_sysvn[i]); if (vflush(mp, 0, 0)) dprintf(("ntfs_mountfs: vflush failed\n")); out: dev->si_mountpoint = NULL; if (bp) brelse(bp); vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NULL); vn_unlock(devvp); return (error); }
/* * Common code for mount and mountroot */ int ntfs_mountfs(struct vnode *devvp, struct mount *mp, struct ntfs_args *argsp, struct lwp *l) { struct buf *bp; struct ntfsmount *ntmp; dev_t dev = devvp->v_rdev; int error, i; struct vnode *vp; ntmp = NULL; /* * Flush out any old buffers remaining from a previous use. */ vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); error = vinvalbuf(devvp, V_SAVE, l->l_cred, l, 0, 0); VOP_UNLOCK(devvp); if (error) return (error); bp = NULL; error = bread(devvp, BBLOCK, BBSIZE, NOCRED, 0, &bp); if (error) goto out; ntmp = malloc( sizeof *ntmp, M_NTFSMNT, M_WAITOK|M_ZERO); memcpy( &ntmp->ntm_bootfile, bp->b_data, sizeof(struct bootfile) ); brelse( bp , 0 ); bp = NULL; if (strncmp(ntmp->ntm_bootfile.bf_sysid, NTFS_BBID, NTFS_BBIDLEN)) { error = EINVAL; dprintf(("ntfs_mountfs: invalid boot block\n")); goto out; } { int8_t cpr = ntmp->ntm_mftrecsz; if( cpr > 0 ) ntmp->ntm_bpmftrec = ntmp->ntm_spc * cpr; else ntmp->ntm_bpmftrec = (1 << (-cpr)) / ntmp->ntm_bps; } dprintf(("ntfs_mountfs(): bps: %d, spc: %d, media: %x, mftrecsz: %d (%d sects)\n", ntmp->ntm_bps,ntmp->ntm_spc,ntmp->ntm_bootfile.bf_media, ntmp->ntm_mftrecsz,ntmp->ntm_bpmftrec)); dprintf(("ntfs_mountfs(): mftcn: 0x%x|0x%x\n", (u_int32_t)ntmp->ntm_mftcn,(u_int32_t)ntmp->ntm_mftmirrcn)); ntmp->ntm_mountp = mp; ntmp->ntm_dev = dev; ntmp->ntm_devvp = devvp; ntmp->ntm_uid = argsp->uid; ntmp->ntm_gid = argsp->gid; ntmp->ntm_mode = argsp->mode; ntmp->ntm_flag = argsp->flag; mp->mnt_data = ntmp; /* set file name encode/decode hooks XXX utf-8 only for now */ ntmp->ntm_wget = ntfs_utf8_wget; ntmp->ntm_wput = ntfs_utf8_wput; ntmp->ntm_wcmp = ntfs_utf8_wcmp; dprintf(("ntfs_mountfs(): case-%s,%s uid: %d, gid: %d, mode: %o\n", (ntmp->ntm_flag & NTFS_MFLAG_CASEINS)?"insens.":"sens.", (ntmp->ntm_flag & NTFS_MFLAG_ALLNAMES)?" allnames,":"", ntmp->ntm_uid, ntmp->ntm_gid, ntmp->ntm_mode)); /* * We read in some system nodes to do not allow * reclaim them and to have everytime access to them. */ { int pi[3] = { NTFS_MFTINO, NTFS_ROOTINO, NTFS_BITMAPINO }; for (i=0; i<3; i++) { error = VFS_VGET(mp, pi[i], &(ntmp->ntm_sysvn[pi[i]])); if(error) goto out1; ntmp->ntm_sysvn[pi[i]]->v_vflag |= VV_SYSTEM; vref(ntmp->ntm_sysvn[pi[i]]); vput(ntmp->ntm_sysvn[pi[i]]); } } /* read the Unicode lowercase --> uppercase translation table, * if necessary */ if ((error = ntfs_toupper_use(mp, ntmp))) goto out1; /* * Scan $BitMap and count free clusters */ error = ntfs_calccfree(ntmp, &ntmp->ntm_cfree); if(error) goto out1; /* * Read and translate to internal format attribute * definition file. */ { int num,j; struct attrdef ad; /* Open $AttrDef */ error = VFS_VGET(mp, NTFS_ATTRDEFINO, &vp ); if(error) goto out1; /* Count valid entries */ for(num=0;;num++) { error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL, num * sizeof(ad), sizeof(ad), &ad, NULL); if (error) goto out1; if (ad.ad_name[0] == 0) break; } /* Alloc memory for attribute definitions */ ntmp->ntm_ad = (struct ntvattrdef *) malloc( num * sizeof(struct ntvattrdef), M_NTFSMNT, M_WAITOK); ntmp->ntm_adnum = num; /* Read them and translate */ for(i=0;i<num;i++){ error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL, i * sizeof(ad), sizeof(ad), &ad, NULL); if (error) goto out1; j = 0; do { ntmp->ntm_ad[i].ad_name[j] = ad.ad_name[j]; } while(ad.ad_name[j++]); ntmp->ntm_ad[i].ad_namelen = j - 1; ntmp->ntm_ad[i].ad_type = ad.ad_type; } vput(vp); } mp->mnt_stat.f_fsidx.__fsid_val[0] = dev; mp->mnt_stat.f_fsidx.__fsid_val[1] = makefstype(MOUNT_NTFS); mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0]; mp->mnt_stat.f_namemax = NTFS_MAXFILENAME; mp->mnt_flag |= MNT_LOCAL; spec_node_setmountedfs(devvp, mp); return (0); out1: for(i=0;i<NTFS_SYSNODESNUM;i++) if(ntmp->ntm_sysvn[i]) vrele(ntmp->ntm_sysvn[i]); if (vflush(mp,NULLVP,0)) { dprintf(("ntfs_mountfs: vflush failed\n")); } out: spec_node_setmountedfs(devvp, NULL); if (bp) brelse(bp, 0); if (error) { if (ntmp) { if (ntmp->ntm_ad) free(ntmp->ntm_ad, M_NTFSMNT); free(ntmp, M_NTFSMNT); } } return (error); }