44#include <sys/param.h> 45#include <sys/systm.h> 46#include <sys/namei.h> 47#include <sys/kernel.h> 48#include <sys/stat.h> 49#include <sys/bio.h> 50#include <sys/buf.h> 51#include <sys/mount.h> 52#include <sys/vnode.h> 53#include <fs/fifofs/fifo.h> 54#include <sys/malloc.h> 55#include <sys/dirent.h> 56#include <sys/unistd.h> 57#include <sys/filio.h> 58 59#include <vm/vm.h> 60#include <vm/vnode_pager.h> 61#include <vm/uma.h> 62 63#include <isofs/cd9660/iso.h> 64#include <isofs/cd9660/cd9660_node.h> 65#include <isofs/cd9660/iso_rrip.h> 66 67static int cd9660_setattr(struct vop_setattr_args *); 68static int cd9660_access(struct vop_access_args *); 69static int cd9660_getattr(struct vop_getattr_args *); 70static int cd9660_ioctl(struct vop_ioctl_args *); 71static int cd9660_pathconf(struct vop_pathconf_args *); 72static int cd9660_read(struct vop_read_args *); 73struct isoreaddir; 74static int iso_uiodir(struct isoreaddir *idp, struct dirent *dp, off_t off); 75static int iso_shipdir(struct isoreaddir *idp); 76static int cd9660_readdir(struct vop_readdir_args *); 77static int cd9660_readlink(struct vop_readlink_args *ap); 78static int cd9660_strategy(struct vop_strategy_args *); 79 80/* 81 * Setattr call. Only allowed for block and character special devices. 82 */ 83static int 84cd9660_setattr(ap) 85 struct vop_setattr_args /* { 86 struct vnodeop_desc *a_desc; 87 struct vnode *a_vp; 88 struct vattr *a_vap; 89 struct ucred *a_cred; 90 struct thread *a_td; 91 } */ *ap; 92{ 93 struct vnode *vp = ap->a_vp; 94 struct vattr *vap = ap->a_vap; 95 96 if (vap->va_flags != (u_long)VNOVAL || vap->va_uid != (uid_t)VNOVAL || 97 vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL || 98 vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL) 99 return (EROFS); 100 if (vap->va_size != (u_quad_t)VNOVAL) { 101 switch (vp->v_type) { 102 case VDIR: 103 return (EISDIR); 104 case VLNK: 105 case VREG: 106 return (EROFS); 107 case VCHR: 108 case VBLK: 109 case VSOCK: 110 case VFIFO: 111 case VNON: 112 case VBAD: 113 return (0); 114 } 115 } 116 return (0); 117} 118 119/* 120 * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC. 121 * The mode is shifted to select the owner/group/other fields. The 122 * super user is granted all permissions. 123 */ 124/* ARGSUSED */ 125static int 126cd9660_access(ap) 127 struct vop_access_args /* { 128 struct vnode *a_vp; 129 int a_mode; 130 struct ucred *a_cred; 131 struct thread *a_td; 132 } */ *ap; 133{ 134 struct vnode *vp = ap->a_vp; 135 struct iso_node *ip = VTOI(vp); 136 mode_t mode = ap->a_mode; 137 138 /* 139 * Disallow write attempts unless the file is a socket, 140 * fifo, or a block or character device resident on the 141 * filesystem. 142 */ 143 if (mode & VWRITE) { 144 switch (vp->v_type) { 145 case VDIR: 146 case VLNK: 147 case VREG: 148 return (EROFS); 149 /* NOT REACHED */ 150 default: 151 break; 152 } 153 } 154 155 return (vaccess(vp->v_type, ip->inode.iso_mode, ip->inode.iso_uid, 156 ip->inode.iso_gid, ap->a_mode, ap->a_cred, NULL)); 157} 158 159static int 160cd9660_getattr(ap) 161 struct vop_getattr_args /* { 162 struct vnode *a_vp; 163 struct vattr *a_vap; 164 struct ucred *a_cred; 165 struct thread *a_td; 166 } */ *ap; 167 168{ 169 struct vnode *vp = ap->a_vp; 170 struct vattr *vap = ap->a_vap; 171 struct iso_node *ip = VTOI(vp); 172 173 vap->va_fsid = dev2udev(ip->i_dev); 174 175 /* 176 * Don't use ip->i_ino for this since it is wrong for hard links. 177 * ip->i_ino should be the same as ip->iso_start (or not exist), 178 * but this currently doesn't work since we abuse it to look up 179 * parent directories from inodes. 180 */ 181 vap->va_fileid = ip->iso_start; 182 183 vap->va_mode = ip->inode.iso_mode; 184 vap->va_nlink = ip->inode.iso_links; 185 vap->va_uid = ip->inode.iso_uid; 186 vap->va_gid = ip->inode.iso_gid; 187 vap->va_atime = ip->inode.iso_atime; 188 vap->va_mtime = ip->inode.iso_mtime; 189 vap->va_ctime = ip->inode.iso_ctime; 190 vap->va_rdev = ip->inode.iso_rdev; 191 192 vap->va_size = (u_quad_t) ip->i_size; 193 if (ip->i_size == 0 && (vap->va_mode & S_IFMT) == S_IFLNK) { 194 struct vop_readlink_args rdlnk; 195 struct iovec aiov; 196 struct uio auio; 197 char *cp; 198 199 MALLOC(cp, char *, MAXPATHLEN, M_TEMP, M_WAITOK); 200 aiov.iov_base = cp; 201 aiov.iov_len = MAXPATHLEN; 202 auio.uio_iov = &aiov; 203 auio.uio_iovcnt = 1; 204 auio.uio_offset = 0; 205 auio.uio_rw = UIO_READ; 206 auio.uio_segflg = UIO_SYSSPACE; 207 auio.uio_td = ap->a_td; 208 auio.uio_resid = MAXPATHLEN; 209 rdlnk.a_uio = &auio; 210 rdlnk.a_vp = ap->a_vp; 211 rdlnk.a_cred = ap->a_cred; 212 if (cd9660_readlink(&rdlnk) == 0) 213 vap->va_size = MAXPATHLEN - auio.uio_resid; 214 FREE(cp, M_TEMP); 215 } 216 vap->va_flags = 0; 217 vap->va_gen = 1; 218 vap->va_blocksize = ip->i_mnt->logical_block_size; 219 vap->va_bytes = (u_quad_t) ip->i_size; 220 vap->va_type = vp->v_type; 221 vap->va_filerev = 0; 222 return (0); 223} 224 225/* 226 * Vnode op for ioctl. 227 */ 228static int 229cd9660_ioctl(ap) 230 struct vop_ioctl_args /* { 231 struct vnode *a_vp; 232 u_long a_command; 233 caddr_t a_data; 234 int a_fflag; 235 struct ucred *a_cred; 236 struct thread *a_td; 237 } */ *ap; 238{ 239 struct vnode *vp = ap->a_vp; 240 struct iso_node *ip = VTOI(vp); 241 242 switch (ap->a_command) { 243 244 case FIOGETLBA: 245 *(int *)(ap->a_data) = ip->iso_start; 246 return 0; 247 default: 248 return (ENOTTY); 249 } 250} 251 252/* 253 * Vnode op for reading. 254 */ 255static int 256cd9660_read(ap) 257 struct vop_read_args /* { 258 struct vnode *a_vp; 259 struct uio *a_uio; 260 int a_ioflag; 261 struct ucred *a_cred; 262 } */ *ap; 263{ 264 struct vnode *vp = ap->a_vp; 265 struct uio *uio = ap->a_uio; 266 struct iso_node *ip = VTOI(vp); 267 struct iso_mnt *imp; 268 struct buf *bp; 269 daddr_t lbn, rablock; 270 off_t diff; 271 int rasize, error = 0; 272 int seqcount; 273 long size, n, on; 274 275 seqcount = ap->a_ioflag >> 16; 276 277 if (uio->uio_resid == 0) 278 return (0); 279 if (uio->uio_offset < 0) 280 return (EINVAL); 281 ip->i_flag |= IN_ACCESS; 282 imp = ip->i_mnt; 283 do { 284 lbn = lblkno(imp, uio->uio_offset); 285 on = blkoff(imp, uio->uio_offset); 286 n = min((u_int)(imp->logical_block_size - on), 287 uio->uio_resid); 288 diff = (off_t)ip->i_size - uio->uio_offset; 289 if (diff <= 0) 290 return (0); 291 if (diff < n) 292 n = diff; 293 size = blksize(imp, ip, lbn); 294 rablock = lbn + 1; 295 if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) { 296 if (lblktosize(imp, rablock) < ip->i_size) 297 error = cluster_read(vp, (off_t)ip->i_size, 298 lbn, size, NOCRED, uio->uio_resid, 299 (ap->a_ioflag >> 16), &bp); 300 else 301 error = bread(vp, lbn, size, NOCRED, &bp); 302 } else { 303 if (seqcount > 1 && 304 lblktosize(imp, rablock) < ip->i_size) { 305 rasize = blksize(imp, ip, rablock); 306 error = breadn(vp, lbn, size, &rablock, 307 &rasize, 1, NOCRED, &bp); 308 } else 309 error = bread(vp, lbn, size, NOCRED, &bp); 310 } 311 n = min(n, size - bp->b_resid); 312 if (error) { 313 brelse(bp); 314 return (error); 315 } 316 317 error = uiomove(bp->b_data + on, (int)n, uio); 318 brelse(bp); 319 } while (error == 0 && uio->uio_resid > 0 && n != 0); 320 return (error); 321} 322 323/* 324 * Structure for reading directories 325 */ 326struct isoreaddir { 327 struct dirent saveent; 328 struct dirent assocent; 329 struct dirent current; 330 off_t saveoff; 331 off_t assocoff; 332 off_t curroff; 333 struct uio *uio; 334 off_t uio_off; 335 int eofflag; 336 u_long *cookies; 337 int ncookies; 338}; 339 340static int 341iso_uiodir(idp,dp,off) 342 struct isoreaddir *idp; 343 struct dirent *dp; 344 off_t off; 345{ 346 int error; 347 348 dp->d_name[dp->d_namlen] = 0; 349 dp->d_reclen = GENERIC_DIRSIZ(dp); 350 351 if (idp->uio->uio_resid < dp->d_reclen) { 352 idp->eofflag = 0; 353 return (-1); 354 } 355 356 if (idp->cookies) { 357 if (idp->ncookies <= 0) { 358 idp->eofflag = 0; 359 return (-1); 360 } 361 362 *idp->cookies++ = off; 363 --idp->ncookies; 364 } 365 366 if ((error = uiomove(dp, dp->d_reclen, idp->uio)) != 0) 367 return (error); 368 idp->uio_off = off; 369 return (0); 370} 371 372static int 373iso_shipdir(idp) 374 struct isoreaddir *idp; 375{ 376 struct dirent *dp; 377 int cl, sl, assoc; 378 int error; 379 char *cname, *sname; 380 381 cl = idp->current.d_namlen; 382 cname = idp->current.d_name; 383assoc = (cl > 1) && (*cname == ASSOCCHAR); 384 if (assoc) { 385 cl--; 386 cname++; 387 } 388 389 dp = &idp->saveent; 390 sname = dp->d_name; 391 if (!(sl = dp->d_namlen)) { 392 dp = &idp->assocent; 393 sname = dp->d_name + 1; 394 sl = dp->d_namlen - 1; 395 } 396 if (sl > 0) { 397 if (sl != cl 398 || bcmp(sname,cname,sl)) { 399 if (idp->assocent.d_namlen) { 400 if ((error = iso_uiodir(idp,&idp->assocent,idp->assocoff)) != 0) 401 return (error); 402 idp->assocent.d_namlen = 0; 403 } 404 if (idp->saveent.d_namlen) { 405 if ((error = iso_uiodir(idp,&idp->saveent,idp->saveoff)) != 0) 406 return (error); 407 idp->saveent.d_namlen = 0; 408 } 409 } 410 } 411 idp->current.d_reclen = GENERIC_DIRSIZ(&idp->current); 412 if (assoc) { 413 idp->assocoff = idp->curroff; 414 bcopy(&idp->current,&idp->assocent,idp->current.d_reclen); 415 } else { 416 idp->saveoff = idp->curroff; 417 bcopy(&idp->current,&idp->saveent,idp->current.d_reclen); 418 } 419 return (0); 420} 421 422/* 423 * Vnode op for readdir 424 */ 425static int 426cd9660_readdir(ap) 427 struct vop_readdir_args /* { 428 struct vnode *a_vp; 429 struct uio *a_uio; 430 struct ucred *a_cred; 431 int *a_eofflag; 432 int *a_ncookies; 433 u_long *a_cookies; 434 } */ *ap; 435{ 436 struct uio *uio = ap->a_uio; 437 struct isoreaddir *idp; 438 struct vnode *vdp = ap->a_vp; 439 struct iso_node *dp; 440 struct iso_mnt *imp; 441 struct buf *bp = NULL; 442 struct iso_directory_record *ep; 443 int entryoffsetinblock; 444 doff_t endsearch; 445 u_long bmask; 446 int error = 0; 447 int reclen; 448 u_short namelen; 449 int ncookies = 0; 450 u_long *cookies = NULL; 451 452 dp = VTOI(vdp); 453 imp = dp->i_mnt; 454 bmask = imp->im_bmask; 455 456 MALLOC(idp, struct isoreaddir *, sizeof(*idp), M_TEMP, M_WAITOK); 457 idp->saveent.d_namlen = idp->assocent.d_namlen = 0; 458 /* 459 * XXX 460 * Is it worth trying to figure out the type? 461 */ 462 idp->saveent.d_type = idp->assocent.d_type = idp->current.d_type = 463 DT_UNKNOWN; 464 idp->uio = uio; 465 if (ap->a_ncookies == NULL) { 466 idp->cookies = NULL; 467 } else { 468 /* 469 * Guess the number of cookies needed. 470 */ 471 ncookies = uio->uio_resid / 16; 472 MALLOC(cookies, u_long *, ncookies * sizeof(u_int), M_TEMP, 473 M_WAITOK); 474 idp->cookies = cookies; 475 idp->ncookies = ncookies; 476 } 477 idp->eofflag = 1; 478 idp->curroff = uio->uio_offset; 479 480 if ((entryoffsetinblock = idp->curroff & bmask) && 481 (error = cd9660_blkatoff(vdp, (off_t)idp->curroff, NULL, &bp))) { 482 FREE(idp, M_TEMP); 483 return (error); 484 } 485 endsearch = dp->i_size; 486 487 while (idp->curroff < endsearch) { 488 /* 489 * If offset is on a block boundary, 490 * read the next directory block. 491 * Release previous if it exists. 492 */ 493 if ((idp->curroff & bmask) == 0) { 494 if (bp != NULL) 495 brelse(bp); 496 if ((error = 497 cd9660_blkatoff(vdp, (off_t)idp->curroff, NULL, &bp)) != 0) 498 break; 499 entryoffsetinblock = 0; 500 } 501 /* 502 * Get pointer to next entry. 503 */ 504 ep = (struct iso_directory_record *) 505 ((char *)bp->b_data + entryoffsetinblock); 506 507 reclen = isonum_711(ep->length); 508 if (reclen == 0) { 509 /* skip to next block, if any */ 510 idp->curroff = 511 (idp->curroff & ~bmask) + imp->logical_block_size; 512 continue; 513 } 514 515 if (reclen < ISO_DIRECTORY_RECORD_SIZE) { 516 error = EINVAL; 517 /* illegal entry, stop */ 518 break; 519 } 520 521 if (entryoffsetinblock + reclen > imp->logical_block_size) { 522 error = EINVAL; 523 /* illegal directory, so stop looking */ 524 break; 525 } 526 527 idp->current.d_namlen = isonum_711(ep->name_len); 528 529 if (reclen < ISO_DIRECTORY_RECORD_SIZE + idp->current.d_namlen) { 530 error = EINVAL; 531 /* illegal entry, stop */ 532 break; 533 } 534 535 /* 536 * The "inode number" is iso_start, not i_ino, as in 537 * cd9660_getattr(). 538 */ 539 idp->current.d_fileno = isonum_711(ep->ext_attr_length) + 540 isonum_733(ep->extent); 541 542 idp->curroff += reclen; 543 544 switch (imp->iso_ftype) { 545 case ISO_FTYPE_RRIP: 546 cd9660_rrip_getname(ep,idp->current.d_name, &namelen, 547 &idp->current.d_fileno,imp); 548 idp->current.d_namlen = (u_char)namelen; 549 if (idp->current.d_namlen) 550 error = iso_uiodir(idp,&idp->current,idp->curroff); 551 break; 552 default: /* ISO_FTYPE_DEFAULT || ISO_FTYPE_9660 || ISO_FTYPE_HIGH_SIERRA*/ 553 strcpy(idp->current.d_name,".."); 554 if (idp->current.d_namlen == 1 && ep->name[0] == 0) { 555 idp->current.d_namlen = 1; 556 error = iso_uiodir(idp,&idp->current,idp->curroff); 557 } else if (idp->current.d_namlen == 1 && ep->name[0] == 1) { 558 idp->current.d_namlen = 2; 559 error = iso_uiodir(idp,&idp->current,idp->curroff); 560 } else { 561 isofntrans(ep->name,idp->current.d_namlen, 562 idp->current.d_name, &namelen, 563 imp->iso_ftype == ISO_FTYPE_9660, 564 isonum_711(ep->flags)&4, 565 imp->joliet_level); 566 idp->current.d_namlen = (u_char)namelen; 567 if (imp->iso_ftype == ISO_FTYPE_DEFAULT) 568 error = iso_shipdir(idp); 569 else 570 error = iso_uiodir(idp,&idp->current,idp->curroff); 571 } 572 } 573 if (error) 574 break; 575 576 entryoffsetinblock += reclen; 577 } 578 579 if (!error && imp->iso_ftype == ISO_FTYPE_DEFAULT) { 580 idp->current.d_namlen = 0; 581 error = iso_shipdir(idp); 582 } 583 if (error < 0) 584 error = 0; 585 586 if (ap->a_ncookies != NULL) { 587 if (error) 588 free(cookies, M_TEMP); 589 else { 590 /* 591 * Work out the number of cookies actually used. 592 */ 593 *ap->a_ncookies = ncookies - idp->ncookies; 594 *ap->a_cookies = cookies; 595 } 596 } 597 598 if (bp) 599 brelse (bp); 600 601 uio->uio_offset = idp->uio_off; 602 *ap->a_eofflag = idp->eofflag; 603 604 FREE(idp, M_TEMP); 605 606 return (error); 607} 608 609/* 610 * Return target name of a symbolic link 611 * Shouldn't we get the parent vnode and read the data from there? 612 * This could eventually result in deadlocks in cd9660_lookup. 613 * But otherwise the block read here is in the block buffer two times. 614 */ 615typedef struct iso_directory_record ISODIR; 616typedef struct iso_node ISONODE; 617typedef struct iso_mnt ISOMNT; 618static int 619cd9660_readlink(ap) 620 struct vop_readlink_args /* { 621 struct vnode *a_vp; 622 struct uio *a_uio; 623 struct ucred *a_cred; 624 } */ *ap; 625{ 626 ISONODE *ip; 627 ISODIR *dirp; 628 ISOMNT *imp; 629 struct buf *bp; 630 struct uio *uio; 631 u_short symlen; 632 int error; 633 char *symname; 634 635 ip = VTOI(ap->a_vp); 636 imp = ip->i_mnt; 637 uio = ap->a_uio; 638 639 if (imp->iso_ftype != ISO_FTYPE_RRIP) 640 return (EINVAL); 641 642 /* 643 * Get parents directory record block that this inode included. 644 */ 645 error = bread(imp->im_devvp, 646 (ip->i_number >> imp->im_bshift) << 647 (imp->im_bshift - DEV_BSHIFT), 648 imp->logical_block_size, NOCRED, &bp); 649 if (error) { 650 brelse(bp); 651 return (EINVAL); 652 } 653 654 /* 655 * Setup the directory pointer for this inode 656 */ 657 dirp = (ISODIR *)(bp->b_data + (ip->i_number & imp->im_bmask)); 658 659 /* 660 * Just make sure, we have a right one.... 661 * 1: Check not cross boundary on block 662 */ 663 if ((ip->i_number & imp->im_bmask) + isonum_711(dirp->length) 664 > (unsigned)imp->logical_block_size) { 665 brelse(bp); 666 return (EINVAL); 667 } 668 669 /* 670 * Now get a buffer 671 * Abuse a namei buffer for now. 672 */ 673 if (uio->uio_segflg == UIO_SYSSPACE) 674 symname = uio->uio_iov->iov_base; 675 else 676 symname = uma_zalloc(namei_zone, M_WAITOK); 677 678 /* 679 * Ok, we just gathering a symbolic name in SL record. 680 */ 681 if (cd9660_rrip_getsymname(dirp, symname, &symlen, imp) == 0) { 682 if (uio->uio_segflg != UIO_SYSSPACE) 683 uma_zfree(namei_zone, symname); 684 brelse(bp); 685 return (EINVAL); 686 } 687 /* 688 * Don't forget before you leave from home ;-) 689 */ 690 brelse(bp); 691 692 /* 693 * return with the symbolic name to caller's. 694 */ 695 if (uio->uio_segflg != UIO_SYSSPACE) { 696 error = uiomove(symname, symlen, uio); 697 uma_zfree(namei_zone, symname); 698 return (error); 699 } 700 uio->uio_resid -= symlen; 701 uio->uio_iov->iov_base = (char *)uio->uio_iov->iov_base + symlen; 702 uio->uio_iov->iov_len -= symlen; 703 return (0); 704} 705 706/* 707 * Calculate the logical to physical mapping if not done already, 708 * then call the device strategy routine. 709 */ 710static int 711cd9660_strategy(ap) 712 struct vop_strategy_args /* { 713 struct buf *a_vp; 714 struct buf *a_bp; 715 } */ *ap; 716{ 717 struct buf *bp = ap->a_bp; 718 struct vnode *vp = bp->b_vp; 719 struct iso_node *ip; 720 721 ip = VTOI(vp); 722 if (vp->v_type == VBLK || vp->v_type == VCHR) 723 panic("cd9660_strategy: spec"); 724 if (bp->b_blkno == bp->b_lblkno) { 725 bp->b_blkno = (ip->iso_start + bp->b_lblkno) << 726 (ip->i_mnt->im_bshift - DEV_BSHIFT); 727 if ((long)bp->b_blkno == -1) /* XXX: cut&paste junk ? */ 728 clrbuf(bp); 729 } 730 if ((long)bp->b_blkno == -1) { /* XXX: cut&paste junk ? */ 731 bufdone(bp); 732 return (0); 733 } 734 vp = ip->i_devvp; 735 bp->b_dev = vp->v_rdev; 736 VOP_SPECSTRATEGY(vp, bp); 737 return (0); 738} 739 740/* 741 * Return POSIX pathconf information applicable to cd9660 filesystems. 742 */ 743static int 744cd9660_pathconf(ap) 745 struct vop_pathconf_args /* { 746 struct vnode *a_vp; 747 int a_name; 748 register_t *a_retval; 749 } */ *ap; 750{ 751 752 switch (ap->a_name) { 753 case _PC_LINK_MAX: 754 *ap->a_retval = 1; 755 return (0); 756 case _PC_NAME_MAX: 757 if (VTOI(ap->a_vp)->i_mnt->iso_ftype == ISO_FTYPE_RRIP) 758 *ap->a_retval = NAME_MAX; 759 else 760 *ap->a_retval = 37; 761 return (0); 762 case _PC_PATH_MAX: 763 *ap->a_retval = PATH_MAX; 764 return (0); 765 case _PC_PIPE_BUF: 766 *ap->a_retval = PIPE_BUF; 767 return (0); 768 case _PC_CHOWN_RESTRICTED: 769 *ap->a_retval = 1; 770 return (0); 771 case _PC_NO_TRUNC: 772 *ap->a_retval = 1; 773 return (0); 774 default: 775 return (EINVAL); 776 } 777 /* NOTREACHED */ 778} 779 780/* 781 * Global vfs data structures for cd9660 782 */ 783vop_t **cd9660_vnodeop_p; 784static struct vnodeopv_entry_desc cd9660_vnodeop_entries[] = { 785 { &vop_default_desc, (vop_t *) vop_defaultop }, 786 { &vop_access_desc, (vop_t *) cd9660_access }, 787 { &vop_bmap_desc, (vop_t *) cd9660_bmap }, 788 { &vop_cachedlookup_desc, (vop_t *) cd9660_lookup }, 789 { &vop_getattr_desc, (vop_t *) cd9660_getattr }, 790 { &vop_inactive_desc, (vop_t *) cd9660_inactive }, 791 { &vop_ioctl_desc, (vop_t *) cd9660_ioctl }, 792 { &vop_lookup_desc, (vop_t *) vfs_cache_lookup }, 793 { &vop_pathconf_desc, (vop_t *) cd9660_pathconf }, 794 { &vop_read_desc, (vop_t *) cd9660_read }, 795 { &vop_readdir_desc, (vop_t *) cd9660_readdir }, 796 { &vop_readlink_desc, (vop_t *) cd9660_readlink }, 797 { &vop_reclaim_desc, (vop_t *) cd9660_reclaim }, 798 { &vop_setattr_desc, (vop_t *) cd9660_setattr }, 799 { &vop_strategy_desc, (vop_t *) cd9660_strategy }, 800 { NULL, NULL } 801}; 802static struct vnodeopv_desc cd9660_vnodeop_opv_desc = 803 { &cd9660_vnodeop_p, cd9660_vnodeop_entries }; 804VNODEOP_SET(cd9660_vnodeop_opv_desc); 805 806/* 807 * Special device vnode ops 808 */ 809vop_t **cd9660_specop_p; 810static struct vnodeopv_entry_desc cd9660_specop_entries[] = { 811 { &vop_default_desc, (vop_t *) spec_vnoperate }, 812 { &vop_access_desc, (vop_t *) cd9660_access }, 813 { &vop_getattr_desc, (vop_t *) cd9660_getattr }, 814 { &vop_inactive_desc, (vop_t *) cd9660_inactive }, 815 { &vop_reclaim_desc, (vop_t *) cd9660_reclaim }, 816 { &vop_setattr_desc, (vop_t *) cd9660_setattr }, 817 { NULL, NULL } 818}; 819static struct vnodeopv_desc cd9660_specop_opv_desc = 820 { &cd9660_specop_p, cd9660_specop_entries }; 821VNODEOP_SET(cd9660_specop_opv_desc); 822 823vop_t **cd9660_fifoop_p; 824static struct vnodeopv_entry_desc cd9660_fifoop_entries[] = { 825 { &vop_default_desc, (vop_t *) fifo_vnoperate }, 826 { &vop_access_desc, (vop_t *) cd9660_access }, 827 { &vop_getattr_desc, (vop_t *) cd9660_getattr }, 828 { &vop_inactive_desc, (vop_t *) cd9660_inactive }, 829 { &vop_reclaim_desc, (vop_t *) cd9660_reclaim }, 830 { &vop_setattr_desc, (vop_t *) cd9660_setattr }, 831 { NULL, NULL } 832}; 833static struct vnodeopv_desc cd9660_fifoop_opv_desc = 834 { &cd9660_fifoop_p, cd9660_fifoop_entries }; 835 836VNODEOP_SET(cd9660_fifoop_opv_desc);
|