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 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * @(#)cd9660_vfsops.c 8.18 (Berkeley) 5/22/95 39 * $FreeBSD$ 40 */ 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/namei.h> 45 #include <sys/proc.h> 46 #include <sys/kernel.h> 47 #include <sys/vnode.h> 48 #include <sys/mount.h> 49 #include <sys/bio.h> 50 #include <sys/buf.h> 51 #include <sys/cdio.h> 52 #include <sys/conf.h> 53 #include <sys/fcntl.h> 54 #include <sys/malloc.h> 55 #include <sys/stat.h> 56 #include <sys/syslog.h> 57 58 59 #include <isofs/cd9660/iso.h> 60 #include <isofs/cd9660/iso_rrip.h> 61 #include <isofs/cd9660/cd9660_node.h> 62 #include <isofs/cd9660/cd9660_mount.h> 63 64 MALLOC_DEFINE(M_ISOFSMNT, "ISOFS mount", "ISOFS mount structure"); 65 MALLOC_DEFINE(M_ISOFSNODE, "ISOFS node", "ISOFS vnode private part"); 66 67 static int cd9660_mount(struct mount *, 68 char *, caddr_t, struct nameidata *, struct thread *); 69 static int cd9660_unmount(struct mount *, int, struct thread *); 70 static int cd9660_root(struct mount *, struct vnode **); 71 static int cd9660_statfs(struct mount *, struct statfs *, struct thread *); 72 static int cd9660_vget(struct mount *, ino_t, int, struct vnode **); 73 static int cd9660_fhtovp(struct mount *, struct fid *, struct vnode **); 74 static int cd9660_vptofh(struct vnode *, struct fid *); 75 76 static struct vfsops cd9660_vfsops = { 77 cd9660_mount, 78 vfs_stdstart, 79 cd9660_unmount, 80 cd9660_root, 81 vfs_stdquotactl, 82 cd9660_statfs, 83 vfs_stdsync, 84 cd9660_vget, 85 cd9660_fhtovp, 86 vfs_stdcheckexp, 87 cd9660_vptofh, 88 cd9660_init, 89 cd9660_uninit, 90 vfs_stdextattrctl, 91 }; 92 VFS_SET(cd9660_vfsops, cd9660, VFCF_READONLY); 93 MODULE_VERSION(cd9660, 1); 94 95 96 /* 97 * Called by vfs_mountroot when iso is going to be mounted as root. 98 */ 99 100 static int iso_get_ssector(dev_t dev, struct thread *td); 101 static int iso_mountfs(struct vnode *devvp, struct mount *mp, 102 struct thread *td, struct iso_args *argp); 103 104 /* 105 * Try to find the start of the last data track on this CD-ROM. This 106 * is used to mount the last session of a multi-session CD. Bail out 107 * and return 0 if we fail, this is always a safe bet. 108 */ 109 static int 110 iso_get_ssector(dev, td) 111 dev_t dev; 112 struct thread *td; 113 { 114 struct ioc_toc_header h; 115 struct ioc_read_toc_single_entry t; 116 int i; 117 struct cdevsw *bd; 118 d_ioctl_t *ioctlp; 119 120 bd = devsw(dev); 121 ioctlp = bd->d_ioctl; 122 if (ioctlp == NULL) 123 return 0; 124 125 if (ioctlp(dev, CDIOREADTOCHEADER, (caddr_t)&h, FREAD, td) != 0) 126 return 0; 127 128 for (i = h.ending_track; i >= 0; i--) { 129 t.address_format = CD_LBA_FORMAT; 130 t.track = i; 131 if (ioctlp(dev, CDIOREADTOCENTRY, (caddr_t)&t, FREAD, td) != 0) 132 return 0; 133 if ((t.entry.control & 4) != 0) 134 /* found a data track */ 135 break; 136 } 137 138 if (i < 0) 139 return 0; 140 141 return ntohl(t.entry.addr.lba); 142 } 143 144 static int iso_mountroot(struct mount *mp, struct thread *td); 145 146 static int 147 iso_mountroot(mp, td) 148 struct mount *mp; 149 struct thread *td; 150 { 151 struct iso_args args; 152 int error; 153 154 if ((error = bdevvp(rootdev, &rootvp))) { 155 printf("iso_mountroot: can't find rootvp\n"); 156 return (error); 157 } 158 args.flags = ISOFSMNT_ROOT; 159 160 vn_lock(rootvp, LK_EXCLUSIVE | LK_RETRY, td); 161 error = VOP_OPEN(rootvp, FREAD, FSCRED, td); 162 VOP_UNLOCK(rootvp, 0, td); 163 if (error) 164 return error; 165 166 args.ssector = iso_get_ssector(rootdev, td); 167 168 (void)VOP_CLOSE(rootvp, FREAD, NOCRED, td); 169 170 if (bootverbose) 171 printf("iso_mountroot(): using session at block %d\n", 172 args.ssector); 173 if ((error = iso_mountfs(rootvp, mp, td, &args)) != 0) 174 return (error); 175 176 (void)cd9660_statfs(mp, &mp->mnt_stat, td); 177 return (0); 178 } 179 180 /* 181 * VFS Operations. 182 * 183 * mount system call 184 */ 185 static int 186 cd9660_mount(mp, path, data, ndp, td) 187 register struct mount *mp; 188 char *path; 189 caddr_t data; 190 struct nameidata *ndp; 191 struct thread *td; 192 { 193 struct vnode *devvp; 194 struct iso_args args; 195 size_t size; 196 int error; 197 mode_t accessmode; 198 struct iso_mnt *imp = 0; 199 200 if ((mp->mnt_flag & MNT_ROOTFS) != 0) { 201 return (iso_mountroot(mp, td)); 202 } 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 */ 271 static int 272 iso_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; 518 out: 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 */ 538 static int 539 cd9660_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 */ 571 static int 572 cd9660_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 */ 592 int 593 cd9660_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 627 struct ifid { 628 ushort ifid_len; 629 ushort ifid_pad; 630 int ifid_ino; 631 long ifid_start; 632 }; 633 634 /* ARGSUSED */ 635 int 636 cd9660_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 665 int 666 cd9660_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 688 int 689 cd9660_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(VT_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 lockinit(&vp->v_lock, PINOD, "isonode", 0, 0); 719 /* 720 * ISOFS uses stdlock and can share lock structure 721 */ 722 vp->v_vnlock = &vp->v_lock; 723 vp->v_data = ip; 724 ip->i_vnode = vp; 725 ip->i_dev = dev; 726 ip->i_number = ino; 727 728 /* 729 * Check to be sure that it did not show up. We have to put it 730 * on the hash chain as the cleanup from vput expects to find 731 * it there. 732 */ 733 if ((error = cd9660_ihashget(dev, ino, flags, vpp)) != 0 || 734 *vpp != NULL) { 735 cd9660_ihashins(ip); 736 vput(vp); 737 return (error); 738 } 739 740 /* 741 * Put it onto its hash chain and lock it so that other requests for 742 * this inode will block if they arrive while we are sleeping waiting 743 * for old data structures to be purged or for the contents of the 744 * disk portion of this inode to be read. 745 */ 746 cd9660_ihashins(ip); 747 748 if (isodir == 0) { 749 int lbn, off; 750 751 lbn = lblkno(imp, ino); 752 if (lbn >= imp->volume_space_size) { 753 vput(vp); 754 printf("fhtovp: lbn exceed volume space %d\n", lbn); 755 return (ESTALE); 756 } 757 758 off = blkoff(imp, ino); 759 if (off + ISO_DIRECTORY_RECORD_SIZE > imp->logical_block_size) { 760 vput(vp); 761 printf("fhtovp: crosses block boundary %d\n", 762 off + ISO_DIRECTORY_RECORD_SIZE); 763 return (ESTALE); 764 } 765 766 error = bread(imp->im_devvp, 767 lbn << (imp->im_bshift - DEV_BSHIFT), 768 imp->logical_block_size, NOCRED, &bp); 769 if (error) { 770 vput(vp); 771 brelse(bp); 772 printf("fhtovp: bread error %d\n",error); 773 return (error); 774 } 775 isodir = (struct iso_directory_record *)(bp->b_data + off); 776 777 if (off + isonum_711(isodir->length) > 778 imp->logical_block_size) { 779 vput(vp); 780 if (bp != 0) 781 brelse(bp); 782 printf("fhtovp: directory crosses block boundary %d[off=%d/len=%d]\n", 783 off +isonum_711(isodir->length), off, 784 isonum_711(isodir->length)); 785 return (ESTALE); 786 } 787 788 #if 0 789 if (isonum_733(isodir->extent) + 790 isonum_711(isodir->ext_attr_length) != ifhp->ifid_start) { 791 if (bp != 0) 792 brelse(bp); 793 printf("fhtovp: file start miss %d vs %d\n", 794 isonum_733(isodir->extent) + isonum_711(isodir->ext_attr_length), 795 ifhp->ifid_start); 796 return (ESTALE); 797 } 798 #endif 799 } else 800 bp = 0; 801 802 ip->i_mnt = imp; 803 ip->i_devvp = imp->im_devvp; 804 VREF(ip->i_devvp); 805 806 if (relocated) { 807 /* 808 * On relocated directories we must 809 * read the `.' entry out of a dir. 810 */ 811 ip->iso_start = ino >> imp->im_bshift; 812 if (bp != 0) 813 brelse(bp); 814 if ((error = cd9660_blkatoff(vp, (off_t)0, NULL, &bp)) != 0) { 815 vput(vp); 816 return (error); 817 } 818 isodir = (struct iso_directory_record *)bp->b_data; 819 } 820 821 ip->iso_extent = isonum_733(isodir->extent); 822 ip->i_size = isonum_733(isodir->size); 823 ip->iso_start = isonum_711(isodir->ext_attr_length) + ip->iso_extent; 824 825 /* 826 * Setup time stamp, attribute 827 */ 828 vp->v_type = VNON; 829 switch (imp->iso_ftype) { 830 default: /* ISO_FTYPE_9660 */ 831 { 832 struct buf *bp2; 833 int off; 834 if ((imp->im_flags & ISOFSMNT_EXTATT) 835 && (off = isonum_711(isodir->ext_attr_length))) 836 cd9660_blkatoff(vp, (off_t)-(off << imp->im_bshift), NULL, 837 &bp2); 838 else 839 bp2 = NULL; 840 cd9660_defattr(isodir, ip, bp2, ISO_FTYPE_9660); 841 cd9660_deftstamp(isodir, ip, bp2, ISO_FTYPE_9660); 842 if (bp2) 843 brelse(bp2); 844 break; 845 } 846 case ISO_FTYPE_RRIP: 847 cd9660_rrip_analyze(isodir, ip, imp); 848 break; 849 } 850 851 if (bp != 0) 852 brelse(bp); 853 854 /* 855 * Initialize the associated vnode 856 */ 857 switch (vp->v_type = IFTOVT(ip->inode.iso_mode)) { 858 case VFIFO: 859 vp->v_op = cd9660_fifoop_p; 860 break; 861 case VCHR: 862 case VBLK: 863 vp->v_op = cd9660_specop_p; 864 vp = addaliasu(vp, ip->inode.iso_rdev); 865 ip->i_vnode = vp; 866 break; 867 default: 868 break; 869 } 870 871 if (ip->iso_extent == imp->root_extent) 872 vp->v_flag |= VROOT; 873 874 /* 875 * XXX need generation number? 876 */ 877 878 *vpp = vp; 879 return (0); 880 } 881 882 /* 883 * Vnode pointer to File handle 884 */ 885 /* ARGSUSED */ 886 int 887 cd9660_vptofh(vp, fhp) 888 struct vnode *vp; 889 struct fid *fhp; 890 { 891 register struct iso_node *ip = VTOI(vp); 892 register struct ifid *ifhp; 893 894 ifhp = (struct ifid *)fhp; 895 ifhp->ifid_len = sizeof(struct ifid); 896 897 ifhp->ifid_ino = ip->i_number; 898 ifhp->ifid_start = ip->iso_start; 899 900 #ifdef ISOFS_DBG 901 printf("vptofh: ino %d, start %ld\n", 902 ifhp->ifid_ino,ifhp->ifid_start); 903 #endif 904 return 0; 905 } 906