| File: | ntfs/ntfs_vfsops.c |
| Warning: | line 758, column 13 Assigned value is garbage or undefined |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: ntfs_vfsops.c,v 1.65 2022/01/11 03:13:59 jsg 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 | |||
| 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)((struct ntfsmount *)((mp)->mnt_data)); | |||
| 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((void *)0)) | |||
| 96 | return (EACCES13); | |||
| 97 | ||||
| 98 | *exflagsp = np->netc_exflags; | |||
| 99 | *credanonp = &np->netc_anon; | |||
| 100 | return (0); | |||
| 101 | } | |||
| 102 | ||||
| 103 | int | |||
| 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 (EINVAL22); | |||
| 108 | } | |||
| 109 | ||||
| 110 | int | |||
| 111 | ntfs_init(struct vfsconf *vcp) | |||
| 112 | { | |||
| 113 | return 0; | |||
| 114 | } | |||
| 115 | ||||
| 116 | int | |||
| 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[MNAMELEN90]; | |||
| 124 | char fspec[MNAMELEN90]; | |||
| 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_UPDATE0x00010000) { | |||
| 139 | /* if not updating name...*/ | |||
| 140 | if (args && args->fspec == NULL((void *)0)) { | |||
| 141 | /* | |||
| 142 | * Process export requests. Jumping to "success" | |||
| 143 | * will return the vfs_export() error code. | |||
| 144 | */ | |||
| 145 | struct ntfsmount *ntm = VFSTONTFS(mp)((struct ntfsmount *)((mp)->mnt_data)); | |||
| 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 = EINVAL22; | |||
| 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((void *)0)); | |||
| 160 | if (err) | |||
| 161 | goto error_1; | |||
| 162 | ||||
| 163 | if (disk_map(fspec, fname, sizeof(fname), DM_OPENBLCK0x2) == -1) | |||
| 164 | bcopy(fspec, fname, sizeof(fname)); | |||
| 165 | ||||
| 166 | NDINIT(ndp, LOOKUP, FOLLOW, UIO_SYSSPACE, fname, p)ndinitat(ndp, 0, 0x0040, UIO_SYSSPACE, -100, 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 = ENOTBLK15; | |||
| 177 | goto error_2; | |||
| 178 | } | |||
| 179 | ||||
| 180 | if (major(devvp->v_rdev)(((unsigned)(devvp->v_un.vu_specinfo->si_rdev) >> 8) & 0xff) >= nblkdev) { | |||
| 181 | err = ENXIO6; | |||
| 182 | goto error_2; | |||
| 183 | } | |||
| 184 | ||||
| 185 | if (mp->mnt_flag & MNT_UPDATE0x00010000) { | |||
| 186 | #if 0 | |||
| 187 | /* | |||
| 188 | ******************** | |||
| 189 | * UPDATE | |||
| 190 | ******************** | |||
| 191 | */ | |||
| 192 | ||||
| 193 | if (devvp != ntmp->um_devvp) | |||
| 194 | err = EINVAL22; /* 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((void *)0), 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)__builtin_bzero((mp->mnt_stat.f_mntonname), (90)); | |||
| 220 | strlcpy(mp->mnt_stat.f_mntonname, path, MNAMELEN90); | |||
| 221 | bzero(mp->mnt_stat.f_mntfromname, MNAMELEN)__builtin_bzero((mp->mnt_stat.f_mntfromname), (90)); | |||
| 222 | strlcpy(mp->mnt_stat.f_mntfromname, fname, MNAMELEN90); | |||
| 223 | bzero(mp->mnt_stat.f_mntfromspec, MNAMELEN)__builtin_bzero((mp->mnt_stat.f_mntfromspec), (90)); | |||
| 224 | strlcpy(mp->mnt_stat.f_mntfromspec, fspec, MNAMELEN90); | |||
| 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)(*(mp)->mnt_op->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 | |||
| 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((void *)0); | |||
| 265 | dev_t dev = devvp->v_rdevv_un.vu_specinfo->si_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 (EBUSY16); | |||
| 281 | vn_lock(devvp, LK_EXCLUSIVE0x0001UL | LK_RETRY0x2000UL); | |||
| 282 | error = vinvalbuf(devvp, V_SAVE0x0001, p->p_ucred, p, 0, INFSLP0xffffffffffffffffULL); | |||
| 283 | VOP_UNLOCK(devvp); | |||
| 284 | if (error) | |||
| 285 | return (error); | |||
| 286 | ||||
| 287 | error = VOP_OPEN(devvp, FREAD0x0001, FSCRED((struct ucred *)-2), p); | |||
| 288 | if (error) | |||
| 289 | return (error); | |||
| 290 | ||||
| 291 | bp = NULL((void *)0); | |||
| 292 | ||||
| 293 | error = bread(devvp, BBLOCK0, BBSIZE1024, &bp); | |||
| 294 | if (error) | |||
| 295 | goto out; | |||
| 296 | ntmp = malloc(sizeof *ntmp, M_NTFSMNT128, M_WAITOK0x0001 | M_ZERO0x0008); | |||
| 297 | bcopy(bp->b_data, &ntmp->ntm_bootfile, sizeof(struct bootfile)); | |||
| 298 | brelse(bp); | |||
| 299 | bp = NULL((void *)0); | |||
| 300 | ||||
| 301 | if (strncmp(ntmp->ntm_bootfile.bf_sysid, NTFS_BBID"NTFS ", NTFS_BBIDLEN8)) { | |||
| 302 | error = EINVAL22; | |||
| 303 | DPRINTF("ntfs_mountfs: invalid boot block\n"); | |||
| 304 | goto out; | |||
| 305 | } | |||
| 306 | ||||
| 307 | { | |||
| 308 | int8_t cpr = ntmp->ntm_mftrecszntm_bootfile.bf_mftrecsz; | |||
| 309 | if( cpr > 0 ) | |||
| 310 | ntmp->ntm_bpmftrec = ntmp->ntm_spcntm_bootfile.bf_spc * cpr; | |||
| 311 | else | |||
| 312 | ntmp->ntm_bpmftrec = (1 << (-cpr)) / ntmp->ntm_bpsntm_bootfile.bf_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)do { (&ntmp->ntm_ntnodeq)->tqh_first = ((void *)0); (&ntmp->ntm_ntnodeq)->tqh_last = &(&ntmp-> ntm_ntnodeq)->tqh_first; } while (0); | |||
| 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 everytime access to them. | |||
| 344 | */ | |||
| 345 | { | |||
| 346 | int pi[3] = { NTFS_MFTINO0, NTFS_ROOTINO5, NTFS_BITMAPINO6 }; | |||
| 347 | for (i=0; i<3; i++) { | |||
| 348 | error = VFS_VGET(mp, pi[i], &(ntmp->ntm_sysvn[pi[i]]))(*(mp)->mnt_op->vfs_vget)(mp, pi[i], &(ntmp->ntm_sysvn [pi[i]])); | |||
| 349 | if(error) | |||
| 350 | goto out1; | |||
| 351 | ntmp->ntm_sysvn[pi[i]]->v_flag |= VSYSTEM0x0004; | |||
| 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 )(*(mp)->mnt_op->vfs_vget)(mp, 4, &vp); | |||
| 379 | if(error) | |||
| 380 | goto out1; | |||
| 381 | ||||
| 382 | /* Count valid entries */ | |||
| 383 | for(num = 0; ; num++) { | |||
| 384 | error = ntfs_readattr(ntmp, VTONT(vp)((((struct fnode *)((vp)->v_data)))->f_ip), | |||
| 385 | NTFS_A_DATA0x80, NULL((void *)0), num * sizeof(ad), sizeof(ad), | |||
| 386 | &ad, NULL((void *)0)); | |||
| 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_NTFSMNT128, M_WAITOK0x0001); | |||
| 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)((((struct fnode *)((vp)->v_data)))->f_ip), | |||
| 402 | NTFS_A_DATA0x80, NULL((void *)0), i * sizeof(ad), sizeof(ad), | |||
| 403 | &ad, NULL((void *)0)); | |||
| 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_MAXFILENAME255; | |||
| 420 | mp->mnt_flag |= MNT_LOCAL0x00001000; | |||
| 421 | devvp->v_specmountpointv_un.vu_specinfo->si_mountpoint = mp; | |||
| 422 | return (0); | |||
| 423 | ||||
| 424 | out1: | |||
| 425 | for (i = 0; i < NTFS_SYSNODESNUM0x0B; i++) | |||
| 426 | if (ntmp->ntm_sysvn[i]) | |||
| 427 | vrele(ntmp->ntm_sysvn[i]); | |||
| 428 | ||||
| 429 | if (vflush(mp,NULLVP((struct vnode *)((void *)0)),0)) | |||
| 430 | DPRINTF("ntfs_mountfs: vflush failed\n"); | |||
| 431 | ||||
| 432 | out: | |||
| 433 | if (devvp->v_specinfov_un.vu_specinfo) | |||
| 434 | devvp->v_specmountpointv_un.vu_specinfo->si_mountpoint = NULL((void *)0); | |||
| 435 | if (bp) | |||
| 436 | brelse(bp); | |||
| 437 | ||||
| 438 | if (ntmp != NULL((void *)0)) { | |||
| 439 | if (ntmp->ntm_ad != NULL((void *)0)) | |||
| 440 | free(ntmp->ntm_ad, M_NTFSMNT128, 0); | |||
| 441 | free(ntmp, M_NTFSMNT128, 0); | |||
| 442 | mp->mnt_data = NULL((void *)0); | |||
| 443 | } | |||
| 444 | ||||
| 445 | /* lock the device vnode before calling VOP_CLOSE() */ | |||
| 446 | vn_lock(devvp, LK_EXCLUSIVE0x0001UL | LK_RETRY0x2000UL); | |||
| 447 | (void)VOP_CLOSE(devvp, FREAD0x0001, NOCRED((struct ucred *)-1), p); | |||
| 448 | VOP_UNLOCK(devvp); | |||
| 449 | ||||
| 450 | return (error); | |||
| 451 | } | |||
| 452 | ||||
| 453 | int | |||
| 454 | ntfs_start(struct mount *mp, int flags, struct proc *p) | |||
| 455 | { | |||
| 456 | return (0); | |||
| 457 | } | |||
| 458 | ||||
| 459 | int | |||
| 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)((struct ntfsmount *)((mp)->mnt_data)); | |||
| 467 | ||||
| 468 | flags = 0; | |||
| 469 | if(mntflags & MNT_FORCE0x00080000) | |||
| 470 | flags |= FORCECLOSE0x0002; | |||
| 471 | ||||
| 472 | DPRINTF("ntfs_unmount: vflushing...\n"); | |||
| 473 | error = vflush(mp,NULLVP((struct vnode *)((void *)0)),flags | SKIPSYSTEM0x0001); | |||
| 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_SYSNODESNUM0x0B;i++) { | |||
| 481 | if(((mntflags & MNT_FORCE0x00080000) == 0) && (ntmp->ntm_sysvn[i] && | |||
| 482 | ntmp->ntm_sysvn[i]->v_usecount > 1)) | |||
| 483 | return (EBUSY16); | |||
| 484 | } | |||
| 485 | ||||
| 486 | /* Dereference all system vnodes */ | |||
| 487 | for(i=0;i<NTFS_SYSNODESNUM0x0B;i++) | |||
| 488 | if(ntmp->ntm_sysvn[i]) vrele(ntmp->ntm_sysvn[i]); | |||
| 489 | ||||
| 490 | /* vflush system vnodes */ | |||
| 491 | error = vflush(mp,NULLVP((struct vnode *)((void *)0)),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_specmountpointv_un.vu_specinfo->si_mountpoint = NULL((void *)0); | |||
| 503 | ||||
| 504 | /* lock the device vnode before calling VOP_CLOSE() */ | |||
| 505 | vn_lock(ntmp->ntm_devvp, LK_EXCLUSIVE0x0001UL | LK_RETRY0x2000UL); | |||
| 506 | vinvalbuf(ntmp->ntm_devvp, V_SAVE0x0001, NOCRED((struct ucred *)-1), p, 0, INFSLP0xffffffffffffffffULL); | |||
| 507 | (void)VOP_CLOSE(ntmp->ntm_devvp, FREAD0x0001, NOCRED((struct ucred *)-1), 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_NTFSMNT128, 0); | |||
| 515 | free(ntmp, M_NTFSMNT128, 0); | |||
| 516 | mp->mnt_data = NULL((void *)0); | |||
| 517 | mp->mnt_flag &= ~MNT_LOCAL0x00001000; | |||
| 518 | return (0); | |||
| 519 | } | |||
| 520 | ||||
| 521 | int | |||
| 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)(*(mp)->mnt_op->vfs_vget)(mp, (ino_t)5, &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 | |||
| 543 | ntfs_quotactl(struct mount *mp, int cmds, uid_t uid, caddr_t arg, | |||
| 544 | struct proc *p) | |||
| 545 | { | |||
| 546 | return EOPNOTSUPP45; | |||
| 547 | } | |||
| 548 | ||||
| 549 | int | |||
| 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_BITMAPINO6]; | |||
| 560 | ||||
| 561 | bmsize = VTOF(vp)((struct fnode *)((vp)->v_data))->f_size; | |||
| 562 | ||||
| 563 | if (bmsize > 1024 * 1024) | |||
| 564 | chunksize = 1024 * 1024; | |||
| 565 | else | |||
| 566 | chunksize = bmsize; | |||
| 567 | ||||
| 568 | tmp = malloc(chunksize, M_TEMP127, M_WAITOK0x0001); | |||
| 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)((((struct fnode *)((vp)->v_data)))->f_ip), NTFS_A_DATA0x80, NULL((void *)0), | |||
| 575 | offset, chunksize, tmp, NULL((void *)0)); | |||
| 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_TEMP127, 0); | |||
| 589 | return(error); | |||
| 590 | } | |||
| 591 | ||||
| 592 | int | |||
| 593 | ntfs_statfs(struct mount *mp, struct statfs *sbp, struct proc *p) | |||
| 594 | { | |||
| 595 | struct ntfsmount *ntmp = VFSTONTFS(mp)((struct ntfsmount *)((mp)->mnt_data)); | |||
| 596 | u_int64_t mftallocated; | |||
| 597 | ||||
| 598 | DPRINTF("ntfs_statfs():\n"); | |||
| 599 | ||||
| 600 | mftallocated = VTOF(ntmp->ntm_sysvn[NTFS_MFTINO])((struct fnode *)((ntmp->ntm_sysvn[0])->v_data))->f_allocated; | |||
| 601 | ||||
| 602 | sbp->f_bsize = ntmp->ntm_bpsntm_bootfile.bf_bps; | |||
| 603 | sbp->f_iosize = ntmp->ntm_bpsntm_bootfile.bf_bps * ntmp->ntm_spcntm_bootfile.bf_spc; | |||
| 604 | sbp->f_blocks = ntmp->ntm_bootfile.bf_spv; | |||
| 605 | sbp->f_bfree = sbp->f_bavail = ntfs_cntobn(ntmp->ntm_cfree)(daddr_t)((ntmp->ntm_cfree) * (ntmp->ntm_bootfile.bf_spc )); | |||
| 606 | sbp->f_ffree = sbp->f_favail = sbp->f_bfree / ntmp->ntm_bpmftrec; | |||
| 607 | sbp->f_files = mftallocated / ntfs_bntob(ntmp->ntm_bpmftrec)(int32_t)((ntmp->ntm_bpmftrec) * (ntmp)->ntm_bootfile.bf_bps ) + | |||
| 608 | sbp->f_ffree; | |||
| 609 | copy_statfs_info(sbp, mp); | |||
| 610 | ||||
| 611 | return (0); | |||
| 612 | } | |||
| 613 | ||||
| 614 | int | |||
| 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 | |||
| 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((void *)0), | |||
| ||||
| 631 | LK_EXCLUSIVE0x0001UL | LK_RETRY0x2000UL, 0, vpp); /* XXX */ | |||
| 632 | if (error != 0) { | |||
| 633 | *vpp = NULLVP((struct vnode *)((void *)0)); | |||
| 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 | |||
| 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)((struct fnode *)((vp)->v_data)); | |||
| 653 | ntp = VTONT(vp)((((struct fnode *)((vp)->v_data)))->f_ip); | |||
| 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 | |||
| 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)((struct ntfsmount *)((mp)->mnt_data)); | |||
| 679 | *vpp = NULL((void *)0); | |||
| 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_DONTLOADIN0x0001) && !(ip->i_flag & IN_LOADED0x8000)) { | |||
| 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_DONTVALIDFN0x0002) && !(fp->f_flag & FN_VALID0x0002)) { | |||
| 709 | if ((ip->i_frflag & NTFS_FRFLAG_DIR0x0002) && | |||
| 710 | (fp->f_attrtype == NTFS_A_DATA0x80 && fp->f_attrname == NULL((void *)0))) { | |||
| 711 | f_type = VDIR; | |||
| 712 | } else if (flags & VG_EXT0x0004) { | |||
| 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_VALID0x0002; | |||
| 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)((fp)->f_vp)) { | |||
| 740 | /* vget() returns error if the vnode has been recycled */ | |||
| 741 | if (vget(FTOV(fp)((fp)->f_vp), lkflags) == 0) { | |||
| 742 | *vpp = FTOV(fp)((fp)->f_vp); | |||
| 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_ROOTINO5) | |||
| 761 | vp->v_flag |= VROOT0x0001; | |||
| 762 | ||||
| 763 | if (lkflags & LK_TYPE_MASK(0x0001UL|0x0002UL)) { | |||
| 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 | |||
| 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_DATA0x80, NULL((void *)0), | |||
| 781 | LK_EXCLUSIVE0x0001UL | LK_RETRY0x2000UL, 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 | }; |