1/* $NetBSD: ntfs_vfsops.c,v 1.23 1999/11/15 19:38:14 jdolecek Exp $ */ 2 3/*- 4 * Copyright (c) 1998, 1999 Semen Ustimenko 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $FreeBSD$ 29 */ 30 31 32#include <sys/param.h> 33#include <sys/systm.h> 34#include <sys/namei.h> 35#include <sys/conf.h> 36#include <sys/priv.h> 37#include <sys/proc.h> 38#include <sys/kernel.h> 39#include <sys/vnode.h> 40#include <sys/mount.h> 41#include <sys/bio.h> 42#include <sys/buf.h> 43#include <sys/fcntl.h> 44#include <sys/malloc.h> 45#include <sys/stat.h> 46#include <sys/systm.h> 47 48#include <geom/geom.h> 49#include <geom/geom_vfs.h> 50 51#include <vm/vm.h> 52#include <vm/vm_param.h> 53#include <vm/vm_page.h> 54#include <vm/vm_object.h> 55#include <vm/vm_extern.h> 56 57/*#define NTFS_DEBUG 1*/ 58#include <fs/ntfs/ntfs.h> 59#include <fs/ntfs/ntfs_inode.h> 60#include <fs/ntfs/ntfs_subr.h> 61#include <fs/ntfs/ntfs_vfsops.h> 62#include <fs/ntfs/ntfs_ihash.h> 63#include <fs/ntfs/ntfsmount.h> 64 65static MALLOC_DEFINE(M_NTFSMNT, "ntfs_mount", "NTFS mount structure"); 66MALLOC_DEFINE(M_NTFSNTNODE,"ntfs_ntnode", "NTFS ntnode information"); 67MALLOC_DEFINE(M_NTFSFNODE,"ntfs_fnode", "NTFS fnode information"); 68MALLOC_DEFINE(M_NTFSDIR,"ntfs_dir", "NTFS dir buffer"); 69 70static int ntfs_mountfs(register struct vnode *, struct mount *, 71 struct thread *); 72static int ntfs_calccfree(struct ntfsmount *ntmp, cn_t *cfreep); 73 74static vfs_init_t ntfs_init; 75static vfs_uninit_t ntfs_uninit; 76static vfs_vget_t ntfs_vget; 77static vfs_fhtovp_t ntfs_fhtovp; 78static vfs_cmount_t ntfs_cmount; 79static vfs_mount_t ntfs_mount; 80static vfs_root_t ntfs_root; 81static vfs_statfs_t ntfs_statfs; 82static vfs_unmount_t ntfs_unmount; 83 84static b_strategy_t ntfs_bufstrategy; 85 86/* 87 * Buffer operations for NTFS vnodes. 88 * We punt on VOP_BMAP, so we need to do 89 * strategy on the file's vnode rather 90 * than the underlying device's 91 */ 92static struct buf_ops ntfs_vnbufops = { 93 .bop_name = "NTFS", 94 .bop_strategy = ntfs_bufstrategy, 95}; 96 97static int 98ntfs_init ( 99 struct vfsconf *vcp ) 100{ 101 ntfs_nthashinit(); 102 ntfs_toupper_init(); 103 return 0; 104} 105 106static int 107ntfs_uninit ( 108 struct vfsconf *vcp ) 109{ 110 ntfs_toupper_destroy(); 111 ntfs_nthashdestroy(); 112 return 0; 113} 114 115static int 116ntfs_cmount ( 117 struct mntarg *ma, 118 void *data, 119 uint64_t flags) 120{ 121 struct ntfs_args args; 122 struct export_args exp; 123 int error; 124 125 error = copyin(data, &args, sizeof(args)); 126 if (error) 127 return (error); 128 vfs_oexport_conv(&args.export, &exp); 129 ma = mount_argsu(ma, "from", args.fspec, MAXPATHLEN); 130 ma = mount_arg(ma, "export", &exp, sizeof(exp)); 131 ma = mount_argf(ma, "uid", "%d", args.uid); 132 ma = mount_argf(ma, "gid", "%d", args.gid); 133 ma = mount_argf(ma, "mode", "%d", args.mode); 134 ma = mount_argb(ma, args.flag & NTFS_MFLAG_CASEINS, "nocaseins"); 135 ma = mount_argb(ma, args.flag & NTFS_MFLAG_ALLNAMES, "noallnames"); 136 if (args.flag & NTFS_MFLAG_KICONV) { 137 ma = mount_argsu(ma, "cs_ntfs", args.cs_ntfs, 64); 138 ma = mount_argsu(ma, "cs_local", args.cs_local, 64); 139 } 140 141 error = kernel_mount(ma, flags); 142 143 return (error); 144} 145 146static const char *ntfs_opts[] = { 147 "from", "export", "uid", "gid", "mode", "caseins", "allnames", 148 "kiconv", "cs_ntfs", "cs_local", NULL 149}; 150 151static int 152ntfs_mount(struct mount *mp) 153{ 154 int err = 0, error; 155 accmode_t accmode; 156 struct vnode *devvp; 157 struct nameidata ndp; 158 struct thread *td; 159 char *from; 160 161 td = curthread; 162 if (vfs_filteropt(mp->mnt_optnew, ntfs_opts)) 163 return (EINVAL); 164 165 from = vfs_getopts(mp->mnt_optnew, "from", &error); 166 if (error) 167 return (error); 168 169 /* 170 * If updating, check whether changing from read-only to 171 * read/write. 172 */ 173 if (mp->mnt_flag & MNT_UPDATE) { 174 if (vfs_flagopt(mp->mnt_optnew, "export", NULL, 0)) { 175 /* Process export requests in vfs_mount.c */ 176 goto success; 177 } else { 178 printf("ntfs_mount(): MNT_UPDATE not supported\n"); 179 err = EINVAL; 180 goto error_1; 181 } 182 } 183 184 /* 185 * Not an update, or updating the name: look up the name 186 * and verify that it refers to a sensible block device. 187 */ 188 NDINIT(&ndp, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, from, td); 189 err = namei(&ndp); 190 if (err) { 191 /* can't get devvp!*/ 192 goto error_1; 193 } 194 NDFREE(&ndp, NDF_ONLY_PNBUF); 195 devvp = ndp.ni_vp; 196 197 if (!vn_isdisk(devvp, &err)) { 198 vput(devvp); 199 return (err); 200 } 201 202 /* 203 * If mount by non-root, then verify that user has necessary 204 * permissions on the device. 205 */ 206 accmode = VREAD; 207 if ((mp->mnt_flag & MNT_RDONLY) == 0) 208 accmode |= VWRITE; 209 err = VOP_ACCESS(devvp, accmode, td->td_ucred, td); 210 if (err) 211 err = priv_check(td, PRIV_VFS_MOUNT_PERM); 212 if (err) { 213 vput(devvp); 214 return (err); 215 } 216 217 if (mp->mnt_flag & MNT_UPDATE) { 218#if 0 219 /* 220 ******************** 221 * UPDATE 222 ******************** 223 */ 224 225 if (devvp != ntmp->um_devvp) 226 err = EINVAL; /* needs translation */ 227 vput(devvp); 228 if (err) 229 return (err); 230#endif 231 } else { 232 /* 233 ******************** 234 * NEW MOUNT 235 ******************** 236 */ 237 238 /* 239 * Since this is a new mount, we want the names for 240 * the device and the mount point copied in. If an 241 * error occurs, the mountpoint is discarded by the 242 * upper level code. Note that vfs_mount() handles 243 * copying the mountpoint f_mntonname for us, so we 244 * don't have to do it here unless we want to set it 245 * to something other than "path" for some rason. 246 */ 247 /* Save "mounted from" info for mount point (NULL pad)*/ 248 vfs_mountedfrom(mp, from); 249 250 err = ntfs_mountfs(devvp, mp, td); 251 } 252 if (err) { 253 vrele(devvp); 254 return (err); 255 } 256 257 goto success; 258 259error_1: /* no state to back out*/ 260 /* XXX: missing NDFREE(&ndp, ...) */ 261 262success: 263 return (err); 264} 265 266/* 267 * Common code for mount and mountroot 268 */ 269int 270ntfs_mountfs(devvp, mp, td) 271 register struct vnode *devvp; 272 struct mount *mp; 273 struct thread *td; 274{ 275 struct buf *bp; 276 struct ntfsmount *ntmp; 277 struct cdev *dev = devvp->v_rdev; 278 int error, ronly, i, v; 279 struct vnode *vp; 280 struct g_consumer *cp; 281 struct g_provider *pp; 282 char *cs_ntfs, *cs_local; 283 284 ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 285 DROP_GIANT(); 286 g_topology_lock(); 287 288 /* 289 * XXX: Do not allow more than one consumer to open a device 290 * associated with a particular GEOM provider. 291 * This disables multiple read-only mounts of a device, 292 * but it gets rid of panics in vget() when you try to 293 * mount the same device more than once. 294 */ 295 pp = g_dev_getprovider(devvp->v_rdev); 296 if ((pp != NULL) && ((pp->acr | pp->acw | pp->ace ) != 0)) 297 error = EPERM; 298 else 299 error = g_vfs_open(devvp, &cp, "ntfs", ronly ? 0 : 1); 300 301 g_topology_unlock(); 302 PICKUP_GIANT(); 303 VOP_UNLOCK(devvp, 0); 304 if (error) 305 return (error); 306 307 bp = NULL; 308 309 error = bread(devvp, BBLOCK, BBSIZE, NOCRED, &bp); 310 if (error) 311 goto out; 312 ntmp = malloc( sizeof *ntmp, M_NTFSMNT, M_WAITOK | M_ZERO); 313 bcopy( bp->b_data, &ntmp->ntm_bootfile, sizeof(struct bootfile) ); 314 /* 315 * We must not cache the boot block if its size is not exactly 316 * one cluster in order to avoid confusing the buffer cache when 317 * the boot file is read later by ntfs_readntvattr_plain(), which 318 * reads a cluster at a time. 319 */ 320 if (ntfs_cntob(1) != BBSIZE) 321 bp->b_flags |= B_NOCACHE; 322 brelse( bp ); 323 bp = NULL; 324 325 if (strncmp((const char *)ntmp->ntm_bootfile.bf_sysid, NTFS_BBID, NTFS_BBIDLEN)) { 326 error = EINVAL; 327 dprintf(("ntfs_mountfs: invalid boot block\n")); 328 goto out; 329 } 330 331 { 332 int8_t cpr = ntmp->ntm_mftrecsz; 333 if( cpr > 0 ) 334 ntmp->ntm_bpmftrec = ntmp->ntm_spc * cpr; 335 else 336 ntmp->ntm_bpmftrec = (1 << (-cpr)) / ntmp->ntm_bps; 337 } 338 ntmp->ntm_multiplier = ntmp->ntm_bps / DEV_BSIZE; 339 340 dprintf(("ntfs_mountfs(): bps: %d, spc: %d, media: %x, mftrecsz: %d (%d sects)\n", 341 ntmp->ntm_bps,ntmp->ntm_spc,ntmp->ntm_bootfile.bf_media, 342 ntmp->ntm_mftrecsz,ntmp->ntm_bpmftrec)); 343 dprintf(("ntfs_mountfs(): mftcn: 0x%x|0x%x\n", 344 (u_int32_t)ntmp->ntm_mftcn,(u_int32_t)ntmp->ntm_mftmirrcn)); 345 346 ntmp->ntm_mountp = mp; 347 ntmp->ntm_devvp = devvp; 348 if (vfs_scanopt(mp->mnt_optnew, "uid", "%d", &v) == 1) 349 ntmp->ntm_uid = v; 350 if (vfs_scanopt(mp->mnt_optnew, "gid", "%d", &v) == 1) 351 ntmp->ntm_gid = v; 352 if (vfs_scanopt(mp->mnt_optnew, "mode", "%d", &v) == 1) 353 ntmp->ntm_mode = v & ACCESSPERMS; 354 vfs_flagopt(mp->mnt_optnew, 355 "caseins", &ntmp->ntm_flag, NTFS_MFLAG_CASEINS); 356 vfs_flagopt(mp->mnt_optnew, 357 "allnames", &ntmp->ntm_flag, NTFS_MFLAG_ALLNAMES); 358 ntmp->ntm_cp = cp; 359 ntmp->ntm_bo = &devvp->v_bufobj; 360 361 cs_local = vfs_getopts(mp->mnt_optnew, "cs_local", &error); 362 if (error && error != ENOENT) 363 goto out; 364 cs_ntfs = vfs_getopts(mp->mnt_optnew, "cs_ntfs", &error); 365 if (error && error != ENOENT) 366 goto out; 367 /* Copy in the 8-bit to Unicode conversion table */ 368 /* Initialize Unicode to 8-bit table from 8toU table */ 369 ntfs_82u_init(ntmp, cs_local, cs_ntfs); 370 if (cs_local != NULL && cs_ntfs != NULL) 371 ntfs_u28_init(ntmp, NULL, cs_local, cs_ntfs); 372 else 373 ntfs_u28_init(ntmp, ntmp->ntm_82u, cs_local, cs_ntfs); 374 375 mp->mnt_data = ntmp; 376 377 dprintf(("ntfs_mountfs(): case-%s,%s uid: %d, gid: %d, mode: %o\n", 378 (ntmp->ntm_flag & NTFS_MFLAG_CASEINS)?"insens.":"sens.", 379 (ntmp->ntm_flag & NTFS_MFLAG_ALLNAMES)?" allnames,":"", 380 ntmp->ntm_uid, ntmp->ntm_gid, ntmp->ntm_mode)); 381 382 /* 383 * We read in some system nodes to do not allow 384 * reclaim them and to have everytime access to them. 385 */ 386 { 387 int pi[3] = { NTFS_MFTINO, NTFS_ROOTINO, NTFS_BITMAPINO }; 388 for (i=0; i<3; i++) { 389 error = VFS_VGET(mp, pi[i], LK_EXCLUSIVE, 390 &(ntmp->ntm_sysvn[pi[i]])); 391 if(error) 392 goto out1; 393 ntmp->ntm_sysvn[pi[i]]->v_vflag |= VV_SYSTEM; 394 VREF(ntmp->ntm_sysvn[pi[i]]); 395 vput(ntmp->ntm_sysvn[pi[i]]); 396 } 397 } 398 399 /* read the Unicode lowercase --> uppercase translation table, 400 * if necessary */ 401 if ((error = ntfs_toupper_use(mp, ntmp))) 402 goto out1; 403 404 /* 405 * Scan $BitMap and count free clusters 406 */ 407 error = ntfs_calccfree(ntmp, &ntmp->ntm_cfree); 408 if(error) 409 goto out1; 410 411 /* 412 * Read and translate to internal format attribute 413 * definition file. 414 */ 415 { 416 int num,j; 417 struct attrdef ad; 418 419 /* Open $AttrDef */ 420 error = VFS_VGET(mp, NTFS_ATTRDEFINO, LK_EXCLUSIVE, &vp ); 421 if(error) 422 goto out1; 423 424 /* Count valid entries */ 425 for(num=0;;num++) { 426 error = ntfs_readattr(ntmp, VTONT(vp), 427 NTFS_A_DATA, NULL, 428 num * sizeof(ad), sizeof(ad), 429 &ad, NULL); 430 if (error) 431 goto out1; 432 if (ad.ad_name[0] == 0) 433 break; 434 } 435 436 /* Alloc memory for attribute definitions */ 437 ntmp->ntm_ad = malloc(num * sizeof(struct ntvattrdef), 438 M_NTFSMNT, M_WAITOK); 439 440 ntmp->ntm_adnum = num; 441 442 /* Read them and translate */ 443 for(i=0;i<num;i++){ 444 error = ntfs_readattr(ntmp, VTONT(vp), 445 NTFS_A_DATA, NULL, 446 i * sizeof(ad), sizeof(ad), 447 &ad, NULL); 448 if (error) 449 goto out1; 450 j = 0; 451 do { 452 ntmp->ntm_ad[i].ad_name[j] = ad.ad_name[j]; 453 } while(ad.ad_name[j++]); 454 ntmp->ntm_ad[i].ad_namelen = j - 1; 455 ntmp->ntm_ad[i].ad_type = ad.ad_type; 456 } 457 458 vput(vp); 459 } 460 461 mp->mnt_stat.f_fsid.val[0] = dev2udev(dev); 462 mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; 463 mp->mnt_maxsymlinklen = 0; 464 MNT_ILOCK(mp); 465 mp->mnt_flag |= MNT_LOCAL; 466 MNT_IUNLOCK(mp); 467 return (0); 468 469out1: 470 for(i=0;i<NTFS_SYSNODESNUM;i++) 471 if(ntmp->ntm_sysvn[i]) vrele(ntmp->ntm_sysvn[i]); 472 473 if (vflush(mp, 0, 0, td)) 474 dprintf(("ntfs_mountfs: vflush failed\n")); 475 476out: 477 if (bp) 478 brelse(bp); 479 480 DROP_GIANT(); 481 g_topology_lock(); 482 g_vfs_close(cp); 483 g_topology_unlock(); 484 PICKUP_GIANT(); 485 486 return (error); 487} 488 489static int 490ntfs_unmount( 491 struct mount *mp, 492 int mntflags) 493{ 494 struct thread *td; 495 struct ntfsmount *ntmp; 496 int error, flags, i; 497 498 dprintf(("ntfs_unmount: unmounting...\n")); 499 td = curthread; 500 ntmp = VFSTONTFS(mp); 501 502 flags = 0; 503 if(mntflags & MNT_FORCE) 504 flags |= FORCECLOSE; 505 506 dprintf(("ntfs_unmount: vflushing...\n")); 507 error = vflush(mp, 0, flags | SKIPSYSTEM, td); 508 if (error) { 509 printf("ntfs_unmount: vflush failed: %d\n",error); 510 return (error); 511 } 512 513 /* Check if only system vnodes are rest */ 514 for(i=0;i<NTFS_SYSNODESNUM;i++) 515 if((ntmp->ntm_sysvn[i]) && 516 (vrefcnt(ntmp->ntm_sysvn[i]) > 1)) return (EBUSY); 517 518 /* Dereference all system vnodes */ 519 for(i=0;i<NTFS_SYSNODESNUM;i++) 520 if(ntmp->ntm_sysvn[i]) vrele(ntmp->ntm_sysvn[i]); 521 522 /* vflush system vnodes */ 523 error = vflush(mp, 0, flags, td); 524 if (error) 525 printf("ntfs_unmount: vflush failed(sysnodes): %d\n",error); 526 527 vinvalbuf(ntmp->ntm_devvp, V_SAVE, 0, 0); 528 529 DROP_GIANT(); 530 g_topology_lock(); 531 g_vfs_close(ntmp->ntm_cp); 532 g_topology_unlock(); 533 PICKUP_GIANT(); 534 535 vrele(ntmp->ntm_devvp); 536 537 /* free the toupper table, if this has been last mounted ntfs volume */ 538 ntfs_toupper_unuse(); 539 540 dprintf(("ntfs_umount: freeing memory...\n")); 541 ntfs_u28_uninit(ntmp); 542 ntfs_82u_uninit(ntmp); 543 mp->mnt_data = NULL; 544 MNT_ILOCK(mp); 545 mp->mnt_flag &= ~MNT_LOCAL; 546 MNT_IUNLOCK(mp); 547 free(ntmp->ntm_ad, M_NTFSMNT); 548 free(ntmp, M_NTFSMNT); 549 return (error); 550} 551 552static int 553ntfs_root( 554 struct mount *mp, 555 int flags, 556 struct vnode **vpp) 557{ 558 struct vnode *nvp; 559 int error = 0; 560 561 dprintf(("ntfs_root(): sysvn: %p\n", 562 VFSTONTFS(mp)->ntm_sysvn[NTFS_ROOTINO])); 563 error = VFS_VGET(mp, (ino_t)NTFS_ROOTINO, LK_EXCLUSIVE, &nvp); 564 if(error) { 565 printf("ntfs_root: VFS_VGET failed: %d\n",error); 566 return (error); 567 } 568 569 *vpp = nvp; 570 return (0); 571} 572 573static int 574ntfs_calccfree( 575 struct ntfsmount *ntmp, 576 cn_t *cfreep) 577{ 578 struct vnode *vp; 579 u_int8_t *tmp; 580 int j, error; 581 long cfree = 0; 582 size_t bmsize, i; 583 584 vp = ntmp->ntm_sysvn[NTFS_BITMAPINO]; 585 586 bmsize = VTOF(vp)->f_size; 587 588 tmp = malloc(bmsize, M_TEMP, M_WAITOK); 589 590 error = ntfs_readattr(ntmp, VTONT(vp), NTFS_A_DATA, NULL, 591 0, bmsize, tmp, NULL); 592 if (error) 593 goto out; 594 595 for(i=0;i<bmsize;i++) 596 for(j=0;j<8;j++) 597 if(~tmp[i] & (1 << j)) cfree++; 598 *cfreep = cfree; 599 600 out: 601 free(tmp, M_TEMP); 602 return(error); 603} 604 605static int 606ntfs_statfs( 607 struct mount *mp, 608 struct statfs *sbp) 609{ 610 struct ntfsmount *ntmp = VFSTONTFS(mp); 611 u_int64_t mftsize,mftallocated; 612 613 dprintf(("ntfs_statfs():\n")); 614 615 mftsize = VTOF(ntmp->ntm_sysvn[NTFS_MFTINO])->f_size; 616 mftallocated = VTOF(ntmp->ntm_sysvn[NTFS_MFTINO])->f_allocated; 617 618 sbp->f_type = mp->mnt_vfc->vfc_typenum; 619 sbp->f_bsize = ntmp->ntm_bps; 620 sbp->f_iosize = ntmp->ntm_bps * ntmp->ntm_spc; 621 sbp->f_blocks = ntmp->ntm_bootfile.bf_spv; 622 sbp->f_bfree = sbp->f_bavail = ntfs_cntobn(ntmp->ntm_cfree); 623 sbp->f_ffree = sbp->f_bfree / ntmp->ntm_bpmftrec; 624 sbp->f_files = mftallocated / ntfs_bntob(ntmp->ntm_bpmftrec) + 625 sbp->f_ffree; 626 sbp->f_flags = mp->mnt_flag; 627 628 return (0); 629} 630 631/*ARGSUSED*/ 632static int 633ntfs_fhtovp( 634 struct mount *mp, 635 struct fid *fhp, 636 int flags, 637 struct vnode **vpp) 638{ 639 struct vnode *nvp; 640 struct ntfid *ntfhp = (struct ntfid *)fhp; 641 int error; 642 643 ddprintf(("ntfs_fhtovp(): %d\n", ntfhp->ntfid_ino)); 644 645 if ((error = VFS_VGET(mp, ntfhp->ntfid_ino, LK_EXCLUSIVE, &nvp)) != 0) { 646 *vpp = NULLVP; 647 return (error); 648 } 649 /* XXX as unlink/rmdir/mkdir/creat are not currently possible 650 * with NTFS, we don't need to check anything else for now */ 651 *vpp = nvp; 652 vnode_create_vobject(nvp, VTOF(nvp)->f_size, curthread); 653 return (0); 654} 655 656int 657ntfs_vgetex( 658 struct mount *mp, 659 ino_t ino, 660 u_int32_t attrtype, 661 char *attrname, 662 u_long lkflags, 663 u_long flags, 664 struct thread *td, 665 struct vnode **vpp) 666{ 667 int error; 668 register struct ntfsmount *ntmp; 669 struct ntnode *ip; 670 struct fnode *fp; 671 struct vnode *vp; 672 enum vtype f_type; 673 674 dprintf(("ntfs_vgetex: ino: %d, attr: 0x%x:%s, lkf: 0x%lx, f: 0x%lx\n", 675 ino, attrtype, attrname?attrname:"", (u_long)lkflags, 676 (u_long)flags)); 677 678 ntmp = VFSTONTFS(mp); 679 *vpp = NULL; 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_DONTLOADIN) && !(ip->i_flag & IN_LOADED)) { 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 return (error); 696 } 697 } 698 699 error = ntfs_fget(ntmp, ip, attrtype, attrname, &fp); 700 if (error) { 701 printf("ntfs_vget: ntfs_fget failed\n"); 702 ntfs_ntput(ip); 703 return (error); 704 } 705 706 f_type = VNON; 707 if (!(flags & VG_DONTVALIDFN) && !(fp->f_flag & FN_VALID)) { 708 if ((ip->i_frflag & NTFS_FRFLAG_DIR) && 709 (fp->f_attrtype == NTFS_A_DATA && fp->f_attrname == NULL)) { 710 f_type = VDIR; 711 } else if (flags & VG_EXT) { 712 f_type = VNON; 713 fp->f_size = fp->f_allocated = 0; 714 } else { 715 f_type = VREG; 716 717 error = ntfs_filesize(ntmp, fp, 718 &fp->f_size, &fp->f_allocated); 719 if (error) { 720 ntfs_ntput(ip); 721 return (error); 722 } 723 } 724 725 fp->f_flag |= FN_VALID; 726 } 727 728 if (FTOV(fp)) { 729 vget(FTOV(fp), lkflags, td); 730 *vpp = FTOV(fp); 731 ntfs_ntput(ip); 732 return (0); 733 } 734 735 error = getnewvnode("ntfs", ntmp->ntm_mountp, &ntfs_vnodeops, &vp); 736 if(error) { 737 ntfs_frele(fp); 738 ntfs_ntput(ip); 739 return (error); 740 } 741 /* XXX: Too early for mpsafe fs, lacks vnode lock */ 742 error = insmntque(vp, ntmp->ntm_mountp); 743 if (error) { 744 ntfs_frele(fp); 745 ntfs_ntput(ip); 746 return (error); 747 } 748 dprintf(("ntfs_vget: vnode: %p for ntnode: %d\n", vp,ino)); 749 750 fp->f_vp = vp; 751 vp->v_data = fp; 752 vp->v_type = f_type; 753 754 vp->v_bufobj.bo_ops = &ntfs_vnbufops; 755 vp->v_bufobj.bo_private = vp; 756 757 if (ino == NTFS_ROOTINO) 758 vp->v_vflag |= VV_ROOT; 759 760 ntfs_ntput(ip); 761 762 if (lkflags & LK_TYPE_MASK) { 763 error = vn_lock(vp, lkflags); 764 if (error) { 765 vput(vp); 766 return (error); 767 } 768 } 769 770 *vpp = vp; 771 return (0); 772 773} 774 775static int 776ntfs_vget( 777 struct mount *mp, 778 ino_t ino, 779 int lkflags, 780 struct vnode **vpp) 781{ 782 return ntfs_vgetex(mp, ino, NTFS_A_DATA, NULL, lkflags, 0, 783 curthread, vpp); 784} 785 786static void 787ntfs_bufstrategy(struct bufobj *bo, struct buf *bp) 788{ 789 struct vnode *vp; 790 int rc; 791 792 vp = bo->bo_private; 793 KASSERT(bo == &vp->v_bufobj, ("BO/VP mismatch: vp %p bo %p != %p", 794 vp, &vp->v_bufobj, bo)); 795 rc = VOP_STRATEGY(vp, bp); 796 KASSERT(rc == 0, ("NTFS VOP_STRATEGY failed: bp=%p, " 797 "vp=%p, rc=%d", bp, vp, rc)); 798} 799 800static struct vfsops ntfs_vfsops = { 801 .vfs_fhtovp = ntfs_fhtovp, 802 .vfs_init = ntfs_init, 803 .vfs_cmount = ntfs_cmount, 804 .vfs_mount = ntfs_mount, 805 .vfs_root = ntfs_root, 806 .vfs_statfs = ntfs_statfs, 807 .vfs_uninit = ntfs_uninit, 808 .vfs_unmount = ntfs_unmount, 809 .vfs_vget = ntfs_vget, 810}; 811VFS_SET(ntfs_vfsops, ntfs, 0); 812MODULE_VERSION(ntfs, 1); 813