1 /*- 2 * Copyright (c) 1994 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley 6 * by Pace Willisson (pace@blitz.com). The Rock Ridge Extension 7 * Support code is derived from software contributed to Berkeley 8 * by Atsushi Murai (amurai@spec.co.jp). 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * @(#)cd9660_vfsops.c 8.18 (Berkeley) 5/22/95 39 * $FreeBSD: src/sys/isofs/cd9660/cd9660_vfsops.c,v 1.74.2.7 2002/04/08 09:39:29 bde Exp $ 40 * $DragonFly: src/sys/vfs/isofs/cd9660/cd9660_vfsops.c,v 1.27 2005/07/26 15:43:35 hmp Exp $ 41 */ 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/proc.h> 46 #include <sys/nlookup.h> 47 #include <sys/kernel.h> 48 #include <sys/vnode.h> 49 #include <sys/mount.h> 50 #include <sys/buf.h> 51 #include <sys/cdio.h> 52 #include <sys/conf.h> 53 #include <sys/fcntl.h> 54 #include <sys/malloc.h> 55 #include <sys/stat.h> 56 #include <sys/syslog.h> 57 58 #include <vm/vm_zone.h> 59 60 #include "iso.h" 61 #include "iso_rrip.h" 62 #include "cd9660_node.h" 63 #include "cd9660_mount.h" 64 65 extern struct vnodeopv_entry_desc cd9660_vnodeop_entries[]; 66 extern struct vnodeopv_entry_desc cd9660_specop_entries[]; 67 extern struct vnodeopv_entry_desc cd9660_fifoop_entries[]; 68 69 MALLOC_DEFINE(M_ISOFSMNT, "ISOFS mount", "ISOFS mount structure"); 70 MALLOC_DEFINE(M_ISOFSNODE, "ISOFS node", "ISOFS vnode private part"); 71 72 static int cd9660_mount (struct mount *, char *, caddr_t, struct thread *); 73 static int cd9660_unmount (struct mount *, int, struct thread *); 74 static int cd9660_root (struct mount *, struct vnode **); 75 static int cd9660_statfs (struct mount *, struct statfs *, struct thread *); 76 static int cd9660_vget (struct mount *, ino_t, struct vnode **); 77 static int cd9660_fhtovp (struct mount *, struct fid *, struct vnode **); 78 static int cd9660_checkexp (struct mount *, struct sockaddr *, 79 int *, struct ucred **); 80 static int cd9660_vptofh (struct vnode *, struct fid *); 81 82 static struct vfsops cd9660_vfsops = { 83 .vfs_mount = cd9660_mount, 84 .vfs_unmount = cd9660_unmount, 85 .vfs_root = cd9660_root, 86 .vfs_statfs = cd9660_statfs, 87 .vfs_sync = vfs_stdsync, 88 .vfs_vget = cd9660_vget, 89 .vfs_fhtovp = cd9660_fhtovp, 90 .vfs_checkexp = cd9660_checkexp, 91 .vfs_vptofh = cd9660_vptofh, 92 .vfs_init = cd9660_init, 93 .vfs_uninit = cd9660_uninit, 94 }; 95 VFS_SET(cd9660_vfsops, cd9660, VFCF_READONLY); 96 MODULE_VERSION(cd9660, 1); 97 98 99 /* 100 * Called by vfs_mountroot when iso is going to be mounted as root. 101 */ 102 103 static int iso_get_ssector (dev_t dev, struct thread *td); 104 static int iso_mountfs (struct vnode *devvp, struct mount *mp, 105 struct thread *td, struct iso_args *argp); 106 107 /* 108 * Try to find the start of the last data track on this CD-ROM. This 109 * is used to mount the last session of a multi-session CD. Bail out 110 * and return 0 if we fail, this is always a safe bet. 111 */ 112 static int 113 iso_get_ssector(dev_t dev, struct thread *td) 114 { 115 struct ioc_toc_header h; 116 struct ioc_read_toc_single_entry t; 117 int i; 118 119 if (dev_dioctl(dev, CDIOREADTOCHEADER, (caddr_t)&h, FREAD, td) != 0) 120 return 0; 121 122 for (i = h.ending_track; i >= 0; i--) { 123 t.address_format = CD_LBA_FORMAT; 124 t.track = i; 125 if (dev_dioctl(dev, CDIOREADTOCENTRY, (caddr_t)&t, FREAD, td) != 0) { 126 return 0; 127 } 128 if ((t.entry.control & 4) != 0) 129 /* found a data track */ 130 break; 131 } 132 133 if (i < 0) 134 return 0; 135 136 return ntohl(t.entry.addr.lba); 137 } 138 139 static int iso_mountroot (struct mount *mp, struct thread *td); 140 141 static int 142 iso_mountroot(struct mount *mp, struct thread *td) 143 { 144 struct iso_args args; 145 struct vnode *rootvp; 146 int error; 147 148 if ((error = bdevvp(rootdev, &rootvp))) { 149 printf("iso_mountroot: can't find rootvp\n"); 150 return (error); 151 } 152 args.flags = ISOFSMNT_ROOT; 153 154 vn_lock(rootvp, LK_EXCLUSIVE | LK_RETRY, td); 155 error = VOP_OPEN(rootvp, FREAD, FSCRED, NULL, td); 156 VOP_UNLOCK(rootvp, 0, td); 157 if (error) 158 return (error); 159 160 args.ssector = iso_get_ssector(rootdev, td); 161 162 (void)VOP_CLOSE(rootvp, FREAD, td); 163 164 if (bootverbose) 165 printf("iso_mountroot(): using session at block %d\n", 166 args.ssector); 167 if ((error = iso_mountfs(rootvp, mp, td, &args)) != 0) 168 return (error); 169 170 (void)cd9660_statfs(mp, &mp->mnt_stat, td); 171 return (0); 172 } 173 174 /* 175 * VFS Operations. 176 * 177 * mount system call 178 */ 179 static int 180 cd9660_mount(struct mount *mp, char *path, caddr_t data, struct thread *td) 181 { 182 struct vnode *devvp; 183 struct iso_args args; 184 size_t size; 185 int error; 186 mode_t accessmode; 187 struct iso_mnt *imp = 0; 188 struct nlookupdata nd; 189 190 if ((mp->mnt_flag & (MNT_ROOTFS|MNT_UPDATE)) == MNT_ROOTFS) { 191 return (iso_mountroot(mp, td)); 192 } 193 if ((error = copyin(data, (caddr_t)&args, sizeof (struct iso_args)))) 194 return (error); 195 196 if ((mp->mnt_flag & MNT_RDONLY) == 0) 197 return (EROFS); 198 199 KKASSERT(td->td_proc); 200 201 /* 202 * If updating, check whether changing from read-only to 203 * read/write; if there is no device name, that's all we do. 204 */ 205 if (mp->mnt_flag & MNT_UPDATE) { 206 imp = VFSTOISOFS(mp); 207 if (args.fspec == 0) 208 return (vfs_export(mp, &imp->im_export, &args.export)); 209 } 210 /* 211 * Not an update, or updating the name: look up the name 212 * and verify that it refers to a sensible block device. 213 */ 214 devvp = NULL; 215 error = nlookup_init(&nd, args.fspec, UIO_USERSPACE, NLC_FOLLOW); 216 if (error == 0) 217 error = nlookup(&nd); 218 if (error == 0) 219 error = cache_vref(nd.nl_ncp, nd.nl_cred, &devvp); 220 nlookup_done(&nd); 221 if (error) 222 return (error); 223 224 if (!vn_isdisk(devvp, &error)) { 225 vrele(devvp); 226 return (error); 227 } 228 229 /* 230 * Verify that user has necessary permissions on the device, 231 * or has superuser abilities 232 */ 233 accessmode = VREAD; 234 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td); 235 error = VOP_ACCESS(devvp, accessmode, td->td_proc->p_ucred, td); 236 if (error) 237 error = suser(td); 238 if (error) { 239 vput(devvp); 240 return (error); 241 } 242 VOP_UNLOCK(devvp, 0, td); 243 244 if ((mp->mnt_flag & MNT_UPDATE) == 0) { 245 error = iso_mountfs(devvp, mp, td, &args); 246 } else { 247 if (devvp != imp->im_devvp) 248 error = EINVAL; /* needs translation */ 249 else 250 vrele(devvp); 251 } 252 if (error) { 253 vrele(devvp); 254 return error; 255 } 256 imp = VFSTOISOFS(mp); 257 (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 258 &size); 259 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 260 (void) cd9660_statfs(mp, &mp->mnt_stat, td); 261 return 0; 262 } 263 264 /* 265 * Common code for mount and mountroot 266 */ 267 static int 268 iso_mountfs(struct vnode *devvp, struct mount *mp, struct thread *td, 269 struct iso_args *argp) 270 { 271 struct iso_mnt *isomp = NULL; 272 struct buf *bp = NULL; 273 struct buf *pribp = NULL, *supbp = NULL; 274 dev_t dev; 275 int error = EINVAL; 276 int needclose = 0; 277 int high_sierra = 0; 278 int iso_bsize; 279 int iso_blknum; 280 int joliet_level; 281 struct iso_volume_descriptor *vdp = 0; 282 struct iso_primary_descriptor *pri = NULL; 283 struct iso_sierra_primary_descriptor *pri_sierra = NULL; 284 struct iso_supplementary_descriptor *sup = NULL; 285 struct iso_directory_record *rootp; 286 int logical_block_size; 287 288 if (!(mp->mnt_flag & MNT_RDONLY)) 289 return EROFS; 290 291 /* 292 * Disallow multiple mounts of the same device. 293 * Disallow mounting of a device that is currently in use 294 * Flush out any old buffers remaining from a previous use. 295 */ 296 if ((error = vfs_mountedon(devvp))) 297 return error; 298 if (count_udev(devvp->v_udev) > 0) 299 return EBUSY; 300 if ((error = vinvalbuf(devvp, V_SAVE, td, 0, 0))) 301 return (error); 302 303 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, td); 304 error = VOP_OPEN(devvp, FREAD, FSCRED, NULL, td); 305 VOP_UNLOCK(devvp, 0, td); 306 if (error) 307 return error; 308 dev = devvp->v_rdev; 309 if (dev->si_iosize_max != 0) 310 mp->mnt_iosize_max = dev->si_iosize_max; 311 if (mp->mnt_iosize_max > MAXPHYS) 312 mp->mnt_iosize_max = MAXPHYS; 313 314 needclose = 1; 315 316 /* This is the "logical sector size". The standard says this 317 * should be 2048 or the physical sector size on the device, 318 * whichever is greater. For now, we'll just use a constant. 319 */ 320 iso_bsize = ISO_DEFAULT_BLOCK_SIZE; 321 322 joliet_level = 0; 323 for (iso_blknum = 16 + argp->ssector; 324 iso_blknum < 100 + argp->ssector; 325 iso_blknum++) { 326 if ((error = bread(devvp, iso_blknum * btodb(iso_bsize), 327 iso_bsize, &bp)) != 0) 328 goto out; 329 330 vdp = (struct iso_volume_descriptor *)bp->b_data; 331 if (bcmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) != 0) { 332 if (bcmp (vdp->id_sierra, ISO_SIERRA_ID, 333 sizeof vdp->id) != 0) { 334 error = EINVAL; 335 goto out; 336 } else 337 high_sierra = 1; 338 } 339 switch (isonum_711 (high_sierra? vdp->type_sierra: vdp->type)){ 340 case ISO_VD_PRIMARY: 341 if (pribp == NULL) { 342 pribp = bp; 343 bp = NULL; 344 pri = (struct iso_primary_descriptor *)vdp; 345 pri_sierra = 346 (struct iso_sierra_primary_descriptor *)vdp; 347 } 348 break; 349 350 case ISO_VD_SUPPLEMENTARY: 351 if (supbp == NULL) { 352 supbp = bp; 353 bp = NULL; 354 sup = (struct iso_supplementary_descriptor *)vdp; 355 356 if (!(argp->flags & ISOFSMNT_NOJOLIET)) { 357 if (bcmp(sup->escape, "%/@", 3) == 0) 358 joliet_level = 1; 359 if (bcmp(sup->escape, "%/C", 3) == 0) 360 joliet_level = 2; 361 if (bcmp(sup->escape, "%/E", 3) == 0) 362 joliet_level = 3; 363 364 if ((isonum_711 (sup->flags) & 1) && 365 (argp->flags & ISOFSMNT_BROKENJOLIET) == 0) 366 joliet_level = 0; 367 } 368 } 369 break; 370 371 case ISO_VD_END: 372 goto vd_end; 373 374 default: 375 break; 376 } 377 if (bp) { 378 brelse(bp); 379 bp = NULL; 380 } 381 } 382 vd_end: 383 if (bp) { 384 brelse(bp); 385 bp = NULL; 386 } 387 388 if (pri == NULL) { 389 error = EINVAL; 390 goto out; 391 } 392 393 logical_block_size = 394 isonum_723 (high_sierra? 395 pri_sierra->logical_block_size: 396 pri->logical_block_size); 397 398 if (logical_block_size < DEV_BSIZE || logical_block_size > MAXBSIZE 399 || (logical_block_size & (logical_block_size - 1)) != 0) { 400 error = EINVAL; 401 goto out; 402 } 403 404 rootp = (struct iso_directory_record *) 405 (high_sierra? 406 pri_sierra->root_directory_record: 407 pri->root_directory_record); 408 409 isomp = malloc(sizeof *isomp, M_ISOFSMNT, M_WAITOK | M_ZERO); 410 isomp->logical_block_size = logical_block_size; 411 isomp->volume_space_size = 412 isonum_733 (high_sierra? 413 pri_sierra->volume_space_size: 414 pri->volume_space_size); 415 isomp->joliet_level = 0; 416 /* 417 * Since an ISO9660 multi-session CD can also access previous 418 * sessions, we have to include them into the space consider- 419 * ations. This doesn't yield a very accurate number since 420 * parts of the old sessions might be inaccessible now, but we 421 * can't do much better. This is also important for the NFS 422 * filehandle validation. 423 */ 424 isomp->volume_space_size += argp->ssector; 425 bcopy (rootp, isomp->root, sizeof isomp->root); 426 isomp->root_extent = isonum_733 (rootp->extent); 427 isomp->root_size = isonum_733 (rootp->size); 428 429 isomp->im_bmask = logical_block_size - 1; 430 isomp->im_bshift = ffs(logical_block_size) - 1; 431 432 pribp->b_flags |= B_AGE; 433 brelse(pribp); 434 pribp = NULL; 435 436 mp->mnt_data = (qaddr_t)isomp; 437 mp->mnt_stat.f_fsid.val[0] = dev2udev(dev); 438 mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; 439 mp->mnt_maxsymlinklen = 0; 440 mp->mnt_flag |= MNT_LOCAL; 441 isomp->im_mountp = mp; 442 isomp->im_dev = dev; 443 isomp->im_devvp = devvp; 444 445 dev->si_mountpoint = mp; 446 447 /* Check the Rock Ridge Extention support */ 448 if (!(argp->flags & ISOFSMNT_NORRIP)) { 449 if ((error = bread(isomp->im_devvp, 450 (isomp->root_extent + isonum_711(rootp->ext_attr_length)) << 451 (isomp->im_bshift - DEV_BSHIFT), 452 isomp->logical_block_size, &bp)) != 0) 453 goto out; 454 455 rootp = (struct iso_directory_record *)bp->b_data; 456 457 if ((isomp->rr_skip = cd9660_rrip_offset(rootp,isomp)) < 0) { 458 argp->flags |= ISOFSMNT_NORRIP; 459 } else { 460 argp->flags &= ~ISOFSMNT_GENS; 461 } 462 463 /* 464 * The contents are valid, 465 * but they will get reread as part of another vnode, so... 466 */ 467 bp->b_flags |= B_AGE; 468 brelse(bp); 469 bp = NULL; 470 } 471 isomp->im_flags = argp->flags & (ISOFSMNT_NORRIP | ISOFSMNT_GENS | 472 ISOFSMNT_EXTATT | ISOFSMNT_NOJOLIET); 473 474 if (high_sierra) { 475 /* this effectively ignores all the mount flags */ 476 log(LOG_INFO, "cd9660: High Sierra Format\n"); 477 isomp->iso_ftype = ISO_FTYPE_HIGH_SIERRA; 478 } else { 479 switch (isomp->im_flags&(ISOFSMNT_NORRIP|ISOFSMNT_GENS)) { 480 default: 481 isomp->iso_ftype = ISO_FTYPE_DEFAULT; 482 break; 483 case ISOFSMNT_GENS|ISOFSMNT_NORRIP: 484 isomp->iso_ftype = ISO_FTYPE_9660; 485 break; 486 case 0: 487 log(LOG_INFO, "cd9660: RockRidge Extension\n"); 488 isomp->iso_ftype = ISO_FTYPE_RRIP; 489 break; 490 } 491 } 492 493 /* Decide whether to use the Joliet descriptor */ 494 495 if (isomp->iso_ftype != ISO_FTYPE_RRIP && joliet_level) { 496 log(LOG_INFO, "cd9660: Joliet Extension (Level %d)\n", joliet_level); 497 rootp = (struct iso_directory_record *) 498 sup->root_directory_record; 499 bcopy (rootp, isomp->root, sizeof isomp->root); 500 isomp->root_extent = isonum_733 (rootp->extent); 501 isomp->root_size = isonum_733 (rootp->size); 502 isomp->joliet_level = joliet_level; 503 supbp->b_flags |= B_AGE; 504 } 505 506 if (supbp) { 507 brelse(supbp); 508 supbp = NULL; 509 } 510 511 vfs_add_vnodeops(mp, &mp->mnt_vn_norm_ops, cd9660_vnodeop_entries); 512 vfs_add_vnodeops(mp, &mp->mnt_vn_spec_ops, cd9660_specop_entries); 513 vfs_add_vnodeops(mp, &mp->mnt_vn_fifo_ops, cd9660_fifoop_entries); 514 515 return 0; 516 out: 517 dev->si_mountpoint = NULL; 518 if (bp) 519 brelse(bp); 520 if (pribp) 521 brelse(pribp); 522 if (supbp) 523 brelse(supbp); 524 if (needclose) 525 (void)VOP_CLOSE(devvp, FREAD, td); 526 if (isomp) { 527 free((caddr_t)isomp, M_ISOFSMNT); 528 mp->mnt_data = (qaddr_t)0; 529 } 530 return error; 531 } 532 533 /* 534 * unmount system call 535 */ 536 static int 537 cd9660_unmount(struct mount *mp, int mntflags, struct thread *td) 538 { 539 struct iso_mnt *isomp; 540 int error, flags = 0; 541 542 if (mntflags & MNT_FORCE) 543 flags |= FORCECLOSE; 544 #if 0 545 mntflushbuf(mp, 0); 546 if (mntinvalbuf(mp)) 547 return EBUSY; 548 #endif 549 if ((error = vflush(mp, 0, flags))) 550 return (error); 551 552 isomp = VFSTOISOFS(mp); 553 554 isomp->im_devvp->v_rdev->si_mountpoint = NULL; 555 error = VOP_CLOSE(isomp->im_devvp, FREAD, td); 556 vrele(isomp->im_devvp); 557 free((caddr_t)isomp, M_ISOFSMNT); 558 mp->mnt_data = (qaddr_t)0; 559 mp->mnt_flag &= ~MNT_LOCAL; 560 return (error); 561 } 562 563 /* 564 * Return root of a filesystem 565 */ 566 static int 567 cd9660_root(struct mount *mp, struct vnode **vpp) 568 { 569 struct iso_mnt *imp = VFSTOISOFS(mp); 570 struct iso_directory_record *dp = 571 (struct iso_directory_record *)imp->root; 572 ino_t ino = isodirino(dp, imp); 573 574 /* 575 * With RRIP we must use the `.' entry of the root directory. 576 * Simply tell vget, that it's a relocated directory. 577 */ 578 return (cd9660_vget_internal(mp, ino, vpp, 579 imp->iso_ftype == ISO_FTYPE_RRIP, dp)); 580 } 581 582 /* 583 * Get file system statistics. 584 */ 585 int 586 cd9660_statfs(struct mount *mp, struct statfs *sbp, struct thread *td) 587 { 588 struct iso_mnt *isomp; 589 590 isomp = VFSTOISOFS(mp); 591 592 sbp->f_bsize = isomp->logical_block_size; 593 sbp->f_iosize = sbp->f_bsize; /* XXX */ 594 sbp->f_blocks = isomp->volume_space_size; 595 sbp->f_bfree = 0; /* total free blocks */ 596 sbp->f_bavail = 0; /* blocks free for non superuser */ 597 sbp->f_files = 0; /* total files */ 598 sbp->f_ffree = 0; /* free file nodes */ 599 if (sbp != &mp->mnt_stat) { 600 sbp->f_type = mp->mnt_vfc->vfc_typenum; 601 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN); 602 } 603 return 0; 604 } 605 606 /* 607 * File handle to vnode 608 * 609 * Have to be really careful about stale file handles: 610 * - check that the inode number is in range 611 * - call iget() to get the locked inode 612 * - check for an unallocated inode (i_mode == 0) 613 * - check that the generation number matches 614 */ 615 616 struct ifid { 617 ushort ifid_len; 618 ushort ifid_pad; 619 int ifid_ino; 620 long ifid_start; 621 }; 622 623 /* ARGSUSED */ 624 int 625 cd9660_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp) 626 { 627 struct ifid *ifhp = (struct ifid *)fhp; 628 struct iso_node *ip; 629 struct vnode *nvp; 630 int error; 631 632 #ifdef ISOFS_DBG 633 printf("fhtovp: ino %d, start %ld\n", 634 ifhp->ifid_ino, ifhp->ifid_start); 635 #endif 636 637 if ((error = VFS_VGET(mp, ifhp->ifid_ino, &nvp)) != 0) { 638 *vpp = NULLVP; 639 return (error); 640 } 641 ip = VTOI(nvp); 642 if (ip->inode.iso_mode == 0) { 643 vput(nvp); 644 *vpp = NULLVP; 645 return (ESTALE); 646 } 647 *vpp = nvp; 648 return (0); 649 } 650 651 int 652 cd9660_checkexp(struct mount *mp, struct sockaddr *nam, int *exflagsp, 653 struct ucred **credanonp) 654 { 655 struct netcred *np; 656 struct iso_mnt *imp; 657 658 imp = VFSTOISOFS(mp); 659 660 /* 661 * Get the export permission structure for this <mp, client> tuple. 662 */ 663 np = vfs_export_lookup(mp, &imp->im_export, nam); 664 if (np == NULL) 665 return (EACCES); 666 667 *exflagsp = np->netc_exflags; 668 *credanonp = &np->netc_anon; 669 return (0); 670 } 671 672 int 673 cd9660_vget(struct mount *mp, ino_t ino, struct vnode **vpp) 674 { 675 676 /* 677 * XXXX 678 * It would be nice if we didn't always set the `relocated' flag 679 * and force the extra read, but I don't want to think about fixing 680 * that right now. 681 */ 682 return (cd9660_vget_internal(mp, ino, vpp, 683 #if 0 684 VFSTOISOFS(mp)->iso_ftype == ISO_FTYPE_RRIP, 685 #else 686 0, 687 #endif 688 (struct iso_directory_record *)0)); 689 } 690 691 int 692 cd9660_vget_internal(struct mount *mp, ino_t ino, struct vnode **vpp, 693 int relocated, struct iso_directory_record *isodir) 694 { 695 /*struct thread *td = curthread;*/ 696 struct iso_mnt *imp; 697 struct iso_node *ip; 698 struct buf *bp; 699 struct vnode *vp; 700 dev_t dev; 701 int error; 702 703 imp = VFSTOISOFS(mp); 704 dev = imp->im_dev; 705 again: 706 if ((*vpp = cd9660_ihashget(dev, ino)) != NULLVP) 707 return (0); 708 709 /* Allocate a new vnode/iso_node. */ 710 error = getnewvnode(VT_ISOFS, mp, &vp, 0, 0); 711 if (error) { 712 *vpp = NULLVP; 713 return (error); 714 } 715 MALLOC(ip, struct iso_node *, sizeof(struct iso_node), M_ISOFSNODE, 716 M_WAITOK); 717 bzero((caddr_t)ip, sizeof(struct iso_node)); 718 ip->i_vnode = vp; 719 ip->i_dev = dev; 720 ip->i_number = ino; 721 722 /* 723 * Insert it into the inode hash table and check for a collision. 724 * If a collision occurs, throw away the vnode and try again. 725 */ 726 if (cd9660_ihashins(ip) != 0) { 727 printf("debug: cd9660 ihashins collision, retrying\n"); 728 vx_put(vp); 729 free(ip, M_ISOFSNODE); 730 goto again; 731 } 732 vp->v_data = ip; 733 734 if (isodir == 0) { 735 int lbn, off; 736 737 lbn = lblkno(imp, ino); 738 if (lbn >= imp->volume_space_size) { 739 vx_put(vp); 740 printf("fhtovp: lbn exceed volume space %d\n", lbn); 741 return (ESTALE); 742 } 743 744 off = blkoff(imp, ino); 745 if (off + ISO_DIRECTORY_RECORD_SIZE > imp->logical_block_size) { 746 vx_put(vp); 747 printf("fhtovp: crosses block boundary %d\n", 748 off + ISO_DIRECTORY_RECORD_SIZE); 749 return (ESTALE); 750 } 751 752 error = bread(imp->im_devvp, 753 lbn << (imp->im_bshift - DEV_BSHIFT), 754 imp->logical_block_size, &bp); 755 if (error) { 756 vx_put(vp); 757 brelse(bp); 758 printf("fhtovp: bread error %d\n",error); 759 return (error); 760 } 761 isodir = (struct iso_directory_record *)(bp->b_data + off); 762 763 if (off + isonum_711(isodir->length) > 764 imp->logical_block_size) { 765 vx_put(vp); 766 if (bp != 0) 767 brelse(bp); 768 printf("fhtovp: directory crosses block boundary %d[off=%d/len=%d]\n", 769 off +isonum_711(isodir->length), off, 770 isonum_711(isodir->length)); 771 return (ESTALE); 772 } 773 774 #if 0 775 if (isonum_733(isodir->extent) + 776 isonum_711(isodir->ext_attr_length) != ifhp->ifid_start) { 777 if (bp != 0) 778 brelse(bp); 779 printf("fhtovp: file start miss %d vs %d\n", 780 isonum_733(isodir->extent) + isonum_711(isodir->ext_attr_length), 781 ifhp->ifid_start); 782 return (ESTALE); 783 } 784 #endif 785 } else 786 bp = 0; 787 788 ip->i_mnt = imp; 789 ip->i_devvp = imp->im_devvp; 790 vref(ip->i_devvp); 791 792 if (relocated) { 793 /* 794 * On relocated directories we must 795 * read the `.' entry out of a dir. 796 */ 797 ip->iso_start = ino >> imp->im_bshift; 798 if (bp != 0) 799 brelse(bp); 800 if ((error = cd9660_blkatoff(vp, (off_t)0, NULL, &bp)) != 0) { 801 vx_put(vp); 802 return (error); 803 } 804 isodir = (struct iso_directory_record *)bp->b_data; 805 } 806 807 ip->iso_extent = isonum_733(isodir->extent); 808 ip->i_size = isonum_733(isodir->size); 809 ip->iso_start = isonum_711(isodir->ext_attr_length) + ip->iso_extent; 810 811 /* 812 * Setup time stamp, attribute 813 */ 814 vp->v_type = VNON; 815 switch (imp->iso_ftype) { 816 default: /* ISO_FTYPE_9660 */ 817 { 818 struct buf *bp2; 819 int off; 820 if ((imp->im_flags & ISOFSMNT_EXTATT) 821 && (off = isonum_711(isodir->ext_attr_length))) 822 cd9660_blkatoff(vp, (off_t)-(off << imp->im_bshift), NULL, 823 &bp2); 824 else 825 bp2 = NULL; 826 cd9660_defattr(isodir, ip, bp2, ISO_FTYPE_9660); 827 cd9660_deftstamp(isodir, ip, bp2, ISO_FTYPE_9660); 828 if (bp2) 829 brelse(bp2); 830 break; 831 } 832 case ISO_FTYPE_RRIP: 833 cd9660_rrip_analyze(isodir, ip, imp); 834 break; 835 } 836 837 if (bp != 0) 838 brelse(bp); 839 840 /* 841 * Initialize the associated vnode 842 */ 843 switch (vp->v_type = IFTOVT(ip->inode.iso_mode)) { 844 case VFIFO: 845 vp->v_ops = &mp->mnt_vn_fifo_ops; 846 break; 847 case VCHR: 848 case VBLK: 849 vp->v_ops = &mp->mnt_vn_spec_ops; 850 addaliasu(vp, ip->inode.iso_rdev); 851 break; 852 default: 853 break; 854 } 855 856 if (ip->iso_extent == imp->root_extent) 857 vp->v_flag |= VROOT; 858 859 /* 860 * Return the locked and refd vp 861 */ 862 *vpp = vp; 863 return (0); 864 } 865 866 /* 867 * Vnode pointer to File handle 868 */ 869 /* ARGSUSED */ 870 int 871 cd9660_vptofh(struct vnode *vp, struct fid *fhp) 872 { 873 struct iso_node *ip = VTOI(vp); 874 struct ifid *ifhp; 875 876 ifhp = (struct ifid *)fhp; 877 ifhp->ifid_len = sizeof(struct ifid); 878 879 ifhp->ifid_ino = ip->i_number; 880 ifhp->ifid_start = ip->iso_start; 881 882 #ifdef ISOFS_DBG 883 printf("vptofh: ino %d, start %ld\n", 884 ifhp->ifid_ino,ifhp->ifid_start); 885 #endif 886 return 0; 887 } 888