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