44#include <sys/param.h> 45#include <sys/systm.h> 46#include <sys/namei.h> 47#include <sys/proc.h> 48#include <sys/kernel.h> 49#include <sys/vnode.h> 50#include <sys/mount.h> 51#include <sys/bio.h> 52#include <sys/buf.h> 53#include <sys/cdio.h> 54#include <sys/conf.h> 55#include <sys/fcntl.h> 56#include <sys/malloc.h> 57#include <sys/stat.h> 58#include <sys/syslog.h> 59 60 61#include <isofs/cd9660/iso.h> 62#include <isofs/cd9660/iso_rrip.h> 63#include <isofs/cd9660/cd9660_node.h> 64#include <isofs/cd9660/cd9660_mount.h> 65 66MALLOC_DEFINE(M_ISOFSMNT, "ISOFS mount", "ISOFS mount structure"); 67MALLOC_DEFINE(M_ISOFSNODE, "ISOFS node", "ISOFS vnode private part"); 68 69static vfs_mount_t cd9660_mount; 70static vfs_unmount_t cd9660_unmount; 71static vfs_root_t cd9660_root; 72static vfs_statfs_t cd9660_statfs; 73static vfs_vget_t cd9660_vget; 74static vfs_fhtovp_t cd9660_fhtovp; 75static vfs_vptofh_t cd9660_vptofh; 76 77static struct vfsops cd9660_vfsops = { 78 cd9660_mount, 79 vfs_stdstart, 80 cd9660_unmount, 81 cd9660_root, 82 vfs_stdquotactl, 83 cd9660_statfs, 84 vfs_stdnosync, 85 cd9660_vget, 86 cd9660_fhtovp, 87 vfs_stdcheckexp, 88 cd9660_vptofh, 89 cd9660_init, 90 cd9660_uninit, 91 vfs_stdextattrctl, 92}; 93VFS_SET(cd9660_vfsops, cd9660, VFCF_READONLY); 94MODULE_VERSION(cd9660, 1); 95 96 97/* 98 * Called by vfs_mountroot when iso is going to be mounted as root. 99 */ 100 101static int iso_get_ssector(dev_t dev, struct thread *td); 102static int iso_mountfs(struct vnode *devvp, struct mount *mp, 103 struct thread *td, struct iso_args *argp); 104 105/* 106 * Try to find the start of the last data track on this CD-ROM. This 107 * is used to mount the last session of a multi-session CD. Bail out 108 * and return 0 if we fail, this is always a safe bet. 109 */ 110static int 111iso_get_ssector(dev, td) 112 dev_t dev; 113 struct thread *td; 114{ 115 struct ioc_toc_header h; 116 struct ioc_read_toc_single_entry t; 117 int i; 118 struct cdevsw *bd; 119 d_ioctl_t *ioctlp; 120 121 bd = devsw(dev); 122 ioctlp = bd->d_ioctl; 123 if (ioctlp == NULL) 124 return 0; 125 126 if (ioctlp(dev, CDIOREADTOCHEADER, (caddr_t)&h, FREAD, td) != 0) 127 return 0; 128 129 for (i = h.ending_track; i >= 0; i--) { 130 t.address_format = CD_LBA_FORMAT; 131 t.track = i; 132 if (ioctlp(dev, CDIOREADTOCENTRY, (caddr_t)&t, FREAD, td) != 0) 133 return 0; 134 if ((t.entry.control & 4) != 0) 135 /* found a data track */ 136 break; 137 } 138 139 if (i < 0) 140 return 0; 141 142 return ntohl(t.entry.addr.lba); 143} 144 145static int iso_mountroot(struct mount *mp, struct thread *td); 146 147static int 148iso_mountroot(mp, td) 149 struct mount *mp; 150 struct thread *td; 151{ 152 struct iso_args args; 153 int error; 154 155 if ((error = bdevvp(rootdev, &rootvp))) { 156 printf("iso_mountroot: can't find rootvp\n"); 157 return (error); 158 } 159 args.flags = ISOFSMNT_ROOT; 160 161 vn_lock(rootvp, LK_EXCLUSIVE | LK_RETRY, td); 162 error = VOP_OPEN(rootvp, FREAD, FSCRED, td); 163 VOP_UNLOCK(rootvp, 0, td); 164 if (error) 165 return error; 166 167 args.ssector = iso_get_ssector(rootdev, td); 168 169 (void)VOP_CLOSE(rootvp, FREAD, NOCRED, td); 170 171 if (bootverbose) 172 printf("iso_mountroot(): using session at block %d\n", 173 args.ssector); 174 if ((error = iso_mountfs(rootvp, mp, td, &args)) != 0) 175 return (error); 176 177 (void)cd9660_statfs(mp, &mp->mnt_stat, td); 178 return (0); 179} 180 181/* 182 * VFS Operations. 183 * 184 * mount system call 185 */ 186static int 187cd9660_mount(mp, path, data, ndp, td) 188 register struct mount *mp; 189 char *path; 190 caddr_t data; 191 struct nameidata *ndp; 192 struct thread *td; 193{ 194 struct vnode *devvp; 195 struct iso_args args; 196 size_t size; 197 int error; 198 mode_t accessmode; 199 struct iso_mnt *imp = 0; 200 201 if (path == NULL) /* We are doing the initial root mount */ 202 return (iso_mountroot(mp, td)); 203 if ((error = copyin(data, (caddr_t)&args, sizeof (struct iso_args)))) 204 return (error); 205 206 if ((mp->mnt_flag & MNT_RDONLY) == 0) 207 return (EROFS); 208 209 /* 210 * If updating, check whether changing from read-only to 211 * read/write; if there is no device name, that's all we do. 212 */ 213 if (mp->mnt_flag & MNT_UPDATE) { 214 imp = VFSTOISOFS(mp); 215 if (args.fspec == 0) 216 return (vfs_export(mp, &args.export)); 217 } 218 /* 219 * Not an update, or updating the name: look up the name 220 * and verify that it refers to a sensible block device. 221 */ 222 NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, td); 223 if ((error = namei(ndp))) 224 return (error); 225 NDFREE(ndp, NDF_ONLY_PNBUF); 226 devvp = ndp->ni_vp; 227 228 if (!vn_isdisk(devvp, &error)) { 229 vrele(devvp); 230 return (error); 231 } 232 233 /* 234 * Verify that user has necessary permissions on the device, 235 * or has superuser abilities 236 */ 237 accessmode = VREAD; 238 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td); 239 error = VOP_ACCESS(devvp, accessmode, td->td_ucred, td); 240 if (error) 241 error = suser(td); 242 if (error) { 243 vput(devvp); 244 return (error); 245 } 246 VOP_UNLOCK(devvp, 0, td); 247 248 if ((mp->mnt_flag & MNT_UPDATE) == 0) { 249 error = iso_mountfs(devvp, mp, td, &args); 250 } else { 251 if (devvp != imp->im_devvp) 252 error = EINVAL; /* needs translation */ 253 else 254 vrele(devvp); 255 } 256 if (error) { 257 vrele(devvp); 258 return error; 259 } 260 imp = VFSTOISOFS(mp); 261 (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 262 &size); 263 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 264 (void) cd9660_statfs(mp, &mp->mnt_stat, td); 265 return 0; 266} 267 268/* 269 * Common code for mount and mountroot 270 */ 271static int 272iso_mountfs(devvp, mp, td, argp) 273 register struct vnode *devvp; 274 struct mount *mp; 275 struct thread *td; 276 struct iso_args *argp; 277{ 278 register struct iso_mnt *isomp = (struct iso_mnt *)0; 279 struct buf *bp = NULL; 280 struct buf *pribp = NULL, *supbp = NULL; 281 dev_t dev = devvp->v_rdev; 282 int error = EINVAL; 283 int needclose = 0; 284 int high_sierra = 0; 285 int iso_bsize; 286 int iso_blknum; 287 int joliet_level; 288 struct iso_volume_descriptor *vdp = 0; 289 struct iso_primary_descriptor *pri = NULL; 290 struct iso_sierra_primary_descriptor *pri_sierra = NULL; 291 struct iso_supplementary_descriptor *sup = NULL; 292 struct iso_directory_record *rootp; 293 int logical_block_size; 294 295 if (!(mp->mnt_flag & MNT_RDONLY)) 296 return EROFS; 297 298 /* 299 * Disallow multiple mounts of the same device. 300 * Disallow mounting of a device that is currently in use 301 * (except for root, which might share swap device for miniroot). 302 * Flush out any old buffers remaining from a previous use. 303 */ 304 if ((error = vfs_mountedon(devvp))) 305 return error; 306 if (vcount(devvp) > 1 && devvp != rootvp) 307 return EBUSY; 308 if ((error = vinvalbuf(devvp, V_SAVE, td->td_ucred, td, 0, 0))) 309 return (error); 310 311 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td); 312 error = VOP_OPEN(devvp, FREAD, FSCRED, td); 313 VOP_UNLOCK(devvp, 0, td); 314 if (error) 315 return error; 316 if (devvp->v_rdev->si_iosize_max != 0) 317 mp->mnt_iosize_max = devvp->v_rdev->si_iosize_max; 318 if (mp->mnt_iosize_max > MAXPHYS) 319 mp->mnt_iosize_max = MAXPHYS; 320 321 needclose = 1; 322 323 /* This is the "logical sector size". The standard says this 324 * should be 2048 or the physical sector size on the device, 325 * whichever is greater. For now, we'll just use a constant. 326 */ 327 iso_bsize = ISO_DEFAULT_BLOCK_SIZE; 328 329 joliet_level = 0; 330 for (iso_blknum = 16 + argp->ssector; 331 iso_blknum < 100 + argp->ssector; 332 iso_blknum++) { 333 if ((error = bread(devvp, iso_blknum * btodb(iso_bsize), 334 iso_bsize, NOCRED, &bp)) != 0) 335 goto out; 336 337 vdp = (struct iso_volume_descriptor *)bp->b_data; 338 if (bcmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) != 0) { 339 if (bcmp (vdp->id_sierra, ISO_SIERRA_ID, 340 sizeof vdp->id) != 0) { 341 error = EINVAL; 342 goto out; 343 } else 344 high_sierra = 1; 345 } 346 switch (isonum_711 (high_sierra? vdp->type_sierra: vdp->type)){ 347 case ISO_VD_PRIMARY: 348 if (pribp == NULL) { 349 pribp = bp; 350 bp = NULL; 351 pri = (struct iso_primary_descriptor *)vdp; 352 pri_sierra = 353 (struct iso_sierra_primary_descriptor *)vdp; 354 } 355 break; 356 357 case ISO_VD_SUPPLEMENTARY: 358 if (supbp == NULL) { 359 supbp = bp; 360 bp = NULL; 361 sup = (struct iso_supplementary_descriptor *)vdp; 362 363 if (!(argp->flags & ISOFSMNT_NOJOLIET)) { 364 if (bcmp(sup->escape, "%/@", 3) == 0) 365 joliet_level = 1; 366 if (bcmp(sup->escape, "%/C", 3) == 0) 367 joliet_level = 2; 368 if (bcmp(sup->escape, "%/E", 3) == 0) 369 joliet_level = 3; 370 371 if ((isonum_711 (sup->flags) & 1) && 372 (argp->flags & ISOFSMNT_BROKENJOLIET) == 0) 373 joliet_level = 0; 374 } 375 } 376 break; 377 378 case ISO_VD_END: 379 goto vd_end; 380 381 default: 382 break; 383 } 384 if (bp) { 385 brelse(bp); 386 bp = NULL; 387 } 388 } 389 vd_end: 390 if (bp) { 391 brelse(bp); 392 bp = NULL; 393 } 394 395 if (pri == NULL) { 396 error = EINVAL; 397 goto out; 398 } 399 400 logical_block_size = 401 isonum_723 (high_sierra? 402 pri_sierra->logical_block_size: 403 pri->logical_block_size); 404 405 if (logical_block_size < DEV_BSIZE || logical_block_size > MAXBSIZE 406 || (logical_block_size & (logical_block_size - 1)) != 0) { 407 error = EINVAL; 408 goto out; 409 } 410 411 rootp = (struct iso_directory_record *) 412 (high_sierra? 413 pri_sierra->root_directory_record: 414 pri->root_directory_record); 415 416 isomp = malloc(sizeof *isomp, M_ISOFSMNT, M_WAITOK | M_ZERO); 417 isomp->logical_block_size = logical_block_size; 418 isomp->volume_space_size = 419 isonum_733 (high_sierra? 420 pri_sierra->volume_space_size: 421 pri->volume_space_size); 422 isomp->joliet_level = 0; 423 /* 424 * Since an ISO9660 multi-session CD can also access previous 425 * sessions, we have to include them into the space consider- 426 * ations. This doesn't yield a very accurate number since 427 * parts of the old sessions might be inaccessible now, but we 428 * can't do much better. This is also important for the NFS 429 * filehandle validation. 430 */ 431 isomp->volume_space_size += argp->ssector; 432 bcopy (rootp, isomp->root, sizeof isomp->root); 433 isomp->root_extent = isonum_733 (rootp->extent); 434 isomp->root_size = isonum_733 (rootp->size); 435 436 isomp->im_bmask = logical_block_size - 1; 437 isomp->im_bshift = ffs(logical_block_size) - 1; 438 439 pribp->b_flags |= B_AGE; 440 brelse(pribp); 441 pribp = NULL; 442 443 mp->mnt_data = (qaddr_t)isomp; 444 mp->mnt_stat.f_fsid.val[0] = dev2udev(dev); 445 mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; 446 mp->mnt_maxsymlinklen = 0; 447 mp->mnt_flag |= MNT_LOCAL; 448 isomp->im_mountp = mp; 449 isomp->im_dev = dev; 450 isomp->im_devvp = devvp; 451 452 devvp->v_rdev->si_mountpoint = mp; 453 454 /* Check the Rock Ridge Extention support */ 455 if (!(argp->flags & ISOFSMNT_NORRIP)) { 456 if ((error = bread(isomp->im_devvp, 457 (isomp->root_extent + isonum_711(rootp->ext_attr_length)) << 458 (isomp->im_bshift - DEV_BSHIFT), 459 isomp->logical_block_size, NOCRED, &bp)) != 0) 460 goto out; 461 462 rootp = (struct iso_directory_record *)bp->b_data; 463 464 if ((isomp->rr_skip = cd9660_rrip_offset(rootp,isomp)) < 0) { 465 argp->flags |= ISOFSMNT_NORRIP; 466 } else { 467 argp->flags &= ~ISOFSMNT_GENS; 468 } 469 470 /* 471 * The contents are valid, 472 * but they will get reread as part of another vnode, so... 473 */ 474 bp->b_flags |= B_AGE; 475 brelse(bp); 476 bp = NULL; 477 } 478 isomp->im_flags = argp->flags & (ISOFSMNT_NORRIP | ISOFSMNT_GENS | 479 ISOFSMNT_EXTATT | ISOFSMNT_NOJOLIET); 480 481 if (high_sierra) { 482 /* this effectively ignores all the mount flags */ 483 log(LOG_INFO, "cd9660: High Sierra Format\n"); 484 isomp->iso_ftype = ISO_FTYPE_HIGH_SIERRA; 485 } else 486 switch (isomp->im_flags&(ISOFSMNT_NORRIP|ISOFSMNT_GENS)) { 487 default: 488 isomp->iso_ftype = ISO_FTYPE_DEFAULT; 489 break; 490 case ISOFSMNT_GENS|ISOFSMNT_NORRIP: 491 isomp->iso_ftype = ISO_FTYPE_9660; 492 break; 493 case 0: 494 log(LOG_INFO, "cd9660: RockRidge Extension\n"); 495 isomp->iso_ftype = ISO_FTYPE_RRIP; 496 break; 497 } 498 499 /* Decide whether to use the Joliet descriptor */ 500 501 if (isomp->iso_ftype != ISO_FTYPE_RRIP && joliet_level) { 502 log(LOG_INFO, "cd9660: Joliet Extension (Level %d)\n", joliet_level); 503 rootp = (struct iso_directory_record *) 504 sup->root_directory_record; 505 bcopy (rootp, isomp->root, sizeof isomp->root); 506 isomp->root_extent = isonum_733 (rootp->extent); 507 isomp->root_size = isonum_733 (rootp->size); 508 isomp->joliet_level = joliet_level; 509 supbp->b_flags |= B_AGE; 510 } 511 512 if (supbp) { 513 brelse(supbp); 514 supbp = NULL; 515 } 516 517 return 0; 518out: 519 devvp->v_rdev->si_mountpoint = NULL; 520 if (bp) 521 brelse(bp); 522 if (pribp) 523 brelse(pribp); 524 if (supbp) 525 brelse(supbp); 526 if (needclose) 527 (void)VOP_CLOSE(devvp, FREAD, NOCRED, td); 528 if (isomp) { 529 free((caddr_t)isomp, M_ISOFSMNT); 530 mp->mnt_data = (qaddr_t)0; 531 } 532 return error; 533} 534 535/* 536 * unmount system call 537 */ 538static int 539cd9660_unmount(mp, mntflags, td) 540 struct mount *mp; 541 int mntflags; 542 struct thread *td; 543{ 544 register struct iso_mnt *isomp; 545 int error, flags = 0; 546 547 if (mntflags & MNT_FORCE) 548 flags |= FORCECLOSE; 549#if 0 550 mntflushbuf(mp, 0); 551 if (mntinvalbuf(mp)) 552 return EBUSY; 553#endif 554 if ((error = vflush(mp, 0, flags))) 555 return (error); 556 557 isomp = VFSTOISOFS(mp); 558 559 isomp->im_devvp->v_rdev->si_mountpoint = NULL; 560 error = VOP_CLOSE(isomp->im_devvp, FREAD, NOCRED, td); 561 vrele(isomp->im_devvp); 562 free((caddr_t)isomp, M_ISOFSMNT); 563 mp->mnt_data = (qaddr_t)0; 564 mp->mnt_flag &= ~MNT_LOCAL; 565 return (error); 566} 567 568/* 569 * Return root of a filesystem 570 */ 571static int 572cd9660_root(mp, vpp) 573 struct mount *mp; 574 struct vnode **vpp; 575{ 576 struct iso_mnt *imp = VFSTOISOFS(mp); 577 struct iso_directory_record *dp = 578 (struct iso_directory_record *)imp->root; 579 ino_t ino = isodirino(dp, imp); 580 581 /* 582 * With RRIP we must use the `.' entry of the root directory. 583 * Simply tell vget, that it's a relocated directory. 584 */ 585 return (cd9660_vget_internal(mp, ino, LK_EXCLUSIVE, vpp, 586 imp->iso_ftype == ISO_FTYPE_RRIP, dp)); 587} 588 589/* 590 * Get filesystem statistics. 591 */ 592static int 593cd9660_statfs(mp, sbp, td) 594 struct mount *mp; 595 register struct statfs *sbp; 596 struct thread *td; 597{ 598 register struct iso_mnt *isomp; 599 600 isomp = VFSTOISOFS(mp); 601 602 sbp->f_bsize = isomp->logical_block_size; 603 sbp->f_iosize = sbp->f_bsize; /* XXX */ 604 sbp->f_blocks = isomp->volume_space_size; 605 sbp->f_bfree = 0; /* total free blocks */ 606 sbp->f_bavail = 0; /* blocks free for non superuser */ 607 sbp->f_files = 0; /* total files */ 608 sbp->f_ffree = 0; /* free file nodes */ 609 if (sbp != &mp->mnt_stat) { 610 sbp->f_type = mp->mnt_vfc->vfc_typenum; 611 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN); 612 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 613 } 614 return 0; 615} 616 617/* 618 * File handle to vnode 619 * 620 * Have to be really careful about stale file handles: 621 * - check that the inode number is in range 622 * - call iget() to get the locked inode 623 * - check for an unallocated inode (i_mode == 0) 624 * - check that the generation number matches 625 */ 626 627struct ifid { 628 ushort ifid_len; 629 ushort ifid_pad; 630 int ifid_ino; 631 long ifid_start; 632}; 633 634/* ARGSUSED */ 635static int 636cd9660_fhtovp(mp, fhp, vpp) 637 register struct mount *mp; 638 struct fid *fhp; 639 struct vnode **vpp; 640{ 641 struct ifid *ifhp = (struct ifid *)fhp; 642 register struct iso_node *ip; 643 struct vnode *nvp; 644 int error; 645 646#ifdef ISOFS_DBG 647 printf("fhtovp: ino %d, start %ld\n", 648 ifhp->ifid_ino, ifhp->ifid_start); 649#endif 650 651 if ((error = VFS_VGET(mp, ifhp->ifid_ino, LK_EXCLUSIVE, &nvp)) != 0) { 652 *vpp = NULLVP; 653 return (error); 654 } 655 ip = VTOI(nvp); 656 if (ip->inode.iso_mode == 0) { 657 vput(nvp); 658 *vpp = NULLVP; 659 return (ESTALE); 660 } 661 *vpp = nvp; 662 return (0); 663} 664 665static int 666cd9660_vget(mp, ino, flags, vpp) 667 struct mount *mp; 668 ino_t ino; 669 int flags; 670 struct vnode **vpp; 671{ 672 673 /* 674 * XXXX 675 * It would be nice if we didn't always set the `relocated' flag 676 * and force the extra read, but I don't want to think about fixing 677 * that right now. 678 */ 679 return (cd9660_vget_internal(mp, ino, flags, vpp, 680#if 0 681 VFSTOISOFS(mp)->iso_ftype == ISO_FTYPE_RRIP, 682#else 683 0, 684#endif 685 (struct iso_directory_record *)0)); 686} 687 688int 689cd9660_vget_internal(mp, ino, flags, vpp, relocated, isodir) 690 struct mount *mp; 691 ino_t ino; 692 int flags; 693 struct vnode **vpp; 694 int relocated; 695 struct iso_directory_record *isodir; 696{ 697 struct iso_mnt *imp; 698 struct iso_node *ip; 699 struct buf *bp; 700 struct vnode *vp; 701 dev_t dev; 702 int error; 703 704 imp = VFSTOISOFS(mp); 705 dev = imp->im_dev; 706 if ((error = cd9660_ihashget(dev, ino, flags, vpp)) != 0) 707 return (error); 708 if (*vpp != NULL) 709 return (0); 710 711 /* Allocate a new vnode/iso_node. */ 712 if ((error = getnewvnode("isofs", mp, cd9660_vnodeop_p, &vp)) != 0) { 713 *vpp = NULLVP; 714 return (error); 715 } 716 MALLOC(ip, struct iso_node *, sizeof(struct iso_node), M_ISOFSNODE, 717 M_WAITOK | M_ZERO); 718 vp->v_data = ip; 719 ip->i_vnode = vp; 720 ip->i_dev = dev; 721 ip->i_number = ino; 722 723 /* 724 * Check to be sure that it did not show up. We have to put it 725 * on the hash chain as the cleanup from vput expects to find 726 * it there. 727 */ 728 if ((error = cd9660_ihashget(dev, ino, flags, vpp)) != 0 || 729 *vpp != NULL) { 730 cd9660_ihashins(ip); 731 vput(vp); 732 return (error); 733 } 734 735 /* 736 * Put it onto its hash chain and lock it so that other requests for 737 * this inode will block if they arrive while we are sleeping waiting 738 * for old data structures to be purged or for the contents of the 739 * disk portion of this inode to be read. 740 */ 741 cd9660_ihashins(ip); 742 743 if (isodir == 0) { 744 int lbn, off; 745 746 lbn = lblkno(imp, ino); 747 if (lbn >= imp->volume_space_size) { 748 vput(vp); 749 printf("fhtovp: lbn exceed volume space %d\n", lbn); 750 return (ESTALE); 751 } 752 753 off = blkoff(imp, ino); 754 if (off + ISO_DIRECTORY_RECORD_SIZE > imp->logical_block_size) { 755 vput(vp); 756 printf("fhtovp: crosses block boundary %d\n", 757 off + ISO_DIRECTORY_RECORD_SIZE); 758 return (ESTALE); 759 } 760 761 error = bread(imp->im_devvp, 762 lbn << (imp->im_bshift - DEV_BSHIFT), 763 imp->logical_block_size, NOCRED, &bp); 764 if (error) { 765 vput(vp); 766 brelse(bp); 767 printf("fhtovp: bread error %d\n",error); 768 return (error); 769 } 770 isodir = (struct iso_directory_record *)(bp->b_data + off); 771 772 if (off + isonum_711(isodir->length) > 773 imp->logical_block_size) { 774 vput(vp); 775 if (bp != 0) 776 brelse(bp); 777 printf("fhtovp: directory crosses block boundary %d[off=%d/len=%d]\n", 778 off +isonum_711(isodir->length), off, 779 isonum_711(isodir->length)); 780 return (ESTALE); 781 } 782 783#if 0 784 if (isonum_733(isodir->extent) + 785 isonum_711(isodir->ext_attr_length) != ifhp->ifid_start) { 786 if (bp != 0) 787 brelse(bp); 788 printf("fhtovp: file start miss %d vs %d\n", 789 isonum_733(isodir->extent) + isonum_711(isodir->ext_attr_length), 790 ifhp->ifid_start); 791 return (ESTALE); 792 } 793#endif 794 } else 795 bp = 0; 796 797 ip->i_mnt = imp; 798 ip->i_devvp = imp->im_devvp; 799 VREF(ip->i_devvp); 800 801 if (relocated) { 802 /* 803 * On relocated directories we must 804 * read the `.' entry out of a dir. 805 */ 806 ip->iso_start = ino >> imp->im_bshift; 807 if (bp != 0) 808 brelse(bp); 809 if ((error = cd9660_blkatoff(vp, (off_t)0, NULL, &bp)) != 0) { 810 vput(vp); 811 return (error); 812 } 813 isodir = (struct iso_directory_record *)bp->b_data; 814 } 815 816 ip->iso_extent = isonum_733(isodir->extent); 817 ip->i_size = isonum_733(isodir->size); 818 ip->iso_start = isonum_711(isodir->ext_attr_length) + ip->iso_extent; 819 820 /* 821 * Setup time stamp, attribute 822 */ 823 vp->v_type = VNON; 824 switch (imp->iso_ftype) { 825 default: /* ISO_FTYPE_9660 */ 826 { 827 struct buf *bp2; 828 int off; 829 if ((imp->im_flags & ISOFSMNT_EXTATT) 830 && (off = isonum_711(isodir->ext_attr_length))) 831 cd9660_blkatoff(vp, (off_t)-(off << imp->im_bshift), NULL, 832 &bp2); 833 else 834 bp2 = NULL; 835 cd9660_defattr(isodir, ip, bp2, ISO_FTYPE_9660); 836 cd9660_deftstamp(isodir, ip, bp2, ISO_FTYPE_9660); 837 if (bp2) 838 brelse(bp2); 839 break; 840 } 841 case ISO_FTYPE_RRIP: 842 cd9660_rrip_analyze(isodir, ip, imp); 843 break; 844 } 845 846 if (bp != 0) 847 brelse(bp); 848 849 /* 850 * Initialize the associated vnode 851 */ 852 switch (vp->v_type = IFTOVT(ip->inode.iso_mode)) { 853 case VFIFO: 854 vp->v_op = cd9660_fifoop_p; 855 break; 856 case VCHR: 857 case VBLK: 858 vp->v_op = cd9660_specop_p; 859 vp = addaliasu(vp, ip->inode.iso_rdev); 860 ip->i_vnode = vp; 861 break; 862 default: 863 break; 864 } 865 866 if (ip->iso_extent == imp->root_extent) 867 vp->v_vflag |= VV_ROOT; 868 869 /* 870 * XXX need generation number? 871 */ 872 873 *vpp = vp; 874 return (0); 875} 876 877/* 878 * Vnode pointer to File handle 879 */ 880/* ARGSUSED */ 881static int 882cd9660_vptofh(vp, fhp) 883 struct vnode *vp; 884 struct fid *fhp; 885{ 886 register struct iso_node *ip = VTOI(vp); 887 register struct ifid *ifhp; 888 889 ifhp = (struct ifid *)fhp; 890 ifhp->ifid_len = sizeof(struct ifid); 891 892 ifhp->ifid_ino = ip->i_number; 893 ifhp->ifid_start = ip->iso_start; 894 895#ifdef ISOFS_DBG 896 printf("vptofh: ino %d, start %ld\n", 897 ifhp->ifid_ino,ifhp->ifid_start); 898#endif 899 return 0; 900}
|