1 /* $NetBSD: cd9660_vfsops.c,v 1.30 2005/12/11 12:24:25 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 1994 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley 8 * by Pace Willisson (pace@blitz.com). The Rock Ridge Extension 9 * Support code is derived from software contributed to Berkeley 10 * by Atsushi Murai (amurai@spec.co.jp). 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * @(#)cd9660_vfsops.c 8.18 (Berkeley) 5/22/95 37 */ 38 39 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: cd9660_vfsops.c,v 1.30 2005/12/11 12:24:25 christos Exp $"); 41 42 #if defined(_KERNEL_OPT) 43 #include "opt_compat_netbsd.h" 44 #endif 45 46 #include <sys/param.h> 47 #include <sys/sysctl.h> 48 #include <sys/systm.h> 49 #include <sys/namei.h> 50 #include <sys/proc.h> 51 #include <sys/kernel.h> 52 #include <sys/vnode.h> 53 #include <miscfs/specfs/specdev.h> 54 #include <sys/mount.h> 55 #include <sys/buf.h> 56 #include <sys/file.h> 57 #include <sys/disklabel.h> 58 #include <sys/device.h> 59 #include <sys/ioctl.h> 60 #include <sys/cdio.h> 61 #include <sys/errno.h> 62 #include <sys/malloc.h> 63 #include <sys/pool.h> 64 #include <sys/stat.h> 65 #include <sys/conf.h> 66 #include <sys/dirent.h> 67 68 #include <fs/cd9660/iso.h> 69 #include <fs/cd9660/cd9660_extern.h> 70 #include <fs/cd9660/iso_rrip.h> 71 #include <fs/cd9660/cd9660_node.h> 72 #include <fs/cd9660/cd9660_mount.h> 73 74 MALLOC_DEFINE(M_ISOFSMNT, "ISOFS mount", "ISOFS mount structure"); 75 76 extern const struct vnodeopv_desc cd9660_vnodeop_opv_desc; 77 extern const struct vnodeopv_desc cd9660_specop_opv_desc; 78 extern const struct vnodeopv_desc cd9660_fifoop_opv_desc; 79 80 const struct vnodeopv_desc * const cd9660_vnodeopv_descs[] = { 81 &cd9660_vnodeop_opv_desc, 82 &cd9660_specop_opv_desc, 83 &cd9660_fifoop_opv_desc, 84 NULL, 85 }; 86 87 struct vfsops cd9660_vfsops = { 88 MOUNT_CD9660, 89 cd9660_mount, 90 cd9660_start, 91 cd9660_unmount, 92 cd9660_root, 93 cd9660_quotactl, 94 cd9660_statvfs, 95 cd9660_sync, 96 cd9660_vget, 97 cd9660_fhtovp, 98 cd9660_vptofh, 99 cd9660_init, 100 cd9660_reinit, 101 cd9660_done, 102 cd9660_mountroot, 103 (int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp, 104 vfs_stdextattrctl, 105 cd9660_vnodeopv_descs, 106 }; 107 VFS_ATTACH(cd9660_vfsops); 108 109 static const struct genfs_ops cd9660_genfsops = { 110 .gop_size = genfs_size, 111 }; 112 113 /* 114 * Called by vfs_mountroot when iso is going to be mounted as root. 115 * 116 * Name is updated by mount(8) after booting. 117 */ 118 #define ROOTNAME "root_device" 119 120 static int iso_makemp(struct iso_mnt *isomp, struct buf *bp, int *ea_len); 121 static int iso_mountfs(struct vnode *devvp, struct mount *mp, 122 struct lwp *l, struct iso_args *argp); 123 124 int 125 cd9660_mountroot() 126 { 127 struct mount *mp; 128 struct lwp *l = curlwp; /* XXX */ 129 int error; 130 struct iso_args args; 131 132 if (root_device->dv_class != DV_DISK) 133 return (ENODEV); 134 135 if ((error = vfs_rootmountalloc(MOUNT_CD9660, "root_device", &mp)) 136 != 0) { 137 vrele(rootvp); 138 return (error); 139 } 140 141 args.flags = ISOFSMNT_ROOT; 142 if ((error = iso_mountfs(rootvp, mp, l, &args)) != 0) { 143 mp->mnt_op->vfs_refcount--; 144 vfs_unbusy(mp); 145 free(mp, M_MOUNT); 146 return (error); 147 } 148 simple_lock(&mountlist_slock); 149 CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); 150 simple_unlock(&mountlist_slock); 151 (void)cd9660_statvfs(mp, &mp->mnt_stat, l); 152 vfs_unbusy(mp); 153 return (0); 154 } 155 156 /* 157 * VFS Operations. 158 * 159 * mount system call 160 */ 161 int 162 cd9660_mount(mp, path, data, ndp, l) 163 struct mount *mp; 164 const char *path; 165 void *data; 166 struct nameidata *ndp; 167 struct lwp *l; 168 { 169 struct vnode *devvp; 170 struct iso_args args; 171 struct proc *p; 172 int error; 173 struct iso_mnt *imp = VFSTOISOFS(mp); 174 175 p = l->l_proc; 176 if (mp->mnt_flag & MNT_GETARGS) { 177 if (imp == NULL) 178 return EIO; 179 args.fspec = NULL; 180 args.flags = imp->im_flags; 181 return copyout(&args, data, sizeof(args)); 182 } 183 error = copyin(data, &args, sizeof (struct iso_args)); 184 if (error) 185 return (error); 186 187 if ((mp->mnt_flag & MNT_RDONLY) == 0) 188 return (EROFS); 189 190 if ((mp->mnt_flag & MNT_UPDATE) && args.fspec == NULL) 191 return EINVAL; 192 193 /* 194 * Not an update, or updating the name: look up the name 195 * and verify that it refers to a sensible block device. 196 */ 197 NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, l); 198 if ((error = namei(ndp)) != 0) 199 return (error); 200 devvp = ndp->ni_vp; 201 202 if (devvp->v_type != VBLK) { 203 vrele(devvp); 204 return ENOTBLK; 205 } 206 if (bdevsw_lookup(devvp->v_rdev) == NULL) { 207 vrele(devvp); 208 return ENXIO; 209 } 210 /* 211 * If mount by non-root, then verify that user has necessary 212 * permissions on the device. 213 */ 214 if (p->p_ucred->cr_uid != 0) { 215 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 216 error = VOP_ACCESS(devvp, VREAD, p->p_ucred, l); 217 VOP_UNLOCK(devvp, 0); 218 if (error) { 219 vrele(devvp); 220 return (error); 221 } 222 } 223 if ((mp->mnt_flag & MNT_UPDATE) == 0) { 224 /* 225 * Disallow multiple mounts of the same device. 226 * Disallow mounting of a device that is currently in use 227 * (except for root, which might share swap device for 228 * miniroot). 229 */ 230 error = vfs_mountedon(devvp); 231 if (error) 232 goto fail; 233 if (vcount(devvp) > 1 && devvp != rootvp) { 234 error = EBUSY; 235 goto fail; 236 } 237 error = VOP_OPEN(devvp, FREAD, FSCRED, l); 238 if (error) 239 goto fail; 240 error = iso_mountfs(devvp, mp, l, &args); 241 if (error) { 242 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 243 (void)VOP_CLOSE(devvp, FREAD, NOCRED, l); 244 VOP_UNLOCK(devvp, 0); 245 goto fail; 246 } 247 } else { 248 vrele(devvp); 249 if (devvp != imp->im_devvp) 250 return (EINVAL); /* needs translation */ 251 } 252 return set_statvfs_info(path, UIO_USERSPACE, args.fspec, UIO_USERSPACE, 253 mp, l); 254 255 fail: 256 vrele(devvp); 257 return (error); 258 } 259 260 /* 261 * Make a mount point from a volume descriptor 262 */ 263 static int 264 iso_makemp(isomp, bp, ea_len) 265 struct iso_mnt *isomp; 266 struct buf *bp; 267 int *ea_len; 268 { 269 struct iso_primary_descriptor *pri; 270 int logical_block_size; 271 struct iso_directory_record *rootp; 272 273 pri = (struct iso_primary_descriptor *)bp->b_data; 274 275 logical_block_size = isonum_723 (pri->logical_block_size); 276 277 if (logical_block_size < DEV_BSIZE || logical_block_size > MAXBSIZE 278 || (logical_block_size & (logical_block_size - 1)) != 0) 279 return -1; 280 281 rootp = (struct iso_directory_record *)pri->root_directory_record; 282 283 isomp->logical_block_size = logical_block_size; 284 isomp->volume_space_size = isonum_733 (pri->volume_space_size); 285 memcpy(isomp->root, rootp, sizeof(isomp->root)); 286 isomp->root_extent = isonum_733 (rootp->extent); 287 isomp->root_size = isonum_733 (rootp->size); 288 isomp->im_joliet_level = 0; 289 290 isomp->im_bmask = logical_block_size - 1; 291 isomp->im_bshift = 0; 292 while ((1 << isomp->im_bshift) < isomp->logical_block_size) 293 isomp->im_bshift++; 294 295 if (ea_len != NULL) 296 *ea_len = isonum_711(rootp->ext_attr_length); 297 298 return 0; 299 } 300 301 /* 302 * Common code for mount and mountroot 303 */ 304 static int 305 iso_mountfs(devvp, mp, l, argp) 306 struct vnode *devvp; 307 struct mount *mp; 308 struct lwp *l; 309 struct iso_args *argp; 310 { 311 struct iso_mnt *isomp = (struct iso_mnt *)0; 312 struct buf *bp = NULL, *pribp = NULL, *supbp = NULL; 313 dev_t dev = devvp->v_rdev; 314 int error = EINVAL; 315 int ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 316 int iso_bsize; 317 int iso_blknum; 318 int joliet_level; 319 struct iso_volume_descriptor *vdp; 320 struct iso_supplementary_descriptor *sup; 321 int sess = 0; 322 int ext_attr_length; 323 struct disklabel label; 324 325 if (!ronly) 326 return EROFS; 327 328 /* Flush out any old buffers remaining from a previous use. */ 329 if ((error = vinvalbuf(devvp, V_SAVE, l->l_proc->p_ucred, l, 0, 0)) != 0) 330 return (error); 331 332 /* This is the "logical sector size". The standard says this 333 * should be 2048 or the physical sector size on the device, 334 * whichever is greater. For now, we'll just use a constant. 335 */ 336 iso_bsize = ISO_DEFAULT_BLOCK_SIZE; 337 338 error = VOP_IOCTL(devvp, DIOCGDINFO, &label, FREAD, FSCRED, l); 339 if (!error && 340 label.d_partitions[DISKPART(dev)].p_fstype == FS_ISO9660) { 341 /* XXX more sanity checks? */ 342 sess = label.d_partitions[DISKPART(dev)].p_cdsession; 343 } else { 344 /* fallback to old method */ 345 error = VOP_IOCTL(devvp, CDIOREADMSADDR, &sess, 0, FSCRED, l); 346 if (error) 347 sess = 0; /* never mind */ 348 } 349 #ifdef ISO_DEBUG 350 printf("isofs: session offset (part %d) %d\n", DISKPART(dev), sess); 351 #endif 352 353 for (iso_blknum = 16; iso_blknum < 100; iso_blknum++) { 354 if ((error = bread(devvp, (iso_blknum+sess) * btodb(iso_bsize), 355 iso_bsize, NOCRED, &bp)) != 0) 356 goto out; 357 358 vdp = (struct iso_volume_descriptor *)bp->b_data; 359 if (memcmp(vdp->id, ISO_STANDARD_ID, sizeof(vdp->id)) != 0) { 360 error = EINVAL; 361 goto out; 362 } 363 364 switch (isonum_711(vdp->type)) { 365 case ISO_VD_PRIMARY: 366 if (pribp == NULL) { 367 pribp = bp; 368 bp = NULL; 369 } 370 break; 371 372 case ISO_VD_SUPPLEMENTARY: 373 if (supbp == NULL) { 374 supbp = bp; 375 bp = NULL; 376 } 377 break; 378 379 default: 380 break; 381 } 382 383 if (isonum_711 (vdp->type) == ISO_VD_END) { 384 brelse(bp); 385 bp = NULL; 386 break; 387 } 388 389 if (bp != NULL) { 390 brelse(bp); 391 bp = NULL; 392 } 393 } 394 395 if (pribp == NULL) { 396 error = EINVAL; 397 goto out; 398 } 399 400 isomp = malloc(sizeof *isomp, M_ISOFSMNT, M_WAITOK); 401 memset(isomp, 0, sizeof *isomp); 402 if (iso_makemp(isomp, pribp, &ext_attr_length) == -1) { 403 error = EINVAL; 404 goto out; 405 } 406 407 isomp->volume_space_size += sess; 408 409 pribp->b_flags |= B_AGE; 410 brelse(pribp); 411 pribp = NULL; 412 413 mp->mnt_data = isomp; 414 mp->mnt_stat.f_fsidx.__fsid_val[0] = (long)dev; 415 mp->mnt_stat.f_fsidx.__fsid_val[1] = makefstype(MOUNT_CD9660); 416 mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0]; 417 mp->mnt_stat.f_namemax = MAXNAMLEN; 418 mp->mnt_flag |= MNT_LOCAL; 419 mp->mnt_dev_bshift = iso_bsize; 420 mp->mnt_fs_bshift = isomp->im_bshift; 421 isomp->im_mountp = mp; 422 isomp->im_dev = dev; 423 isomp->im_devvp = devvp; 424 425 devvp->v_specmountpoint = mp; 426 427 /* Check the Rock Ridge Extension support */ 428 if (!(argp->flags & ISOFSMNT_NORRIP)) { 429 struct iso_directory_record *rootp; 430 431 if ((error = bread(isomp->im_devvp, 432 (isomp->root_extent + ext_attr_length) << 433 (isomp->im_bshift - DEV_BSHIFT), 434 isomp->logical_block_size, NOCRED, 435 &bp)) != 0) 436 goto out; 437 438 rootp = (struct iso_directory_record *)bp->b_data; 439 440 if ((isomp->rr_skip = cd9660_rrip_offset(rootp,isomp)) < 0) { 441 argp->flags |= ISOFSMNT_NORRIP; 442 } else { 443 argp->flags &= ~ISOFSMNT_GENS; 444 } 445 446 /* 447 * The contents are valid, 448 * but they will get reread as part of another vnode, so... 449 */ 450 bp->b_flags |= B_AGE; 451 brelse(bp); 452 bp = NULL; 453 } 454 isomp->im_flags = argp->flags & (ISOFSMNT_NORRIP | ISOFSMNT_GENS | 455 ISOFSMNT_EXTATT | ISOFSMNT_NOJOLIET | ISOFSMNT_RRCASEINS); 456 457 if (isomp->im_flags & ISOFSMNT_GENS) 458 isomp->iso_ftype = ISO_FTYPE_9660; 459 else if (isomp->im_flags & ISOFSMNT_NORRIP) { 460 isomp->iso_ftype = ISO_FTYPE_DEFAULT; 461 if (argp->flags & ISOFSMNT_NOCASETRANS) 462 isomp->im_flags |= ISOFSMNT_NOCASETRANS; 463 } else 464 isomp->iso_ftype = ISO_FTYPE_RRIP; 465 466 /* Check the Joliet Extension support */ 467 if ((argp->flags & ISOFSMNT_NORRIP) != 0 && 468 (argp->flags & ISOFSMNT_NOJOLIET) == 0 && 469 supbp != NULL) { 470 joliet_level = 0; 471 sup = (struct iso_supplementary_descriptor *)supbp->b_data; 472 473 if ((isonum_711(sup->flags) & 1) == 0) { 474 if (memcmp(sup->escape, "%/@", 3) == 0) 475 joliet_level = 1; 476 if (memcmp(sup->escape, "%/C", 3) == 0) 477 joliet_level = 2; 478 if (memcmp(sup->escape, "%/E", 3) == 0) 479 joliet_level = 3; 480 } 481 if (joliet_level != 0) { 482 if (iso_makemp(isomp, supbp, NULL) == -1) { 483 error = EINVAL; 484 goto out; 485 } 486 isomp->im_joliet_level = joliet_level; 487 } 488 } 489 490 if (supbp != NULL) { 491 brelse(supbp); 492 supbp = NULL; 493 } 494 495 return 0; 496 out: 497 if (bp) 498 brelse(bp); 499 if (pribp) 500 brelse(pribp); 501 if (supbp) 502 brelse(supbp); 503 if (isomp) { 504 free(isomp, M_ISOFSMNT); 505 mp->mnt_data = NULL; 506 } 507 return error; 508 } 509 510 /* 511 * Make a filesystem operational. 512 * Nothing to do at the moment. 513 */ 514 /* ARGSUSED */ 515 int 516 cd9660_start(mp, flags, l) 517 struct mount *mp; 518 int flags; 519 struct lwp *l; 520 { 521 return 0; 522 } 523 524 /* 525 * unmount system call 526 */ 527 int 528 cd9660_unmount(mp, mntflags, l) 529 struct mount *mp; 530 int mntflags; 531 struct lwp *l; 532 { 533 struct iso_mnt *isomp; 534 int error, flags = 0; 535 536 if (mntflags & MNT_FORCE) 537 flags |= FORCECLOSE; 538 #if 0 539 mntflushbuf(mp, 0); 540 if (mntinvalbuf(mp)) 541 return EBUSY; 542 #endif 543 if ((error = vflush(mp, NULLVP, flags)) != 0) 544 return (error); 545 546 isomp = VFSTOISOFS(mp); 547 548 #ifdef ISODEVMAP 549 if (isomp->iso_ftype == ISO_FTYPE_RRIP) 550 iso_dunmap(isomp->im_dev); 551 #endif 552 553 if (isomp->im_devvp->v_type != VBAD) 554 isomp->im_devvp->v_specmountpoint = NULL; 555 556 vn_lock(isomp->im_devvp, LK_EXCLUSIVE | LK_RETRY); 557 error = VOP_CLOSE(isomp->im_devvp, FREAD, NOCRED, l); 558 vput(isomp->im_devvp); 559 free(isomp, M_ISOFSMNT); 560 mp->mnt_data = NULL; 561 mp->mnt_flag &= ~MNT_LOCAL; 562 return (error); 563 } 564 565 /* 566 * Return root of a filesystem 567 */ 568 int 569 cd9660_root(mp, vpp) 570 struct mount *mp; 571 struct vnode **vpp; 572 { 573 struct iso_mnt *imp = VFSTOISOFS(mp); 574 struct iso_directory_record *dp = 575 (struct iso_directory_record *)imp->root; 576 ino_t ino = isodirino(dp, imp); 577 578 /* 579 * With RRIP we must use the `.' entry of the root directory. 580 * Simply tell vget, that it's a relocated directory. 581 */ 582 return (cd9660_vget_internal(mp, ino, vpp, 583 imp->iso_ftype == ISO_FTYPE_RRIP, dp)); 584 } 585 586 /* 587 * Do operations associated with quotas, not supported 588 */ 589 /* ARGSUSED */ 590 int 591 cd9660_quotactl(mp, cmd, uid, arg, l) 592 struct mount *mp; 593 int cmd; 594 uid_t uid; 595 void *arg; 596 struct lwp *l; 597 { 598 599 return (EOPNOTSUPP); 600 } 601 602 /* 603 * Get file system statistics. 604 */ 605 int 606 cd9660_statvfs(mp, sbp, l) 607 struct mount *mp; 608 struct statvfs *sbp; 609 struct lwp *l; 610 { 611 struct iso_mnt *isomp; 612 613 isomp = VFSTOISOFS(mp); 614 615 sbp->f_bsize = isomp->logical_block_size; 616 sbp->f_frsize = sbp->f_bsize; 617 sbp->f_iosize = sbp->f_bsize; /* XXX */ 618 sbp->f_blocks = isomp->volume_space_size; 619 sbp->f_bfree = 0; /* total free blocks */ 620 sbp->f_bavail = 0; /* blocks free for non superuser */ 621 sbp->f_bresvd = 0; /* total reserved blocks */ 622 sbp->f_files = 0; /* total files */ 623 sbp->f_ffree = 0; /* free file nodes */ 624 sbp->f_favail = 0; /* free file nodes for non superuser */ 625 sbp->f_fresvd = 0; /* reserved file nodes */ 626 copy_statvfs_info(sbp, mp); 627 /* Use the first spare for flags: */ 628 sbp->f_spare[0] = isomp->im_flags; 629 return 0; 630 } 631 632 /* ARGSUSED */ 633 int 634 cd9660_sync(mp, waitfor, cred, l) 635 struct mount *mp; 636 int waitfor; 637 struct ucred *cred; 638 struct lwp *l; 639 { 640 return (0); 641 } 642 643 /* 644 * File handle to vnode 645 * 646 * Have to be really careful about stale file handles: 647 * - check that the inode number is in range 648 * - call iget() to get the locked inode 649 * - check for an unallocated inode (i_mode == 0) 650 * - check that the generation number matches 651 */ 652 653 struct ifid { 654 ushort ifid_len; 655 ushort ifid_pad; 656 int ifid_ino; 657 long ifid_start; 658 }; 659 660 /* ARGSUSED */ 661 int 662 cd9660_fhtovp(mp, fhp, vpp) 663 struct mount *mp; 664 struct fid *fhp; 665 struct vnode **vpp; 666 { 667 struct ifid *ifhp = (struct ifid *)fhp; 668 struct iso_node *ip; 669 struct vnode *nvp; 670 int error; 671 672 #ifdef ISOFS_DBG 673 printf("fhtovp: ino %d, start %ld\n", 674 ifhp->ifid_ino, ifhp->ifid_start); 675 #endif 676 677 if ((error = VFS_VGET(mp, ifhp->ifid_ino, &nvp)) != 0) { 678 *vpp = NULLVP; 679 return (error); 680 } 681 ip = VTOI(nvp); 682 if (ip->inode.iso_mode == 0) { 683 vput(nvp); 684 *vpp = NULLVP; 685 return (ESTALE); 686 } 687 *vpp = nvp; 688 return (0); 689 } 690 691 int 692 cd9660_vget(mp, ino, vpp) 693 struct mount *mp; 694 ino_t ino; 695 struct vnode **vpp; 696 { 697 698 /* 699 * XXXX 700 * It would be nice if we didn't always set the `relocated' flag 701 * and force the extra read, but I don't want to think about fixing 702 * that right now. 703 */ 704 return (cd9660_vget_internal(mp, ino, vpp, 705 #if 0 706 VFSTOISOFS(mp)->iso_ftype == ISO_FTYPE_RRIP, 707 #else 708 0, 709 #endif 710 NULL)); 711 } 712 713 int 714 cd9660_vget_internal(mp, ino, vpp, relocated, isodir) 715 struct mount *mp; 716 ino_t ino; 717 struct vnode **vpp; 718 int relocated; 719 struct iso_directory_record *isodir; 720 { 721 struct iso_mnt *imp; 722 struct iso_node *ip; 723 #ifdef ISODEVMAP 724 struct iso_dnode *dp; 725 #endif 726 struct buf *bp; 727 struct vnode *vp, *nvp; 728 dev_t dev; 729 int error; 730 731 imp = VFSTOISOFS(mp); 732 dev = imp->im_dev; 733 if ((*vpp = cd9660_ihashget(dev, ino)) != NULLVP) 734 return (0); 735 736 /* Allocate a new vnode/iso_node. */ 737 if ((error = getnewvnode(VT_ISOFS, mp, cd9660_vnodeop_p, &vp)) != 0) { 738 *vpp = NULLVP; 739 return (error); 740 } 741 ip = pool_get(&cd9660_node_pool, PR_WAITOK); 742 memset(ip, 0, sizeof(struct iso_node)); 743 vp->v_data = ip; 744 ip->i_vnode = vp; 745 ip->i_dev = dev; 746 ip->i_number = ino; 747 748 /* 749 * Put it onto its hash chain and lock it so that other requests for 750 * this inode will block if they arrive while we are sleeping waiting 751 * for old data structures to be purged or for the contents of the 752 * disk portion of this inode to be read. 753 */ 754 cd9660_ihashins(ip); 755 756 if (isodir == 0) { 757 int lbn, off; 758 759 lbn = lblkno(imp, ino); 760 if (lbn >= imp->volume_space_size) { 761 vput(vp); 762 printf("fhtovp: lbn exceed volume space %d\n", lbn); 763 return (ESTALE); 764 } 765 766 off = blkoff(imp, ino); 767 if (off + ISO_DIRECTORY_RECORD_SIZE > imp->logical_block_size) { 768 vput(vp); 769 printf("fhtovp: crosses block boundary %d\n", 770 off + ISO_DIRECTORY_RECORD_SIZE); 771 return (ESTALE); 772 } 773 774 error = bread(imp->im_devvp, 775 lbn << (imp->im_bshift - DEV_BSHIFT), 776 imp->logical_block_size, NOCRED, &bp); 777 if (error) { 778 vput(vp); 779 brelse(bp); 780 printf("fhtovp: bread error %d\n",error); 781 return (error); 782 } 783 isodir = (struct iso_directory_record *)(bp->b_data + off); 784 785 if (off + isonum_711(isodir->length) > 786 imp->logical_block_size) { 787 vput(vp); 788 if (bp != 0) 789 brelse(bp); 790 printf("fhtovp: directory crosses block boundary %d[off=%d/len=%d]\n", 791 off +isonum_711(isodir->length), off, 792 isonum_711(isodir->length)); 793 return (ESTALE); 794 } 795 796 #if 0 797 if (isonum_733(isodir->extent) + 798 isonum_711(isodir->ext_attr_length) != ifhp->ifid_start) { 799 if (bp != 0) 800 brelse(bp); 801 printf("fhtovp: file start miss %d vs %d\n", 802 isonum_733(isodir->extent) + isonum_711(isodir->ext_attr_length), 803 ifhp->ifid_start); 804 return (ESTALE); 805 } 806 #endif 807 } else 808 bp = 0; 809 810 ip->i_mnt = imp; 811 ip->i_devvp = imp->im_devvp; 812 VREF(ip->i_devvp); 813 814 if (relocated) { 815 /* 816 * On relocated directories we must 817 * read the `.' entry out of a dir. 818 */ 819 ip->iso_start = ino >> imp->im_bshift; 820 if (bp != 0) 821 brelse(bp); 822 if ((error = cd9660_blkatoff(vp, (off_t)0, NULL, &bp)) != 0) { 823 vput(vp); 824 return (error); 825 } 826 isodir = (struct iso_directory_record *)bp->b_data; 827 } 828 829 ip->iso_extent = isonum_733(isodir->extent); 830 ip->i_size = isonum_733(isodir->size); 831 ip->iso_start = isonum_711(isodir->ext_attr_length) + ip->iso_extent; 832 833 /* 834 * Setup time stamp, attribute 835 */ 836 vp->v_type = VNON; 837 switch (imp->iso_ftype) { 838 default: /* ISO_FTYPE_9660 */ 839 { 840 struct buf *bp2; 841 int off; 842 if ((imp->im_flags & ISOFSMNT_EXTATT) 843 && (off = isonum_711(isodir->ext_attr_length))) 844 cd9660_blkatoff(vp, (off_t)-(off << imp->im_bshift), 845 NULL, &bp2); 846 else 847 bp2 = NULL; 848 cd9660_defattr(isodir, ip, bp2); 849 cd9660_deftstamp(isodir, ip, bp2); 850 if (bp2) 851 brelse(bp2); 852 break; 853 } 854 case ISO_FTYPE_RRIP: 855 cd9660_rrip_analyze(isodir, ip, imp); 856 break; 857 } 858 859 if (bp != 0) 860 brelse(bp); 861 862 /* 863 * Initialize the associated vnode 864 */ 865 switch (vp->v_type = IFTOVT(ip->inode.iso_mode)) { 866 case VFIFO: 867 vp->v_op = cd9660_fifoop_p; 868 break; 869 case VCHR: 870 case VBLK: 871 /* 872 * if device, look at device number table for translation 873 */ 874 #ifdef ISODEVMAP 875 if ((dp = iso_dmap(dev, ino, 0)) != NULL) 876 ip->inode.iso_rdev = dp->d_dev; 877 #endif 878 vp->v_op = cd9660_specop_p; 879 if ((nvp = checkalias(vp, ip->inode.iso_rdev, mp)) != NULL) { 880 /* 881 * Discard unneeded vnode, but save its iso_node. 882 * Note that the lock is carried over in the iso_node 883 * to the replacement vnode. 884 */ 885 nvp->v_data = vp->v_data; 886 vp->v_data = NULL; 887 VOP_UNLOCK(vp, 0); 888 vp->v_op = spec_vnodeop_p; 889 vrele(vp); 890 vgone(vp); 891 lockmgr(&nvp->v_lock, LK_EXCLUSIVE, &nvp->v_interlock); 892 /* 893 * Reinitialize aliased inode. 894 */ 895 vp = nvp; 896 ip->i_vnode = vp; 897 } 898 break; 899 case VLNK: 900 case VNON: 901 case VSOCK: 902 case VDIR: 903 case VBAD: 904 break; 905 case VREG: 906 uvm_vnp_setsize(vp, ip->i_size); 907 break; 908 } 909 910 if (ip->iso_extent == imp->root_extent) 911 vp->v_flag |= VROOT; 912 913 /* 914 * XXX need generation number? 915 */ 916 917 genfs_node_init(vp, &cd9660_genfsops); 918 *vpp = vp; 919 return (0); 920 } 921 922 /* 923 * Vnode pointer to File handle 924 */ 925 /* ARGSUSED */ 926 int 927 cd9660_vptofh(vp, fhp) 928 struct vnode *vp; 929 struct fid *fhp; 930 { 931 struct iso_node *ip = VTOI(vp); 932 struct ifid *ifhp; 933 934 ifhp = (struct ifid *)fhp; 935 ifhp->ifid_len = sizeof(struct ifid); 936 937 ifhp->ifid_ino = ip->i_number; 938 ifhp->ifid_start = ip->iso_start; 939 940 #ifdef ISOFS_DBG 941 printf("vptofh: ino %d, start %ld\n", 942 ifhp->ifid_ino,ifhp->ifid_start); 943 #endif 944 return 0; 945 } 946 947 SYSCTL_SETUP(sysctl_vfs_cd9660_setup, "sysctl vfs.cd9660 subtree setup") 948 { 949 950 sysctl_createv(clog, 0, NULL, NULL, 951 CTLFLAG_PERMANENT, CTLTYPE_NODE, "vfs", NULL, 952 NULL, 0, NULL, 0, 953 CTL_VFS, CTL_EOL); 954 sysctl_createv(clog, 0, NULL, NULL, 955 CTLFLAG_PERMANENT, CTLTYPE_NODE, "cd9660", 956 SYSCTL_DESCR("ISO-9660 file system"), 957 NULL, 0, NULL, 0, 958 CTL_VFS, 14, CTL_EOL); 959 960 sysctl_createv(clog, 0, NULL, NULL, 961 CTLFLAG_PERMANENT|CTLFLAG_READWRITE, 962 CTLTYPE_INT, "utf8_joliet", 963 SYSCTL_DESCR("Encode Joliet file names to UTF-8"), 964 NULL, 0, &cd9660_utf8_joliet, 0, 965 CTL_VFS, 14, CD9660_UTF8_JOLIET, CTL_EOL); 966 967 } 968