1 /*- 2 * Copyright (c) 1994 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley 6 * by Pace Willisson (pace@blitz.com). The Rock Ridge Extension 7 * Support code is derived from software contributed to Berkeley 8 * by Atsushi Murai (amurai@spec.co.jp). 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 4. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * @(#)cd9660_vfsops.c 8.18 (Berkeley) 5/22/95 35 */ 36 37 #include <sys/cdefs.h> 38 __FBSDID("$FreeBSD$"); 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/namei.h> 43 #include <sys/priv.h> 44 #include <sys/proc.h> 45 #include <sys/kernel.h> 46 #include <sys/vnode.h> 47 #include <sys/mount.h> 48 #include <sys/bio.h> 49 #include <sys/buf.h> 50 #include <sys/cdio.h> 51 #include <sys/conf.h> 52 #include <sys/fcntl.h> 53 #include <sys/malloc.h> 54 #include <sys/stat.h> 55 #include <sys/syslog.h> 56 #include <sys/iconv.h> 57 58 #include <fs/cd9660/iso.h> 59 #include <fs/cd9660/iso_rrip.h> 60 #include <fs/cd9660/cd9660_node.h> 61 #include <fs/cd9660/cd9660_mount.h> 62 63 #include <geom/geom.h> 64 #include <geom/geom_vfs.h> 65 66 MALLOC_DEFINE(M_ISOFSMNT, "isofs_mount", "ISOFS mount structure"); 67 MALLOC_DEFINE(M_ISOFSNODE, "isofs_node", "ISOFS vnode private part"); 68 69 struct iconv_functions *cd9660_iconv = NULL; 70 71 static vfs_mount_t cd9660_mount; 72 static vfs_cmount_t cd9660_cmount; 73 static vfs_unmount_t cd9660_unmount; 74 static vfs_root_t cd9660_root; 75 static vfs_statfs_t cd9660_statfs; 76 static vfs_vget_t cd9660_vget; 77 static vfs_fhtovp_t cd9660_fhtovp; 78 79 static struct vfsops cd9660_vfsops = { 80 .vfs_fhtovp = cd9660_fhtovp, 81 .vfs_mount = cd9660_mount, 82 .vfs_cmount = cd9660_cmount, 83 .vfs_root = cd9660_root, 84 .vfs_statfs = cd9660_statfs, 85 .vfs_unmount = cd9660_unmount, 86 .vfs_vget = cd9660_vget, 87 }; 88 VFS_SET(cd9660_vfsops, cd9660, VFCF_READONLY); 89 MODULE_VERSION(cd9660, 1); 90 91 static int iso_mountfs(struct vnode *devvp, struct mount *mp, 92 struct thread *td); 93 94 /* 95 * VFS Operations. 96 */ 97 98 static int 99 cd9660_cmount(struct mntarg *ma, void *data, int flags, struct thread *td) 100 { 101 struct iso_args args; 102 int error; 103 104 error = copyin(data, &args, sizeof args); 105 if (error) 106 return (error); 107 108 ma = mount_argsu(ma, "from", args.fspec, MAXPATHLEN); 109 ma = mount_arg(ma, "export", &args.export, sizeof args.export); 110 ma = mount_argsu(ma, "cs_disk", args.cs_disk, 64); 111 ma = mount_argsu(ma, "cs_local", args.cs_local, 64); 112 ma = mount_argf(ma, "ssector", "%u", args.ssector); 113 ma = mount_argb(ma, !(args.flags & ISOFSMNT_NORRIP), "norrip"); 114 ma = mount_argb(ma, args.flags & ISOFSMNT_GENS, "nogens"); 115 ma = mount_argb(ma, args.flags & ISOFSMNT_EXTATT, "noextatt"); 116 ma = mount_argb(ma, !(args.flags & ISOFSMNT_NOJOLIET), "nojoliet"); 117 ma = mount_argb(ma, 118 args.flags & ISOFSMNT_BROKENJOLIET, "nobrokenjoliet"); 119 ma = mount_argb(ma, args.flags & ISOFSMNT_KICONV, "nokiconv"); 120 121 error = kernel_mount(ma, flags); 122 123 return (error); 124 } 125 126 static int 127 cd9660_mount(struct mount *mp, struct thread *td) 128 { 129 struct vnode *devvp; 130 char *fspec; 131 int error; 132 mode_t accessmode; 133 struct nameidata ndp; 134 struct iso_mnt *imp = 0; 135 136 /* 137 * Unconditionally mount as read-only. 138 */ 139 MNT_ILOCK(mp); 140 mp->mnt_flag |= MNT_RDONLY; 141 MNT_IUNLOCK(mp); 142 143 fspec = vfs_getopts(mp->mnt_optnew, "from", &error); 144 if (error) 145 return (error); 146 147 imp = VFSTOISOFS(mp); 148 149 if (mp->mnt_flag & MNT_UPDATE) { 150 if (vfs_flagopt(mp->mnt_optnew, "export", NULL, 0)) 151 return (0); 152 } 153 /* 154 * Not an update, or updating the name: look up the name 155 * and verify that it refers to a sensible block device. 156 */ 157 NDINIT(&ndp, LOOKUP, FOLLOW, UIO_SYSSPACE, fspec, td); 158 if ((error = namei(&ndp))) 159 return (error); 160 NDFREE(&ndp, NDF_ONLY_PNBUF); 161 devvp = ndp.ni_vp; 162 163 if (!vn_isdisk(devvp, &error)) { 164 vrele(devvp); 165 return (error); 166 } 167 168 /* 169 * Verify that user has necessary permissions on the device, 170 * or has superuser abilities 171 */ 172 accessmode = VREAD; 173 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td); 174 error = VOP_ACCESS(devvp, accessmode, td->td_ucred, td); 175 if (error) 176 error = priv_check(td, PRIV_VFS_MOUNT_PERM); 177 if (error) { 178 vput(devvp); 179 return (error); 180 } 181 VOP_UNLOCK(devvp, 0, td); 182 183 if ((mp->mnt_flag & MNT_UPDATE) == 0) { 184 error = iso_mountfs(devvp, mp, td); 185 } else { 186 if (devvp != imp->im_devvp) 187 error = EINVAL; /* needs translation */ 188 else 189 vrele(devvp); 190 } 191 if (error) { 192 vrele(devvp); 193 return error; 194 } 195 vfs_mountedfrom(mp, fspec); 196 return 0; 197 } 198 199 /* 200 * Common code for mount and mountroot 201 */ 202 static int 203 iso_mountfs(devvp, mp, td) 204 struct vnode *devvp; 205 struct mount *mp; 206 struct thread *td; 207 { 208 struct iso_mnt *isomp = (struct iso_mnt *)0; 209 struct buf *bp = NULL; 210 struct buf *pribp = NULL, *supbp = NULL; 211 struct cdev *dev = devvp->v_rdev; 212 int error = EINVAL; 213 int high_sierra = 0; 214 int iso_bsize; 215 int iso_blknum; 216 int joliet_level; 217 struct iso_volume_descriptor *vdp = 0; 218 struct iso_primary_descriptor *pri = NULL; 219 struct iso_sierra_primary_descriptor *pri_sierra = NULL; 220 struct iso_supplementary_descriptor *sup = NULL; 221 struct iso_directory_record *rootp; 222 int logical_block_size, ssector; 223 struct g_consumer *cp; 224 struct bufobj *bo; 225 char *cs_local, *cs_disk; 226 227 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td); 228 DROP_GIANT(); 229 g_topology_lock(); 230 error = g_vfs_open(devvp, &cp, "cd9660", 0); 231 g_topology_unlock(); 232 PICKUP_GIANT(); 233 VOP_UNLOCK(devvp, 0, td); 234 if (error) 235 return error; 236 if (devvp->v_rdev->si_iosize_max != 0) 237 mp->mnt_iosize_max = devvp->v_rdev->si_iosize_max; 238 if (mp->mnt_iosize_max > MAXPHYS) 239 mp->mnt_iosize_max = MAXPHYS; 240 241 bo = &devvp->v_bufobj; 242 bo->bo_private = cp; 243 bo->bo_ops = g_vfs_bufops; 244 245 /* This is the "logical sector size". The standard says this 246 * should be 2048 or the physical sector size on the device, 247 * whichever is greater. 248 */ 249 if ((ISO_DEFAULT_BLOCK_SIZE % cp->provider->sectorsize) != 0) { 250 DROP_GIANT(); 251 g_topology_lock(); 252 g_vfs_close(cp, td); 253 g_topology_unlock(); 254 PICKUP_GIANT(); 255 return (EINVAL); 256 } 257 258 iso_bsize = cp->provider->sectorsize; 259 260 joliet_level = 0; 261 if (1 != vfs_scanopt(mp->mnt_optnew, "ssector", "%d", &ssector)) 262 ssector = 0; 263 for (iso_blknum = 16 + ssector; 264 iso_blknum < 100 + ssector; 265 iso_blknum++) { 266 if ((error = bread(devvp, iso_blknum * btodb(ISO_DEFAULT_BLOCK_SIZE), 267 iso_bsize, NOCRED, &bp)) != 0) 268 goto out; 269 270 vdp = (struct iso_volume_descriptor *)bp->b_data; 271 if (bcmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) != 0) { 272 if (bcmp (vdp->id_sierra, ISO_SIERRA_ID, 273 sizeof vdp->id) != 0) { 274 error = EINVAL; 275 goto out; 276 } else 277 high_sierra = 1; 278 } 279 switch (isonum_711 (high_sierra? vdp->type_sierra: vdp->type)){ 280 case ISO_VD_PRIMARY: 281 if (pribp == NULL) { 282 pribp = bp; 283 bp = NULL; 284 pri = (struct iso_primary_descriptor *)vdp; 285 pri_sierra = 286 (struct iso_sierra_primary_descriptor *)vdp; 287 } 288 break; 289 290 case ISO_VD_SUPPLEMENTARY: 291 if (supbp == NULL) { 292 supbp = bp; 293 bp = NULL; 294 sup = (struct iso_supplementary_descriptor *)vdp; 295 296 if (!vfs_flagopt(mp->mnt_optnew, "nojoliet", NULL, 0)) { 297 if (bcmp(sup->escape, "%/@", 3) == 0) 298 joliet_level = 1; 299 if (bcmp(sup->escape, "%/C", 3) == 0) 300 joliet_level = 2; 301 if (bcmp(sup->escape, "%/E", 3) == 0) 302 joliet_level = 3; 303 304 if ((isonum_711 (sup->flags) & 1) && 305 !vfs_flagopt(mp->mnt_optnew, "brokenjoliet", NULL, 0)) 306 joliet_level = 0; 307 } 308 } 309 break; 310 311 case ISO_VD_END: 312 goto vd_end; 313 314 default: 315 break; 316 } 317 if (bp) { 318 brelse(bp); 319 bp = NULL; 320 } 321 } 322 vd_end: 323 if (bp) { 324 brelse(bp); 325 bp = NULL; 326 } 327 328 if (pri == NULL) { 329 error = EINVAL; 330 goto out; 331 } 332 333 logical_block_size = 334 isonum_723 (high_sierra? 335 pri_sierra->logical_block_size: 336 pri->logical_block_size); 337 338 if (logical_block_size < DEV_BSIZE || logical_block_size > MAXBSIZE 339 || (logical_block_size & (logical_block_size - 1)) != 0) { 340 error = EINVAL; 341 goto out; 342 } 343 344 rootp = (struct iso_directory_record *) 345 (high_sierra? 346 pri_sierra->root_directory_record: 347 pri->root_directory_record); 348 349 isomp = malloc(sizeof *isomp, M_ISOFSMNT, M_WAITOK | M_ZERO); 350 isomp->im_cp = cp; 351 isomp->im_bo = bo; 352 isomp->logical_block_size = logical_block_size; 353 isomp->volume_space_size = 354 isonum_733 (high_sierra? 355 pri_sierra->volume_space_size: 356 pri->volume_space_size); 357 isomp->joliet_level = 0; 358 /* 359 * Since an ISO9660 multi-session CD can also access previous 360 * sessions, we have to include them into the space consider- 361 * ations. This doesn't yield a very accurate number since 362 * parts of the old sessions might be inaccessible now, but we 363 * can't do much better. This is also important for the NFS 364 * filehandle validation. 365 */ 366 isomp->volume_space_size += ssector; 367 bcopy (rootp, isomp->root, sizeof isomp->root); 368 isomp->root_extent = isonum_733 (rootp->extent); 369 isomp->root_size = isonum_733 (rootp->size); 370 371 isomp->im_bmask = logical_block_size - 1; 372 isomp->im_bshift = ffs(logical_block_size) - 1; 373 374 pribp->b_flags |= B_AGE; 375 brelse(pribp); 376 pribp = NULL; 377 378 mp->mnt_data = isomp; 379 mp->mnt_stat.f_fsid.val[0] = dev2udev(dev); 380 mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; 381 mp->mnt_maxsymlinklen = 0; 382 MNT_ILOCK(mp); 383 mp->mnt_flag |= MNT_LOCAL; 384 MNT_IUNLOCK(mp); 385 isomp->im_mountp = mp; 386 isomp->im_dev = dev; 387 isomp->im_devvp = devvp; 388 389 vfs_flagopt(mp->mnt_optnew, "norrip", &isomp->im_flags, ISOFSMNT_NORRIP); 390 vfs_flagopt(mp->mnt_optnew, "gens", &isomp->im_flags, ISOFSMNT_GENS); 391 vfs_flagopt(mp->mnt_optnew, "extatt", &isomp->im_flags, ISOFSMNT_EXTATT); 392 vfs_flagopt(mp->mnt_optnew, "nojoliet", &isomp->im_flags, ISOFSMNT_NOJOLIET); 393 vfs_flagopt(mp->mnt_optnew, "kiconv", &isomp->im_flags, ISOFSMNT_KICONV); 394 395 /* Check the Rock Ridge Extension support */ 396 if (!(isomp->im_flags & ISOFSMNT_NORRIP)) { 397 if ((error = bread(isomp->im_devvp, 398 (isomp->root_extent + isonum_711(rootp->ext_attr_length)) << 399 (isomp->im_bshift - DEV_BSHIFT), 400 isomp->logical_block_size, NOCRED, &bp)) != 0) 401 goto out; 402 403 rootp = (struct iso_directory_record *)bp->b_data; 404 405 if ((isomp->rr_skip = cd9660_rrip_offset(rootp,isomp)) < 0) { 406 isomp->im_flags |= ISOFSMNT_NORRIP; 407 } else { 408 isomp->im_flags &= ~ISOFSMNT_GENS; 409 } 410 411 /* 412 * The contents are valid, 413 * but they will get reread as part of another vnode, so... 414 */ 415 bp->b_flags |= B_AGE; 416 brelse(bp); 417 bp = NULL; 418 } 419 420 if (isomp->im_flags & ISOFSMNT_KICONV && cd9660_iconv) { 421 cs_local = vfs_getopts(mp->mnt_optnew, "cs_local", &error); 422 if (error) 423 goto out; 424 cs_disk = vfs_getopts(mp->mnt_optnew, "cs_disk", &error); 425 if (error) 426 goto out; 427 cd9660_iconv->open(cs_local, cs_disk, &isomp->im_d2l); 428 cd9660_iconv->open(cs_disk, cs_local, &isomp->im_l2d); 429 } else { 430 isomp->im_d2l = NULL; 431 isomp->im_l2d = NULL; 432 } 433 434 if (high_sierra) { 435 /* this effectively ignores all the mount flags */ 436 if (bootverbose) 437 log(LOG_INFO, "cd9660: High Sierra Format\n"); 438 isomp->iso_ftype = ISO_FTYPE_HIGH_SIERRA; 439 } else 440 switch (isomp->im_flags&(ISOFSMNT_NORRIP|ISOFSMNT_GENS)) { 441 default: 442 isomp->iso_ftype = ISO_FTYPE_DEFAULT; 443 break; 444 case ISOFSMNT_GENS|ISOFSMNT_NORRIP: 445 isomp->iso_ftype = ISO_FTYPE_9660; 446 break; 447 case 0: 448 if (bootverbose) 449 log(LOG_INFO, "cd9660: RockRidge Extension\n"); 450 isomp->iso_ftype = ISO_FTYPE_RRIP; 451 break; 452 } 453 454 /* Decide whether to use the Joliet descriptor */ 455 456 if (isomp->iso_ftype != ISO_FTYPE_RRIP && joliet_level) { 457 if (bootverbose) 458 log(LOG_INFO, "cd9660: Joliet Extension (Level %d)\n", 459 joliet_level); 460 rootp = (struct iso_directory_record *) 461 sup->root_directory_record; 462 bcopy (rootp, isomp->root, sizeof isomp->root); 463 isomp->root_extent = isonum_733 (rootp->extent); 464 isomp->root_size = isonum_733 (rootp->size); 465 isomp->joliet_level = joliet_level; 466 supbp->b_flags |= B_AGE; 467 } 468 469 if (supbp) { 470 brelse(supbp); 471 supbp = NULL; 472 } 473 474 return 0; 475 out: 476 if (bp) 477 brelse(bp); 478 if (pribp) 479 brelse(pribp); 480 if (supbp) 481 brelse(supbp); 482 if (cp != NULL) { 483 DROP_GIANT(); 484 g_topology_lock(); 485 g_vfs_close(cp, td); 486 g_topology_unlock(); 487 PICKUP_GIANT(); 488 } 489 if (isomp) { 490 free((caddr_t)isomp, M_ISOFSMNT); 491 mp->mnt_data = NULL; 492 } 493 return error; 494 } 495 496 /* 497 * unmount system call 498 */ 499 static int 500 cd9660_unmount(mp, mntflags, td) 501 struct mount *mp; 502 int mntflags; 503 struct thread *td; 504 { 505 struct iso_mnt *isomp; 506 int error, flags = 0; 507 508 if (mntflags & MNT_FORCE) 509 flags |= FORCECLOSE; 510 #if 0 511 mntflushbuf(mp, 0); 512 if (mntinvalbuf(mp)) 513 return EBUSY; 514 #endif 515 if ((error = vflush(mp, 0, flags, td))) 516 return (error); 517 518 isomp = VFSTOISOFS(mp); 519 520 if (isomp->im_flags & ISOFSMNT_KICONV && cd9660_iconv) { 521 if (isomp->im_d2l) 522 cd9660_iconv->close(isomp->im_d2l); 523 if (isomp->im_l2d) 524 cd9660_iconv->close(isomp->im_l2d); 525 } 526 DROP_GIANT(); 527 g_topology_lock(); 528 g_vfs_close(isomp->im_cp, td); 529 g_topology_unlock(); 530 PICKUP_GIANT(); 531 vrele(isomp->im_devvp); 532 free((caddr_t)isomp, M_ISOFSMNT); 533 mp->mnt_data = NULL; 534 MNT_ILOCK(mp); 535 mp->mnt_flag &= ~MNT_LOCAL; 536 MNT_IUNLOCK(mp); 537 return (error); 538 } 539 540 /* 541 * Return root of a filesystem 542 */ 543 static int 544 cd9660_root(mp, flags, vpp, td) 545 struct mount *mp; 546 int flags; 547 struct vnode **vpp; 548 struct thread *td; 549 { 550 struct iso_mnt *imp = VFSTOISOFS(mp); 551 struct iso_directory_record *dp = 552 (struct iso_directory_record *)imp->root; 553 ino_t ino = isodirino(dp, imp); 554 555 /* 556 * With RRIP we must use the `.' entry of the root directory. 557 * Simply tell vget, that it's a relocated directory. 558 */ 559 return (cd9660_vget_internal(mp, ino, LK_EXCLUSIVE, vpp, 560 imp->iso_ftype == ISO_FTYPE_RRIP, dp)); 561 } 562 563 /* 564 * Get filesystem statistics. 565 */ 566 static int 567 cd9660_statfs(mp, sbp, td) 568 struct mount *mp; 569 struct statfs *sbp; 570 struct thread *td; 571 { 572 struct iso_mnt *isomp; 573 574 isomp = VFSTOISOFS(mp); 575 576 sbp->f_bsize = isomp->logical_block_size; 577 sbp->f_iosize = sbp->f_bsize; /* XXX */ 578 sbp->f_blocks = isomp->volume_space_size; 579 sbp->f_bfree = 0; /* total free blocks */ 580 sbp->f_bavail = 0; /* blocks free for non superuser */ 581 sbp->f_files = 0; /* total files */ 582 sbp->f_ffree = 0; /* free file nodes */ 583 return 0; 584 } 585 586 /* 587 * File handle to vnode 588 * 589 * Have to be really careful about stale file handles: 590 * - check that the inode number is in range 591 * - call iget() to get the locked inode 592 * - check for an unallocated inode (i_mode == 0) 593 * - check that the generation number matches 594 */ 595 596 /* ARGSUSED */ 597 static int 598 cd9660_fhtovp(mp, fhp, vpp) 599 struct mount *mp; 600 struct fid *fhp; 601 struct vnode **vpp; 602 { 603 struct ifid *ifhp = (struct ifid *)fhp; 604 struct iso_node *ip; 605 struct vnode *nvp; 606 int error; 607 608 #ifdef ISOFS_DBG 609 printf("fhtovp: ino %d, start %ld\n", 610 ifhp->ifid_ino, ifhp->ifid_start); 611 #endif 612 613 if ((error = VFS_VGET(mp, ifhp->ifid_ino, LK_EXCLUSIVE, &nvp)) != 0) { 614 *vpp = NULLVP; 615 return (error); 616 } 617 ip = VTOI(nvp); 618 if (ip->inode.iso_mode == 0) { 619 vput(nvp); 620 *vpp = NULLVP; 621 return (ESTALE); 622 } 623 *vpp = nvp; 624 vnode_create_vobject(*vpp, ip->i_size, curthread); 625 return (0); 626 } 627 628 static int 629 cd9660_vget(mp, ino, flags, vpp) 630 struct mount *mp; 631 ino_t ino; 632 int flags; 633 struct vnode **vpp; 634 { 635 636 /* 637 * XXXX 638 * It would be nice if we didn't always set the `relocated' flag 639 * and force the extra read, but I don't want to think about fixing 640 * that right now. 641 */ 642 return (cd9660_vget_internal(mp, ino, flags, vpp, 643 #if 0 644 VFSTOISOFS(mp)->iso_ftype == ISO_FTYPE_RRIP, 645 #else 646 0, 647 #endif 648 (struct iso_directory_record *)0)); 649 } 650 651 int 652 cd9660_vget_internal(mp, ino, flags, vpp, relocated, isodir) 653 struct mount *mp; 654 ino_t ino; 655 int flags; 656 struct vnode **vpp; 657 int relocated; 658 struct iso_directory_record *isodir; 659 { 660 struct iso_mnt *imp; 661 struct iso_node *ip; 662 struct buf *bp; 663 struct vnode *vp; 664 struct cdev *dev; 665 int error; 666 struct thread *td; 667 668 td = curthread; 669 error = vfs_hash_get(mp, ino, flags, td, vpp, NULL, NULL); 670 if (error || *vpp != NULL) 671 return (error); 672 673 imp = VFSTOISOFS(mp); 674 dev = imp->im_dev; 675 676 /* Allocate a new vnode/iso_node. */ 677 if ((error = getnewvnode("isofs", mp, &cd9660_vnodeops, &vp)) != 0) { 678 *vpp = NULLVP; 679 return (error); 680 } 681 MALLOC(ip, struct iso_node *, sizeof(struct iso_node), M_ISOFSNODE, 682 M_WAITOK | M_ZERO); 683 vp->v_data = ip; 684 ip->i_vnode = vp; 685 ip->i_number = ino; 686 687 lockmgr(vp->v_vnlock, LK_EXCLUSIVE, NULL, td); 688 error = insmntque(vp, mp); 689 if (error != 0) { 690 free(ip, M_ISOFSNODE); 691 *vpp = NULLVP; 692 return (error); 693 } 694 error = vfs_hash_insert(vp, ino, flags, td, vpp, NULL, NULL); 695 if (error || *vpp != NULL) 696 return (error); 697 698 if (isodir == 0) { 699 int lbn, off; 700 701 lbn = lblkno(imp, ino); 702 if (lbn >= imp->volume_space_size) { 703 vput(vp); 704 printf("fhtovp: lbn exceed volume space %d\n", lbn); 705 return (ESTALE); 706 } 707 708 off = blkoff(imp, ino); 709 if (off + ISO_DIRECTORY_RECORD_SIZE > imp->logical_block_size) { 710 vput(vp); 711 printf("fhtovp: crosses block boundary %d\n", 712 off + ISO_DIRECTORY_RECORD_SIZE); 713 return (ESTALE); 714 } 715 716 error = bread(imp->im_devvp, 717 lbn << (imp->im_bshift - DEV_BSHIFT), 718 imp->logical_block_size, NOCRED, &bp); 719 if (error) { 720 vput(vp); 721 brelse(bp); 722 printf("fhtovp: bread error %d\n",error); 723 return (error); 724 } 725 isodir = (struct iso_directory_record *)(bp->b_data + off); 726 727 if (off + isonum_711(isodir->length) > 728 imp->logical_block_size) { 729 vput(vp); 730 if (bp != 0) 731 brelse(bp); 732 printf("fhtovp: directory crosses block boundary %d[off=%d/len=%d]\n", 733 off +isonum_711(isodir->length), off, 734 isonum_711(isodir->length)); 735 return (ESTALE); 736 } 737 738 #if 0 739 if (isonum_733(isodir->extent) + 740 isonum_711(isodir->ext_attr_length) != ifhp->ifid_start) { 741 if (bp != 0) 742 brelse(bp); 743 printf("fhtovp: file start miss %d vs %d\n", 744 isonum_733(isodir->extent) + isonum_711(isodir->ext_attr_length), 745 ifhp->ifid_start); 746 return (ESTALE); 747 } 748 #endif 749 } else 750 bp = 0; 751 752 ip->i_mnt = imp; 753 VREF(imp->im_devvp); 754 755 if (relocated) { 756 /* 757 * On relocated directories we must 758 * read the `.' entry out of a dir. 759 */ 760 ip->iso_start = ino >> imp->im_bshift; 761 if (bp != 0) 762 brelse(bp); 763 if ((error = cd9660_blkatoff(vp, (off_t)0, NULL, &bp)) != 0) { 764 vput(vp); 765 return (error); 766 } 767 isodir = (struct iso_directory_record *)bp->b_data; 768 } 769 770 ip->iso_extent = isonum_733(isodir->extent); 771 ip->i_size = isonum_733(isodir->size); 772 ip->iso_start = isonum_711(isodir->ext_attr_length) + ip->iso_extent; 773 774 /* 775 * Setup time stamp, attribute 776 */ 777 vp->v_type = VNON; 778 switch (imp->iso_ftype) { 779 default: /* ISO_FTYPE_9660 */ 780 { 781 struct buf *bp2; 782 int off; 783 if ((imp->im_flags & ISOFSMNT_EXTATT) 784 && (off = isonum_711(isodir->ext_attr_length))) 785 cd9660_blkatoff(vp, (off_t)-(off << imp->im_bshift), NULL, 786 &bp2); 787 else 788 bp2 = NULL; 789 cd9660_defattr(isodir, ip, bp2, ISO_FTYPE_9660); 790 cd9660_deftstamp(isodir, ip, bp2, ISO_FTYPE_9660); 791 if (bp2) 792 brelse(bp2); 793 break; 794 } 795 case ISO_FTYPE_RRIP: 796 cd9660_rrip_analyze(isodir, ip, imp); 797 break; 798 } 799 800 if (bp != 0) 801 brelse(bp); 802 803 /* 804 * Initialize the associated vnode 805 */ 806 switch (vp->v_type = IFTOVT(ip->inode.iso_mode)) { 807 case VFIFO: 808 vp->v_op = &cd9660_fifoops; 809 break; 810 default: 811 break; 812 } 813 814 if (ip->iso_extent == imp->root_extent) 815 vp->v_vflag |= VV_ROOT; 816 817 /* 818 * XXX need generation number? 819 */ 820 821 *vpp = vp; 822 return (0); 823 } 824