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