214 vap->va_fileid = ip->i_number; 215 216 vap->va_mode = ip->inode.iso_mode; 217 vap->va_nlink = ip->inode.iso_links; 218 vap->va_uid = ip->inode.iso_uid; 219 vap->va_gid = ip->inode.iso_gid; 220 vap->va_atime = ip->inode.iso_atime; 221 vap->va_mtime = ip->inode.iso_mtime; 222 vap->va_ctime = ip->inode.iso_ctime; 223 vap->va_rdev = ip->inode.iso_rdev; 224 225 vap->va_size = (u_quad_t) ip->i_size; 226 if (ip->i_size == 0 && (vap->va_mode & S_IFMT) == S_IFLNK) { 227 struct vop_readlink_args rdlnk; 228 struct iovec aiov; 229 struct uio auio; 230 char *cp; 231 232 MALLOC(cp, char *, MAXPATHLEN, M_TEMP, M_WAITOK); 233 aiov.iov_base = cp; 234 aiov.iov_len = MAXPATHLEN; 235 auio.uio_iov = &aiov; 236 auio.uio_iovcnt = 1; 237 auio.uio_offset = 0; 238 auio.uio_rw = UIO_READ; 239 auio.uio_segflg = UIO_SYSSPACE; 240 auio.uio_procp = ap->a_p; 241 auio.uio_resid = MAXPATHLEN; 242 rdlnk.a_uio = &auio; 243 rdlnk.a_vp = ap->a_vp; 244 rdlnk.a_cred = ap->a_cred; 245 if (cd9660_readlink(&rdlnk) == 0) 246 vap->va_size = MAXPATHLEN - auio.uio_resid; 247 FREE(cp, M_TEMP); 248 } 249 vap->va_flags = 0; 250 vap->va_gen = 1; 251 vap->va_blocksize = ip->i_mnt->logical_block_size; 252 vap->va_bytes = (u_quad_t) ip->i_size; 253 vap->va_type = vp->v_type; 254 vap->va_filerev = 0; 255 return (0); 256} 257 258/* 259 * Vnode op for reading. 260 */ 261static int 262cd9660_read(ap) 263 struct vop_read_args /* { 264 struct vnode *a_vp; 265 struct uio *a_uio; 266 int a_ioflag; 267 struct ucred *a_cred; 268 } */ *ap; 269{ 270 struct vnode *vp = ap->a_vp; 271 register struct uio *uio = ap->a_uio; 272 register struct iso_node *ip = VTOI(vp); 273 register struct iso_mnt *imp; 274 struct buf *bp; 275 daddr_t lbn, rablock; 276 off_t diff; 277 int rasize, error = 0; 278 long size, n, on; 279 280 if (uio->uio_resid == 0) 281 return (0); 282 if (uio->uio_offset < 0) 283 return (EINVAL); 284 ip->i_flag |= IN_ACCESS; 285 imp = ip->i_mnt; 286 do { 287 lbn = lblkno(imp, uio->uio_offset); 288 on = blkoff(imp, uio->uio_offset); 289 n = min((u_int)(imp->logical_block_size - on), 290 uio->uio_resid); 291 diff = (off_t)ip->i_size - uio->uio_offset; 292 if (diff <= 0) 293 return (0); 294 if (diff < n) 295 n = diff; 296 size = blksize(imp, ip, lbn); 297 rablock = lbn + 1; 298 if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) { 299 if (lblktosize(imp, rablock) < ip->i_size) 300 error = cluster_read(vp, (off_t)ip->i_size, 301 lbn, size, NOCRED, uio->uio_resid, 302 (ap->a_ioflag >> 16), &bp); 303 else 304 error = bread(vp, lbn, size, NOCRED, &bp); 305 } else { 306 if (vp->v_lastr + 1 == lbn && 307 lblktosize(imp, rablock) < ip->i_size) { 308 rasize = blksize(imp, ip, rablock); 309 error = breadn(vp, lbn, size, &rablock, 310 &rasize, 1, NOCRED, &bp); 311 } else 312 error = bread(vp, lbn, size, NOCRED, &bp); 313 } 314 vp->v_lastr = lbn; 315 n = min(n, size - bp->b_resid); 316 if (error) { 317 brelse(bp); 318 return (error); 319 } 320 321 error = uiomove(bp->b_data + on, (int)n, uio); 322 brelse(bp); 323 } while (error == 0 && uio->uio_resid > 0 && n != 0); 324 return (error); 325} 326 327/* 328 * Structure for reading directories 329 */ 330struct isoreaddir { 331 struct dirent saveent; 332 struct dirent assocent; 333 struct dirent current; 334 off_t saveoff; 335 off_t assocoff; 336 off_t curroff; 337 struct uio *uio; 338 off_t uio_off; 339 int eofflag; 340 u_long *cookies; 341 int ncookies; 342}; 343 344int 345iso_uiodir(idp,dp,off) 346 struct isoreaddir *idp; 347 struct dirent *dp; 348 off_t off; 349{ 350 int error; 351 352 dp->d_name[dp->d_namlen] = 0; 353 dp->d_reclen = GENERIC_DIRSIZ(dp); 354 355 if (idp->uio->uio_resid < dp->d_reclen) { 356 idp->eofflag = 0; 357 return (-1); 358 } 359 360 if (idp->cookies) { 361 if (idp->ncookies <= 0) { 362 idp->eofflag = 0; 363 return (-1); 364 } 365 366 *idp->cookies++ = off; 367 --idp->ncookies; 368 } 369 370 if ((error = uiomove((caddr_t) dp,dp->d_reclen,idp->uio)) != 0) 371 return (error); 372 idp->uio_off = off; 373 return (0); 374} 375 376int 377iso_shipdir(idp) 378 struct isoreaddir *idp; 379{ 380 struct dirent *dp; 381 int cl, sl, assoc; 382 int error; 383 char *cname, *sname; 384 385 cl = idp->current.d_namlen; 386 cname = idp->current.d_name; 387assoc = (cl > 1) && (*cname == ASSOCCHAR); 388 if (assoc) { 389 cl--; 390 cname++; 391 } 392 393 dp = &idp->saveent; 394 sname = dp->d_name; 395 if (!(sl = dp->d_namlen)) { 396 dp = &idp->assocent; 397 sname = dp->d_name + 1; 398 sl = dp->d_namlen - 1; 399 } 400 if (sl > 0) { 401 if (sl != cl 402 || bcmp(sname,cname,sl)) { 403 if (idp->assocent.d_namlen) { 404 if ((error = iso_uiodir(idp,&idp->assocent,idp->assocoff)) != 0) 405 return (error); 406 idp->assocent.d_namlen = 0; 407 } 408 if (idp->saveent.d_namlen) { 409 if ((error = iso_uiodir(idp,&idp->saveent,idp->saveoff)) != 0) 410 return (error); 411 idp->saveent.d_namlen = 0; 412 } 413 } 414 } 415 idp->current.d_reclen = GENERIC_DIRSIZ(&idp->current); 416 if (assoc) { 417 idp->assocoff = idp->curroff; 418 bcopy(&idp->current,&idp->assocent,idp->current.d_reclen); 419 } else { 420 idp->saveoff = idp->curroff; 421 bcopy(&idp->current,&idp->saveent,idp->current.d_reclen); 422 } 423 return (0); 424} 425 426/* 427 * Vnode op for readdir 428 */ 429static int 430cd9660_readdir(ap) 431 struct vop_readdir_args /* { 432 struct vnode *a_vp; 433 struct uio *a_uio; 434 struct ucred *a_cred; 435 int *a_eofflag; 436 int *a_ncookies; 437 u_long *a_cookies; 438 } */ *ap; 439{ 440 register struct uio *uio = ap->a_uio; 441 struct isoreaddir *idp; 442 struct vnode *vdp = ap->a_vp; 443 struct iso_node *dp; 444 struct iso_mnt *imp; 445 struct buf *bp = NULL; 446 struct iso_directory_record *ep; 447 int entryoffsetinblock; 448 doff_t endsearch; 449 u_long bmask; 450 int error = 0; 451 int reclen; 452 u_short namelen; 453 int ncookies = 0; 454 u_long *cookies = NULL; 455 456 dp = VTOI(vdp); 457 imp = dp->i_mnt; 458 bmask = imp->im_bmask; 459 460 MALLOC(idp, struct isoreaddir *, sizeof(*idp), M_TEMP, M_WAITOK); 461 idp->saveent.d_namlen = idp->assocent.d_namlen = 0; 462 /* 463 * XXX 464 * Is it worth trying to figure out the type? 465 */ 466 idp->saveent.d_type = idp->assocent.d_type = idp->current.d_type = 467 DT_UNKNOWN; 468 idp->uio = uio; 469 if (ap->a_ncookies == NULL) { 470 idp->cookies = NULL; 471 } else { 472 /* 473 * Guess the number of cookies needed. 474 */ 475 ncookies = uio->uio_resid / 16; 476 MALLOC(cookies, u_long *, ncookies * sizeof(u_int), M_TEMP, 477 M_WAITOK); 478 idp->cookies = cookies; 479 idp->ncookies = ncookies; 480 } 481 idp->eofflag = 1; 482 idp->curroff = uio->uio_offset; 483 484 if ((entryoffsetinblock = idp->curroff & bmask) && 485 (error = cd9660_blkatoff(vdp, (off_t)idp->curroff, NULL, &bp))) { 486 FREE(idp, M_TEMP); 487 return (error); 488 } 489 endsearch = dp->i_size; 490 491 while (idp->curroff < endsearch) { 492 /* 493 * If offset is on a block boundary, 494 * read the next directory block. 495 * Release previous if it exists. 496 */ 497 if ((idp->curroff & bmask) == 0) { 498 if (bp != NULL) 499 brelse(bp); 500 if ((error = 501 cd9660_blkatoff(vdp, (off_t)idp->curroff, NULL, &bp)) != 0) 502 break; 503 entryoffsetinblock = 0; 504 } 505 /* 506 * Get pointer to next entry. 507 */ 508 ep = (struct iso_directory_record *) 509 ((char *)bp->b_data + entryoffsetinblock); 510 511 reclen = isonum_711(ep->length); 512 if (reclen == 0) { 513 /* skip to next block, if any */ 514 idp->curroff = 515 (idp->curroff & ~bmask) + imp->logical_block_size; 516 continue; 517 } 518 519 if (reclen < ISO_DIRECTORY_RECORD_SIZE) { 520 error = EINVAL; 521 /* illegal entry, stop */ 522 break; 523 } 524 525 if (entryoffsetinblock + reclen > imp->logical_block_size) { 526 error = EINVAL; 527 /* illegal directory, so stop looking */ 528 break; 529 } 530 531 idp->current.d_namlen = isonum_711(ep->name_len); 532 533 if (reclen < ISO_DIRECTORY_RECORD_SIZE + idp->current.d_namlen) { 534 error = EINVAL; 535 /* illegal entry, stop */ 536 break; 537 } 538 539 if (isonum_711(ep->flags)&2) 540 idp->current.d_fileno = isodirino(ep, imp); 541 else 542 idp->current.d_fileno = dbtob(bp->b_blkno) + 543 entryoffsetinblock; 544 545 idp->curroff += reclen; 546 547 switch (imp->iso_ftype) { 548 case ISO_FTYPE_RRIP: 549 cd9660_rrip_getname(ep,idp->current.d_name, &namelen, 550 &idp->current.d_fileno,imp); 551 idp->current.d_namlen = (u_char)namelen; 552 if (idp->current.d_namlen) 553 error = iso_uiodir(idp,&idp->current,idp->curroff); 554 break; 555 default: /* ISO_FTYPE_DEFAULT || ISO_FTYPE_9660 || ISO_FTYPE_HIGH_SIERRA*/ 556 strcpy(idp->current.d_name,".."); 557 if (idp->current.d_namlen == 1 && ep->name[0] == 0) { 558 idp->current.d_namlen = 1; 559 error = iso_uiodir(idp,&idp->current,idp->curroff); 560 } else if (idp->current.d_namlen == 1 && ep->name[0] == 1) { 561 idp->current.d_namlen = 2; 562 error = iso_uiodir(idp,&idp->current,idp->curroff); 563 } else { 564 isofntrans(ep->name,idp->current.d_namlen, 565 idp->current.d_name, &namelen, 566 imp->iso_ftype == ISO_FTYPE_9660, 567 isonum_711(ep->flags)&4, 568 imp->joliet_level); 569 idp->current.d_namlen = (u_char)namelen; 570 if (imp->iso_ftype == ISO_FTYPE_DEFAULT) 571 error = iso_shipdir(idp); 572 else 573 error = iso_uiodir(idp,&idp->current,idp->curroff); 574 } 575 } 576 if (error) 577 break; 578 579 entryoffsetinblock += reclen; 580 } 581 582 if (!error && imp->iso_ftype == ISO_FTYPE_DEFAULT) { 583 idp->current.d_namlen = 0; 584 error = iso_shipdir(idp); 585 } 586 if (error < 0) 587 error = 0; 588 589 if (ap->a_ncookies != NULL) { 590 if (error) 591 free(cookies, M_TEMP); 592 else { 593 /* 594 * Work out the number of cookies actually used. 595 */ 596 *ap->a_ncookies = ncookies - idp->ncookies; 597 *ap->a_cookies = cookies; 598 } 599 } 600 601 if (bp) 602 brelse (bp); 603 604 uio->uio_offset = idp->uio_off; 605 *ap->a_eofflag = idp->eofflag; 606 607 FREE(idp, M_TEMP); 608 609 return (error); 610} 611 612/* 613 * Return target name of a symbolic link 614 * Shouldn't we get the parent vnode and read the data from there? 615 * This could eventually result in deadlocks in cd9660_lookup. 616 * But otherwise the block read here is in the block buffer two times. 617 */ 618typedef struct iso_directory_record ISODIR; 619typedef struct iso_node ISONODE; 620typedef struct iso_mnt ISOMNT; 621static int 622cd9660_readlink(ap) 623 struct vop_readlink_args /* { 624 struct vnode *a_vp; 625 struct uio *a_uio; 626 struct ucred *a_cred; 627 } */ *ap; 628{ 629 ISONODE *ip; 630 ISODIR *dirp; 631 ISOMNT *imp; 632 struct buf *bp; 633 struct uio *uio; 634 u_short symlen; 635 int error; 636 char *symname; 637 638 ip = VTOI(ap->a_vp); 639 imp = ip->i_mnt; 640 uio = ap->a_uio; 641 642 if (imp->iso_ftype != ISO_FTYPE_RRIP) 643 return (EINVAL); 644 645 /* 646 * Get parents directory record block that this inode included. 647 */ 648 error = bread(imp->im_devvp, 649 (ip->i_number >> imp->im_bshift) << 650 (imp->im_bshift - DEV_BSHIFT), 651 imp->logical_block_size, NOCRED, &bp); 652 if (error) { 653 brelse(bp); 654 return (EINVAL); 655 } 656 657 /* 658 * Setup the directory pointer for this inode 659 */ 660 dirp = (ISODIR *)(bp->b_data + (ip->i_number & imp->im_bmask)); 661 662 /* 663 * Just make sure, we have a right one.... 664 * 1: Check not cross boundary on block 665 */ 666 if ((ip->i_number & imp->im_bmask) + isonum_711(dirp->length) 667 > (unsigned)imp->logical_block_size) { 668 brelse(bp); 669 return (EINVAL); 670 } 671 672 /* 673 * Now get a buffer 674 * Abuse a namei buffer for now. 675 */ 676 if (uio->uio_segflg == UIO_SYSSPACE) 677 symname = uio->uio_iov->iov_base; 678 else 679 symname = zalloc(namei_zone); 680 681 /* 682 * Ok, we just gathering a symbolic name in SL record. 683 */ 684 if (cd9660_rrip_getsymname(dirp, symname, &symlen, imp) == 0) { 685 if (uio->uio_segflg != UIO_SYSSPACE) 686 zfree(namei_zone, symname); 687 brelse(bp); 688 return (EINVAL); 689 } 690 /* 691 * Don't forget before you leave from home ;-) 692 */ 693 brelse(bp); 694 695 /* 696 * return with the symbolic name to caller's. 697 */ 698 if (uio->uio_segflg != UIO_SYSSPACE) { 699 error = uiomove(symname, symlen, uio); 700 zfree(namei_zone, symname); 701 return (error); 702 } 703 uio->uio_resid -= symlen; 704 uio->uio_iov->iov_base += symlen; 705 uio->uio_iov->iov_len -= symlen; 706 return (0); 707} 708 709/* 710 * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually 711 * done. If a buffer has been saved in anticipation of a CREATE, delete it. 712 */ 713static int 714cd9660_abortop(ap) 715 struct vop_abortop_args /* { 716 struct vnode *a_dvp; 717 struct componentname *a_cnp; 718 } */ *ap; 719{ 720 if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) 721 zfree(namei_zone, ap->a_cnp->cn_pnbuf); 722 return (0); 723} 724 725/* 726 * Calculate the logical to physical mapping if not done already, 727 * then call the device strategy routine. 728 */ 729static int 730cd9660_strategy(ap) 731 struct vop_strategy_args /* { 732 struct buf *a_vp; 733 struct buf *a_bp; 734 } */ *ap; 735{ 736 register struct buf *bp = ap->a_bp; 737 register struct vnode *vp = bp->b_vp; 738 register struct iso_node *ip; 739 int error; 740 741 ip = VTOI(vp); 742 if (vp->v_type == VBLK || vp->v_type == VCHR) 743 panic("cd9660_strategy: spec"); 744 if (bp->b_blkno == bp->b_lblkno) { 745 if ((error = 746 VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL, NULL))) { 747 bp->b_error = error; 748 bp->b_flags |= B_ERROR; 749 biodone(bp); 750 return (error); 751 } 752 if ((long)bp->b_blkno == -1) 753 clrbuf(bp); 754 } 755 if ((long)bp->b_blkno == -1) { 756 biodone(bp); 757 return (0); 758 } 759 vp = ip->i_devvp; 760 bp->b_dev = vp->v_rdev; 761 VOP_STRATEGY(vp, bp); 762 return (0); 763} 764 765/* 766 * Print out the contents of an inode. 767 */ 768static int 769cd9660_print(ap) 770 struct vop_print_args /* { 771 struct vnode *a_vp; 772 } */ *ap; 773{ 774 775 printf("tag VT_ISOFS, isofs vnode\n"); 776 return (0); 777} 778 779/* 780 * Return POSIX pathconf information applicable to cd9660 filesystems. 781 */ 782static int 783cd9660_pathconf(ap) 784 struct vop_pathconf_args /* { 785 struct vnode *a_vp; 786 int a_name; 787 register_t *a_retval; 788 } */ *ap; 789{ 790 791 switch (ap->a_name) { 792 case _PC_LINK_MAX: 793 *ap->a_retval = 1; 794 return (0); 795 case _PC_NAME_MAX: 796 if (VTOI(ap->a_vp)->i_mnt->iso_ftype == ISO_FTYPE_RRIP) 797 *ap->a_retval = NAME_MAX; 798 else 799 *ap->a_retval = 37; 800 return (0); 801 case _PC_PATH_MAX: 802 *ap->a_retval = PATH_MAX; 803 return (0); 804 case _PC_PIPE_BUF: 805 *ap->a_retval = PIPE_BUF; 806 return (0); 807 case _PC_CHOWN_RESTRICTED: 808 *ap->a_retval = 1; 809 return (0); 810 case _PC_NO_TRUNC: 811 *ap->a_retval = 1; 812 return (0); 813 default: 814 return (EINVAL); 815 } 816 /* NOTREACHED */ 817} 818 819/* 820 * get page routine 821 * 822 * XXX By default, wimp out... note that a_offset is ignored (and always 823 * XXX has been). 824 */ 825int 826cd9660_getpages(ap) 827 struct vop_getpages_args *ap; 828{ 829 return vnode_pager_generic_getpages(ap->a_vp, ap->a_m, ap->a_count, 830 ap->a_reqpage); 831} 832 833/* 834 * put page routine 835 * 836 * XXX By default, wimp out... note that a_offset is ignored (and always 837 * XXX has been). 838 */ 839int 840cd9660_putpages(ap) 841 struct vop_putpages_args *ap; 842{ 843 return vnode_pager_generic_putpages(ap->a_vp, ap->a_m, ap->a_count, 844 ap->a_sync, ap->a_rtvals); 845} 846 847/* 848 * Global vfs data structures for cd9660 849 */ 850vop_t **cd9660_vnodeop_p; 851static struct vnodeopv_entry_desc cd9660_vnodeop_entries[] = { 852 { &vop_default_desc, (vop_t *) vop_defaultop }, 853 { &vop_abortop_desc, (vop_t *) cd9660_abortop }, 854 { &vop_access_desc, (vop_t *) cd9660_access }, 855 { &vop_bmap_desc, (vop_t *) cd9660_bmap }, 856 { &vop_cachedlookup_desc, (vop_t *) cd9660_lookup }, 857 { &vop_getattr_desc, (vop_t *) cd9660_getattr }, 858 { &vop_inactive_desc, (vop_t *) cd9660_inactive }, 859 { &vop_islocked_desc, (vop_t *) vop_stdislocked }, 860 { &vop_lock_desc, (vop_t *) vop_stdlock }, 861 { &vop_lookup_desc, (vop_t *) vfs_cache_lookup }, 862 { &vop_pathconf_desc, (vop_t *) cd9660_pathconf }, 863 { &vop_print_desc, (vop_t *) cd9660_print }, 864 { &vop_read_desc, (vop_t *) cd9660_read }, 865 { &vop_readdir_desc, (vop_t *) cd9660_readdir }, 866 { &vop_readlink_desc, (vop_t *) cd9660_readlink }, 867 { &vop_reclaim_desc, (vop_t *) cd9660_reclaim }, 868 { &vop_setattr_desc, (vop_t *) cd9660_setattr }, 869 { &vop_strategy_desc, (vop_t *) cd9660_strategy }, 870 { &vop_unlock_desc, (vop_t *) vop_stdunlock }, 871 { &vop_getpages_desc, (vop_t *) cd9660_getpages }, 872 { &vop_putpages_desc, (vop_t *) cd9660_putpages }, 873 { NULL, NULL } 874}; 875static struct vnodeopv_desc cd9660_vnodeop_opv_desc = 876 { &cd9660_vnodeop_p, cd9660_vnodeop_entries }; 877VNODEOP_SET(cd9660_vnodeop_opv_desc); 878 879/* 880 * Special device vnode ops 881 */ 882vop_t **cd9660_specop_p; 883static struct vnodeopv_entry_desc cd9660_specop_entries[] = { 884 { &vop_default_desc, (vop_t *) spec_vnoperate }, 885 { &vop_access_desc, (vop_t *) cd9660_access }, 886 { &vop_getattr_desc, (vop_t *) cd9660_getattr }, 887 { &vop_inactive_desc, (vop_t *) cd9660_inactive }, 888 { &vop_islocked_desc, (vop_t *) vop_stdislocked }, 889 { &vop_lock_desc, (vop_t *) vop_stdlock }, 890 { &vop_print_desc, (vop_t *) cd9660_print }, 891 { &vop_reclaim_desc, (vop_t *) cd9660_reclaim }, 892 { &vop_setattr_desc, (vop_t *) cd9660_setattr }, 893 { &vop_unlock_desc, (vop_t *) vop_stdunlock }, 894 { NULL, NULL } 895}; 896static struct vnodeopv_desc cd9660_specop_opv_desc = 897 { &cd9660_specop_p, cd9660_specop_entries }; 898VNODEOP_SET(cd9660_specop_opv_desc); 899 900vop_t **cd9660_fifoop_p; 901static struct vnodeopv_entry_desc cd9660_fifoop_entries[] = { 902 { &vop_default_desc, (vop_t *) fifo_vnoperate }, 903 { &vop_access_desc, (vop_t *) cd9660_access }, 904 { &vop_getattr_desc, (vop_t *) cd9660_getattr }, 905 { &vop_inactive_desc, (vop_t *) cd9660_inactive }, 906 { &vop_islocked_desc, (vop_t *) vop_stdislocked }, 907 { &vop_lock_desc, (vop_t *) vop_stdlock }, 908 { &vop_print_desc, (vop_t *) cd9660_print }, 909 { &vop_reclaim_desc, (vop_t *) cd9660_reclaim }, 910 { &vop_setattr_desc, (vop_t *) cd9660_setattr }, 911 { &vop_unlock_desc, (vop_t *) vop_stdunlock }, 912 { NULL, NULL } 913}; 914static struct vnodeopv_desc cd9660_fifoop_opv_desc = 915 { &cd9660_fifoop_p, cd9660_fifoop_entries }; 916 917VNODEOP_SET(cd9660_fifoop_opv_desc);
| 214 vap->va_fileid = ip->i_number; 215 216 vap->va_mode = ip->inode.iso_mode; 217 vap->va_nlink = ip->inode.iso_links; 218 vap->va_uid = ip->inode.iso_uid; 219 vap->va_gid = ip->inode.iso_gid; 220 vap->va_atime = ip->inode.iso_atime; 221 vap->va_mtime = ip->inode.iso_mtime; 222 vap->va_ctime = ip->inode.iso_ctime; 223 vap->va_rdev = ip->inode.iso_rdev; 224 225 vap->va_size = (u_quad_t) ip->i_size; 226 if (ip->i_size == 0 && (vap->va_mode & S_IFMT) == S_IFLNK) { 227 struct vop_readlink_args rdlnk; 228 struct iovec aiov; 229 struct uio auio; 230 char *cp; 231 232 MALLOC(cp, char *, MAXPATHLEN, M_TEMP, M_WAITOK); 233 aiov.iov_base = cp; 234 aiov.iov_len = MAXPATHLEN; 235 auio.uio_iov = &aiov; 236 auio.uio_iovcnt = 1; 237 auio.uio_offset = 0; 238 auio.uio_rw = UIO_READ; 239 auio.uio_segflg = UIO_SYSSPACE; 240 auio.uio_procp = ap->a_p; 241 auio.uio_resid = MAXPATHLEN; 242 rdlnk.a_uio = &auio; 243 rdlnk.a_vp = ap->a_vp; 244 rdlnk.a_cred = ap->a_cred; 245 if (cd9660_readlink(&rdlnk) == 0) 246 vap->va_size = MAXPATHLEN - auio.uio_resid; 247 FREE(cp, M_TEMP); 248 } 249 vap->va_flags = 0; 250 vap->va_gen = 1; 251 vap->va_blocksize = ip->i_mnt->logical_block_size; 252 vap->va_bytes = (u_quad_t) ip->i_size; 253 vap->va_type = vp->v_type; 254 vap->va_filerev = 0; 255 return (0); 256} 257 258/* 259 * Vnode op for reading. 260 */ 261static int 262cd9660_read(ap) 263 struct vop_read_args /* { 264 struct vnode *a_vp; 265 struct uio *a_uio; 266 int a_ioflag; 267 struct ucred *a_cred; 268 } */ *ap; 269{ 270 struct vnode *vp = ap->a_vp; 271 register struct uio *uio = ap->a_uio; 272 register struct iso_node *ip = VTOI(vp); 273 register struct iso_mnt *imp; 274 struct buf *bp; 275 daddr_t lbn, rablock; 276 off_t diff; 277 int rasize, error = 0; 278 long size, n, on; 279 280 if (uio->uio_resid == 0) 281 return (0); 282 if (uio->uio_offset < 0) 283 return (EINVAL); 284 ip->i_flag |= IN_ACCESS; 285 imp = ip->i_mnt; 286 do { 287 lbn = lblkno(imp, uio->uio_offset); 288 on = blkoff(imp, uio->uio_offset); 289 n = min((u_int)(imp->logical_block_size - on), 290 uio->uio_resid); 291 diff = (off_t)ip->i_size - uio->uio_offset; 292 if (diff <= 0) 293 return (0); 294 if (diff < n) 295 n = diff; 296 size = blksize(imp, ip, lbn); 297 rablock = lbn + 1; 298 if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) { 299 if (lblktosize(imp, rablock) < ip->i_size) 300 error = cluster_read(vp, (off_t)ip->i_size, 301 lbn, size, NOCRED, uio->uio_resid, 302 (ap->a_ioflag >> 16), &bp); 303 else 304 error = bread(vp, lbn, size, NOCRED, &bp); 305 } else { 306 if (vp->v_lastr + 1 == lbn && 307 lblktosize(imp, rablock) < ip->i_size) { 308 rasize = blksize(imp, ip, rablock); 309 error = breadn(vp, lbn, size, &rablock, 310 &rasize, 1, NOCRED, &bp); 311 } else 312 error = bread(vp, lbn, size, NOCRED, &bp); 313 } 314 vp->v_lastr = lbn; 315 n = min(n, size - bp->b_resid); 316 if (error) { 317 brelse(bp); 318 return (error); 319 } 320 321 error = uiomove(bp->b_data + on, (int)n, uio); 322 brelse(bp); 323 } while (error == 0 && uio->uio_resid > 0 && n != 0); 324 return (error); 325} 326 327/* 328 * Structure for reading directories 329 */ 330struct isoreaddir { 331 struct dirent saveent; 332 struct dirent assocent; 333 struct dirent current; 334 off_t saveoff; 335 off_t assocoff; 336 off_t curroff; 337 struct uio *uio; 338 off_t uio_off; 339 int eofflag; 340 u_long *cookies; 341 int ncookies; 342}; 343 344int 345iso_uiodir(idp,dp,off) 346 struct isoreaddir *idp; 347 struct dirent *dp; 348 off_t off; 349{ 350 int error; 351 352 dp->d_name[dp->d_namlen] = 0; 353 dp->d_reclen = GENERIC_DIRSIZ(dp); 354 355 if (idp->uio->uio_resid < dp->d_reclen) { 356 idp->eofflag = 0; 357 return (-1); 358 } 359 360 if (idp->cookies) { 361 if (idp->ncookies <= 0) { 362 idp->eofflag = 0; 363 return (-1); 364 } 365 366 *idp->cookies++ = off; 367 --idp->ncookies; 368 } 369 370 if ((error = uiomove((caddr_t) dp,dp->d_reclen,idp->uio)) != 0) 371 return (error); 372 idp->uio_off = off; 373 return (0); 374} 375 376int 377iso_shipdir(idp) 378 struct isoreaddir *idp; 379{ 380 struct dirent *dp; 381 int cl, sl, assoc; 382 int error; 383 char *cname, *sname; 384 385 cl = idp->current.d_namlen; 386 cname = idp->current.d_name; 387assoc = (cl > 1) && (*cname == ASSOCCHAR); 388 if (assoc) { 389 cl--; 390 cname++; 391 } 392 393 dp = &idp->saveent; 394 sname = dp->d_name; 395 if (!(sl = dp->d_namlen)) { 396 dp = &idp->assocent; 397 sname = dp->d_name + 1; 398 sl = dp->d_namlen - 1; 399 } 400 if (sl > 0) { 401 if (sl != cl 402 || bcmp(sname,cname,sl)) { 403 if (idp->assocent.d_namlen) { 404 if ((error = iso_uiodir(idp,&idp->assocent,idp->assocoff)) != 0) 405 return (error); 406 idp->assocent.d_namlen = 0; 407 } 408 if (idp->saveent.d_namlen) { 409 if ((error = iso_uiodir(idp,&idp->saveent,idp->saveoff)) != 0) 410 return (error); 411 idp->saveent.d_namlen = 0; 412 } 413 } 414 } 415 idp->current.d_reclen = GENERIC_DIRSIZ(&idp->current); 416 if (assoc) { 417 idp->assocoff = idp->curroff; 418 bcopy(&idp->current,&idp->assocent,idp->current.d_reclen); 419 } else { 420 idp->saveoff = idp->curroff; 421 bcopy(&idp->current,&idp->saveent,idp->current.d_reclen); 422 } 423 return (0); 424} 425 426/* 427 * Vnode op for readdir 428 */ 429static int 430cd9660_readdir(ap) 431 struct vop_readdir_args /* { 432 struct vnode *a_vp; 433 struct uio *a_uio; 434 struct ucred *a_cred; 435 int *a_eofflag; 436 int *a_ncookies; 437 u_long *a_cookies; 438 } */ *ap; 439{ 440 register struct uio *uio = ap->a_uio; 441 struct isoreaddir *idp; 442 struct vnode *vdp = ap->a_vp; 443 struct iso_node *dp; 444 struct iso_mnt *imp; 445 struct buf *bp = NULL; 446 struct iso_directory_record *ep; 447 int entryoffsetinblock; 448 doff_t endsearch; 449 u_long bmask; 450 int error = 0; 451 int reclen; 452 u_short namelen; 453 int ncookies = 0; 454 u_long *cookies = NULL; 455 456 dp = VTOI(vdp); 457 imp = dp->i_mnt; 458 bmask = imp->im_bmask; 459 460 MALLOC(idp, struct isoreaddir *, sizeof(*idp), M_TEMP, M_WAITOK); 461 idp->saveent.d_namlen = idp->assocent.d_namlen = 0; 462 /* 463 * XXX 464 * Is it worth trying to figure out the type? 465 */ 466 idp->saveent.d_type = idp->assocent.d_type = idp->current.d_type = 467 DT_UNKNOWN; 468 idp->uio = uio; 469 if (ap->a_ncookies == NULL) { 470 idp->cookies = NULL; 471 } else { 472 /* 473 * Guess the number of cookies needed. 474 */ 475 ncookies = uio->uio_resid / 16; 476 MALLOC(cookies, u_long *, ncookies * sizeof(u_int), M_TEMP, 477 M_WAITOK); 478 idp->cookies = cookies; 479 idp->ncookies = ncookies; 480 } 481 idp->eofflag = 1; 482 idp->curroff = uio->uio_offset; 483 484 if ((entryoffsetinblock = idp->curroff & bmask) && 485 (error = cd9660_blkatoff(vdp, (off_t)idp->curroff, NULL, &bp))) { 486 FREE(idp, M_TEMP); 487 return (error); 488 } 489 endsearch = dp->i_size; 490 491 while (idp->curroff < endsearch) { 492 /* 493 * If offset is on a block boundary, 494 * read the next directory block. 495 * Release previous if it exists. 496 */ 497 if ((idp->curroff & bmask) == 0) { 498 if (bp != NULL) 499 brelse(bp); 500 if ((error = 501 cd9660_blkatoff(vdp, (off_t)idp->curroff, NULL, &bp)) != 0) 502 break; 503 entryoffsetinblock = 0; 504 } 505 /* 506 * Get pointer to next entry. 507 */ 508 ep = (struct iso_directory_record *) 509 ((char *)bp->b_data + entryoffsetinblock); 510 511 reclen = isonum_711(ep->length); 512 if (reclen == 0) { 513 /* skip to next block, if any */ 514 idp->curroff = 515 (idp->curroff & ~bmask) + imp->logical_block_size; 516 continue; 517 } 518 519 if (reclen < ISO_DIRECTORY_RECORD_SIZE) { 520 error = EINVAL; 521 /* illegal entry, stop */ 522 break; 523 } 524 525 if (entryoffsetinblock + reclen > imp->logical_block_size) { 526 error = EINVAL; 527 /* illegal directory, so stop looking */ 528 break; 529 } 530 531 idp->current.d_namlen = isonum_711(ep->name_len); 532 533 if (reclen < ISO_DIRECTORY_RECORD_SIZE + idp->current.d_namlen) { 534 error = EINVAL; 535 /* illegal entry, stop */ 536 break; 537 } 538 539 if (isonum_711(ep->flags)&2) 540 idp->current.d_fileno = isodirino(ep, imp); 541 else 542 idp->current.d_fileno = dbtob(bp->b_blkno) + 543 entryoffsetinblock; 544 545 idp->curroff += reclen; 546 547 switch (imp->iso_ftype) { 548 case ISO_FTYPE_RRIP: 549 cd9660_rrip_getname(ep,idp->current.d_name, &namelen, 550 &idp->current.d_fileno,imp); 551 idp->current.d_namlen = (u_char)namelen; 552 if (idp->current.d_namlen) 553 error = iso_uiodir(idp,&idp->current,idp->curroff); 554 break; 555 default: /* ISO_FTYPE_DEFAULT || ISO_FTYPE_9660 || ISO_FTYPE_HIGH_SIERRA*/ 556 strcpy(idp->current.d_name,".."); 557 if (idp->current.d_namlen == 1 && ep->name[0] == 0) { 558 idp->current.d_namlen = 1; 559 error = iso_uiodir(idp,&idp->current,idp->curroff); 560 } else if (idp->current.d_namlen == 1 && ep->name[0] == 1) { 561 idp->current.d_namlen = 2; 562 error = iso_uiodir(idp,&idp->current,idp->curroff); 563 } else { 564 isofntrans(ep->name,idp->current.d_namlen, 565 idp->current.d_name, &namelen, 566 imp->iso_ftype == ISO_FTYPE_9660, 567 isonum_711(ep->flags)&4, 568 imp->joliet_level); 569 idp->current.d_namlen = (u_char)namelen; 570 if (imp->iso_ftype == ISO_FTYPE_DEFAULT) 571 error = iso_shipdir(idp); 572 else 573 error = iso_uiodir(idp,&idp->current,idp->curroff); 574 } 575 } 576 if (error) 577 break; 578 579 entryoffsetinblock += reclen; 580 } 581 582 if (!error && imp->iso_ftype == ISO_FTYPE_DEFAULT) { 583 idp->current.d_namlen = 0; 584 error = iso_shipdir(idp); 585 } 586 if (error < 0) 587 error = 0; 588 589 if (ap->a_ncookies != NULL) { 590 if (error) 591 free(cookies, M_TEMP); 592 else { 593 /* 594 * Work out the number of cookies actually used. 595 */ 596 *ap->a_ncookies = ncookies - idp->ncookies; 597 *ap->a_cookies = cookies; 598 } 599 } 600 601 if (bp) 602 brelse (bp); 603 604 uio->uio_offset = idp->uio_off; 605 *ap->a_eofflag = idp->eofflag; 606 607 FREE(idp, M_TEMP); 608 609 return (error); 610} 611 612/* 613 * Return target name of a symbolic link 614 * Shouldn't we get the parent vnode and read the data from there? 615 * This could eventually result in deadlocks in cd9660_lookup. 616 * But otherwise the block read here is in the block buffer two times. 617 */ 618typedef struct iso_directory_record ISODIR; 619typedef struct iso_node ISONODE; 620typedef struct iso_mnt ISOMNT; 621static int 622cd9660_readlink(ap) 623 struct vop_readlink_args /* { 624 struct vnode *a_vp; 625 struct uio *a_uio; 626 struct ucred *a_cred; 627 } */ *ap; 628{ 629 ISONODE *ip; 630 ISODIR *dirp; 631 ISOMNT *imp; 632 struct buf *bp; 633 struct uio *uio; 634 u_short symlen; 635 int error; 636 char *symname; 637 638 ip = VTOI(ap->a_vp); 639 imp = ip->i_mnt; 640 uio = ap->a_uio; 641 642 if (imp->iso_ftype != ISO_FTYPE_RRIP) 643 return (EINVAL); 644 645 /* 646 * Get parents directory record block that this inode included. 647 */ 648 error = bread(imp->im_devvp, 649 (ip->i_number >> imp->im_bshift) << 650 (imp->im_bshift - DEV_BSHIFT), 651 imp->logical_block_size, NOCRED, &bp); 652 if (error) { 653 brelse(bp); 654 return (EINVAL); 655 } 656 657 /* 658 * Setup the directory pointer for this inode 659 */ 660 dirp = (ISODIR *)(bp->b_data + (ip->i_number & imp->im_bmask)); 661 662 /* 663 * Just make sure, we have a right one.... 664 * 1: Check not cross boundary on block 665 */ 666 if ((ip->i_number & imp->im_bmask) + isonum_711(dirp->length) 667 > (unsigned)imp->logical_block_size) { 668 brelse(bp); 669 return (EINVAL); 670 } 671 672 /* 673 * Now get a buffer 674 * Abuse a namei buffer for now. 675 */ 676 if (uio->uio_segflg == UIO_SYSSPACE) 677 symname = uio->uio_iov->iov_base; 678 else 679 symname = zalloc(namei_zone); 680 681 /* 682 * Ok, we just gathering a symbolic name in SL record. 683 */ 684 if (cd9660_rrip_getsymname(dirp, symname, &symlen, imp) == 0) { 685 if (uio->uio_segflg != UIO_SYSSPACE) 686 zfree(namei_zone, symname); 687 brelse(bp); 688 return (EINVAL); 689 } 690 /* 691 * Don't forget before you leave from home ;-) 692 */ 693 brelse(bp); 694 695 /* 696 * return with the symbolic name to caller's. 697 */ 698 if (uio->uio_segflg != UIO_SYSSPACE) { 699 error = uiomove(symname, symlen, uio); 700 zfree(namei_zone, symname); 701 return (error); 702 } 703 uio->uio_resid -= symlen; 704 uio->uio_iov->iov_base += symlen; 705 uio->uio_iov->iov_len -= symlen; 706 return (0); 707} 708 709/* 710 * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually 711 * done. If a buffer has been saved in anticipation of a CREATE, delete it. 712 */ 713static int 714cd9660_abortop(ap) 715 struct vop_abortop_args /* { 716 struct vnode *a_dvp; 717 struct componentname *a_cnp; 718 } */ *ap; 719{ 720 if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) 721 zfree(namei_zone, ap->a_cnp->cn_pnbuf); 722 return (0); 723} 724 725/* 726 * Calculate the logical to physical mapping if not done already, 727 * then call the device strategy routine. 728 */ 729static int 730cd9660_strategy(ap) 731 struct vop_strategy_args /* { 732 struct buf *a_vp; 733 struct buf *a_bp; 734 } */ *ap; 735{ 736 register struct buf *bp = ap->a_bp; 737 register struct vnode *vp = bp->b_vp; 738 register struct iso_node *ip; 739 int error; 740 741 ip = VTOI(vp); 742 if (vp->v_type == VBLK || vp->v_type == VCHR) 743 panic("cd9660_strategy: spec"); 744 if (bp->b_blkno == bp->b_lblkno) { 745 if ((error = 746 VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL, NULL))) { 747 bp->b_error = error; 748 bp->b_flags |= B_ERROR; 749 biodone(bp); 750 return (error); 751 } 752 if ((long)bp->b_blkno == -1) 753 clrbuf(bp); 754 } 755 if ((long)bp->b_blkno == -1) { 756 biodone(bp); 757 return (0); 758 } 759 vp = ip->i_devvp; 760 bp->b_dev = vp->v_rdev; 761 VOP_STRATEGY(vp, bp); 762 return (0); 763} 764 765/* 766 * Print out the contents of an inode. 767 */ 768static int 769cd9660_print(ap) 770 struct vop_print_args /* { 771 struct vnode *a_vp; 772 } */ *ap; 773{ 774 775 printf("tag VT_ISOFS, isofs vnode\n"); 776 return (0); 777} 778 779/* 780 * Return POSIX pathconf information applicable to cd9660 filesystems. 781 */ 782static int 783cd9660_pathconf(ap) 784 struct vop_pathconf_args /* { 785 struct vnode *a_vp; 786 int a_name; 787 register_t *a_retval; 788 } */ *ap; 789{ 790 791 switch (ap->a_name) { 792 case _PC_LINK_MAX: 793 *ap->a_retval = 1; 794 return (0); 795 case _PC_NAME_MAX: 796 if (VTOI(ap->a_vp)->i_mnt->iso_ftype == ISO_FTYPE_RRIP) 797 *ap->a_retval = NAME_MAX; 798 else 799 *ap->a_retval = 37; 800 return (0); 801 case _PC_PATH_MAX: 802 *ap->a_retval = PATH_MAX; 803 return (0); 804 case _PC_PIPE_BUF: 805 *ap->a_retval = PIPE_BUF; 806 return (0); 807 case _PC_CHOWN_RESTRICTED: 808 *ap->a_retval = 1; 809 return (0); 810 case _PC_NO_TRUNC: 811 *ap->a_retval = 1; 812 return (0); 813 default: 814 return (EINVAL); 815 } 816 /* NOTREACHED */ 817} 818 819/* 820 * get page routine 821 * 822 * XXX By default, wimp out... note that a_offset is ignored (and always 823 * XXX has been). 824 */ 825int 826cd9660_getpages(ap) 827 struct vop_getpages_args *ap; 828{ 829 return vnode_pager_generic_getpages(ap->a_vp, ap->a_m, ap->a_count, 830 ap->a_reqpage); 831} 832 833/* 834 * put page routine 835 * 836 * XXX By default, wimp out... note that a_offset is ignored (and always 837 * XXX has been). 838 */ 839int 840cd9660_putpages(ap) 841 struct vop_putpages_args *ap; 842{ 843 return vnode_pager_generic_putpages(ap->a_vp, ap->a_m, ap->a_count, 844 ap->a_sync, ap->a_rtvals); 845} 846 847/* 848 * Global vfs data structures for cd9660 849 */ 850vop_t **cd9660_vnodeop_p; 851static struct vnodeopv_entry_desc cd9660_vnodeop_entries[] = { 852 { &vop_default_desc, (vop_t *) vop_defaultop }, 853 { &vop_abortop_desc, (vop_t *) cd9660_abortop }, 854 { &vop_access_desc, (vop_t *) cd9660_access }, 855 { &vop_bmap_desc, (vop_t *) cd9660_bmap }, 856 { &vop_cachedlookup_desc, (vop_t *) cd9660_lookup }, 857 { &vop_getattr_desc, (vop_t *) cd9660_getattr }, 858 { &vop_inactive_desc, (vop_t *) cd9660_inactive }, 859 { &vop_islocked_desc, (vop_t *) vop_stdislocked }, 860 { &vop_lock_desc, (vop_t *) vop_stdlock }, 861 { &vop_lookup_desc, (vop_t *) vfs_cache_lookup }, 862 { &vop_pathconf_desc, (vop_t *) cd9660_pathconf }, 863 { &vop_print_desc, (vop_t *) cd9660_print }, 864 { &vop_read_desc, (vop_t *) cd9660_read }, 865 { &vop_readdir_desc, (vop_t *) cd9660_readdir }, 866 { &vop_readlink_desc, (vop_t *) cd9660_readlink }, 867 { &vop_reclaim_desc, (vop_t *) cd9660_reclaim }, 868 { &vop_setattr_desc, (vop_t *) cd9660_setattr }, 869 { &vop_strategy_desc, (vop_t *) cd9660_strategy }, 870 { &vop_unlock_desc, (vop_t *) vop_stdunlock }, 871 { &vop_getpages_desc, (vop_t *) cd9660_getpages }, 872 { &vop_putpages_desc, (vop_t *) cd9660_putpages }, 873 { NULL, NULL } 874}; 875static struct vnodeopv_desc cd9660_vnodeop_opv_desc = 876 { &cd9660_vnodeop_p, cd9660_vnodeop_entries }; 877VNODEOP_SET(cd9660_vnodeop_opv_desc); 878 879/* 880 * Special device vnode ops 881 */ 882vop_t **cd9660_specop_p; 883static struct vnodeopv_entry_desc cd9660_specop_entries[] = { 884 { &vop_default_desc, (vop_t *) spec_vnoperate }, 885 { &vop_access_desc, (vop_t *) cd9660_access }, 886 { &vop_getattr_desc, (vop_t *) cd9660_getattr }, 887 { &vop_inactive_desc, (vop_t *) cd9660_inactive }, 888 { &vop_islocked_desc, (vop_t *) vop_stdislocked }, 889 { &vop_lock_desc, (vop_t *) vop_stdlock }, 890 { &vop_print_desc, (vop_t *) cd9660_print }, 891 { &vop_reclaim_desc, (vop_t *) cd9660_reclaim }, 892 { &vop_setattr_desc, (vop_t *) cd9660_setattr }, 893 { &vop_unlock_desc, (vop_t *) vop_stdunlock }, 894 { NULL, NULL } 895}; 896static struct vnodeopv_desc cd9660_specop_opv_desc = 897 { &cd9660_specop_p, cd9660_specop_entries }; 898VNODEOP_SET(cd9660_specop_opv_desc); 899 900vop_t **cd9660_fifoop_p; 901static struct vnodeopv_entry_desc cd9660_fifoop_entries[] = { 902 { &vop_default_desc, (vop_t *) fifo_vnoperate }, 903 { &vop_access_desc, (vop_t *) cd9660_access }, 904 { &vop_getattr_desc, (vop_t *) cd9660_getattr }, 905 { &vop_inactive_desc, (vop_t *) cd9660_inactive }, 906 { &vop_islocked_desc, (vop_t *) vop_stdislocked }, 907 { &vop_lock_desc, (vop_t *) vop_stdlock }, 908 { &vop_print_desc, (vop_t *) cd9660_print }, 909 { &vop_reclaim_desc, (vop_t *) cd9660_reclaim }, 910 { &vop_setattr_desc, (vop_t *) cd9660_setattr }, 911 { &vop_unlock_desc, (vop_t *) vop_stdunlock }, 912 { NULL, NULL } 913}; 914static struct vnodeopv_desc cd9660_fifoop_opv_desc = 915 { &cd9660_fifoop_p, cd9660_fifoop_entries }; 916 917VNODEOP_SET(cd9660_fifoop_opv_desc);
|