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