40 */ 41 42#include <sys/param.h> 43#include <sys/systm.h> 44#include <sys/namei.h> 45#include <sys/resourcevar.h> 46#include <sys/kernel.h> 47#include <sys/file.h> 48#include <sys/stat.h> 49#include <sys/buf.h> 50#include <sys/proc.h> 51#include <sys/conf.h> 52#include <sys/mount.h> 53#include <sys/vnode.h> 54#include <miscfs/specfs/specdev.h> 55#include <miscfs/fifofs/fifo.h> 56#include <sys/malloc.h> 57#include <sys/dir.h> 58 59#include <isofs/cd9660/iso.h> 60#include <isofs/cd9660/cd9660_node.h> 61#include <isofs/cd9660/iso_rrip.h> 62 63#if 0 64/* 65 * Mknod vnode call 66 * Actually remap the device number 67 */ 68cd9660_mknod(ndp, vap, cred, p) 69 struct nameidata *ndp; 70 struct ucred *cred; 71 struct vattr *vap; 72 struct proc *p; 73{ 74#ifndef ISODEVMAP 75 free(ndp->ni_pnbuf, M_NAMEI); 76 vput(ndp->ni_dvp); 77 vput(ndp->ni_vp); 78 return EINVAL; 79#else 80 register struct vnode *vp; 81 struct iso_node *ip; 82 struct iso_dnode *dp; 83 int error; 84 85 vp = ndp->ni_vp; 86 ip = VTOI(vp); 87 88 if (ip->i_mnt->iso_ftype != ISO_FTYPE_RRIP 89 || vap->va_type != vp->v_type 90 || (vap->va_type != VCHR && vap->va_type != VBLK)) { 91 free(ndp->ni_pnbuf, M_NAMEI); 92 vput(ndp->ni_dvp); 93 vput(ndp->ni_vp); 94 return EINVAL; 95 } 96 97 dp = iso_dmap(ip->i_dev,ip->i_number,1); 98 if (ip->inode.iso_rdev == vap->va_rdev || vap->va_rdev == VNOVAL) { 99 /* same as the unmapped one, delete the mapping */ 100 remque(dp); 101 FREE(dp,M_CACHE); 102 } else 103 /* enter new mapping */ 104 dp->d_dev = vap->va_rdev; 105 106 /* 107 * Remove inode so that it will be reloaded by iget and 108 * checked to see if it is an alias of an existing entry 109 * in the inode cache. 110 */ 111 vput(vp); 112 vp->v_type = VNON; 113 vgone(vp); 114 return (0); 115#endif 116} 117#endif 118 119/* 120 * Open called. 121 * 122 * Nothing to do. 123 */ 124/* ARGSUSED */ 125int 126cd9660_open(ap) 127 struct vop_open_args /* { 128 struct vnode *a_vp; 129 int a_mode; 130 struct ucred *a_cred; 131 struct proc *a_p; 132 } */ *ap; 133{ 134 return (0); 135} 136 137/* 138 * Close called 139 * 140 * Update the times on the inode on writeable file systems. 141 */ 142/* ARGSUSED */ 143int 144cd9660_close(ap) 145 struct vop_close_args /* { 146 struct vnode *a_vp; 147 int a_fflag; 148 struct ucred *a_cred; 149 struct proc *a_p; 150 } */ *ap; 151{ 152 return (0); 153} 154 155/* 156 * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC. 157 * The mode is shifted to select the owner/group/other fields. The 158 * super user is granted all permissions. 159 */ 160/* ARGSUSED */ 161int 162cd9660_access(ap) 163 struct vop_access_args /* { 164 struct vnode *a_vp; 165 int a_mode; 166 struct ucred *a_cred; 167 struct proc *a_p; 168 } */ *ap; 169{ 170 return (0); 171} 172 173int 174cd9660_getattr(ap) 175 struct vop_getattr_args /* { 176 struct vnode *a_vp; 177 struct vattr *a_vap; 178 struct ucred *a_cred; 179 struct proc *a_p; 180 } */ *ap; 181 182{ 183 struct vnode *vp = ap->a_vp; 184 register struct vattr *vap = ap->a_vap; 185 register struct iso_node *ip = VTOI(vp); 186 187 vap->va_fsid = ip->i_dev; 188 vap->va_fileid = ip->i_number; 189 190 vap->va_mode = ip->inode.iso_mode; 191 vap->va_nlink = ip->inode.iso_links; 192 vap->va_uid = ip->inode.iso_uid; 193 vap->va_gid = ip->inode.iso_gid; 194 vap->va_atime = ip->inode.iso_atime; 195 vap->va_mtime = ip->inode.iso_mtime; 196 vap->va_ctime = ip->inode.iso_ctime; 197 vap->va_rdev = ip->inode.iso_rdev; 198 199 vap->va_size = (u_quad_t) ip->i_size; 200 vap->va_flags = 0; 201 vap->va_gen = 1; 202 vap->va_blocksize = ip->i_mnt->logical_block_size; 203 vap->va_bytes = (u_quad_t) ip->i_size; 204 vap->va_type = vp->v_type; 205 vap->va_filerev = 0; 206 return (0); 207} 208 209#if ISO_DEFAULT_BLOCK_SIZE >= NBPG 210#ifdef DEBUG 211extern int doclusterread; 212#else 213#define doclusterread 1 214#endif 215#else 216/* XXX until cluster routines can handle block sizes less than one page */ 217#define doclusterread 0 218#endif 219 220/* 221 * Vnode op for reading. 222 */ 223int 224cd9660_read(ap) 225 struct vop_read_args /* { 226 struct vnode *a_vp; 227 struct uio *a_uio; 228 int a_ioflag; 229 struct ucred *a_cred; 230 } */ *ap; 231{ 232 struct vnode *vp = ap->a_vp; 233 register struct uio *uio = ap->a_uio; 234 register struct iso_node *ip = VTOI(vp); 235 register struct iso_mnt *imp; 236 struct buf *bp; 237 daddr_t lbn, rablock; 238 off_t diff; 239 int rasize, error = 0; 240 long size, n, on; 241 242 if (uio->uio_resid == 0) 243 return (0); 244 if (uio->uio_offset < 0) 245 return (EINVAL); 246 ip->i_flag |= IACC; 247 imp = ip->i_mnt; 248 do { 249 lbn = iso_lblkno(imp, uio->uio_offset); 250 on = iso_blkoff(imp, uio->uio_offset); 251 n = min((unsigned)(imp->logical_block_size - on), 252 uio->uio_resid); 253 diff = (off_t)ip->i_size - uio->uio_offset; 254 if (diff <= 0) 255 return (0); 256 if (diff < n) 257 n = diff; 258 size = iso_blksize(imp, ip, lbn); 259 rablock = lbn + 1; 260 if (doclusterread) { 261 if (iso_lblktosize(imp, rablock) <= ip->i_size) 262 error = cluster_read(vp, (off_t)ip->i_size, 263 lbn, size, NOCRED, &bp); 264 else 265 error = bread(vp, lbn, size, NOCRED, &bp); 266 } else { 267 if (vp->v_lastr + 1 == lbn && 268 iso_lblktosize(imp, rablock) < ip->i_size) { 269 rasize = iso_blksize(imp, ip, rablock); 270 error = breadn(vp, lbn, size, &rablock, 271 &rasize, 1, NOCRED, &bp); 272 } else 273 error = bread(vp, lbn, size, NOCRED, &bp); 274 } 275 vp->v_lastr = lbn; 276 n = min(n, size - bp->b_resid); 277 if (error) { 278 brelse(bp); 279 return (error); 280 } 281 282 error = uiomove(bp->b_un.b_addr + on, (int)n, uio); 283 brelse(bp); 284 } while (error == 0 && uio->uio_resid > 0 && n != 0); 285 return (error); 286} 287 288/* ARGSUSED */ 289int 290cd9660_ioctl(ap) 291 struct vop_ioctl_args /* { 292 struct vnode *a_vp; 293 int a_command; 294 caddr_t a_data; 295 int a_fflag; 296 struct ucred *a_cred; 297 struct proc *a_p; 298 } */ *ap; 299{ 300 printf("You did ioctl for isofs !!\n"); 301 return (ENOTTY); 302} 303 304/* ARGSUSED */ 305int 306cd9660_select(ap) 307 struct vop_select_args /* { 308 struct vnode *a_vp; 309 int a_which; 310 int a_fflags; 311 struct ucred *a_cred; 312 struct proc *a_p; 313 } */ *ap; 314{ 315 316 /* 317 * We should really check to see if I/O is possible. 318 */ 319 return (1); 320} 321 322/* 323 * Mmap a file 324 * 325 * NB Currently unsupported. 326 */ 327/* ARGSUSED */ 328int 329cd9660_mmap(ap) 330 struct vop_mmap_args /* { 331 struct vnode *a_vp; 332 int a_fflags; 333 struct ucred *a_cred; 334 struct proc *a_p; 335 } */ *ap; 336{ 337 338 return (EINVAL); 339} 340 341/* 342 * Seek on a file 343 * 344 * Nothing to do, so just return. 345 */ 346/* ARGSUSED */ 347int 348cd9660_seek(ap) 349 struct vop_seek_args /* { 350 struct vnode *a_vp; 351 off_t a_oldoff; 352 off_t a_newoff; 353 struct ucred *a_cred; 354 } */ *ap; 355{ 356 357 return (0); 358} 359 360/* 361 * Structure for reading directories 362 */ 363struct isoreaddir { 364 struct dirent saveent; 365 struct dirent assocent; 366 struct dirent current; 367 off_t saveoff; 368 off_t assocoff; 369 off_t curroff; 370 struct uio *uio; 371 off_t uio_off; 372 u_int *cookiep; 373 int ncookies; 374 int eof; 375}; 376 377static int 378iso_uiodir(idp,dp,off) 379 struct isoreaddir *idp; 380 struct dirent *dp; 381 off_t off; 382{ 383 int error; 384 385 dp->d_name[dp->d_namlen] = 0; 386 dp->d_reclen = DIRSIZ(dp); 387 388 if (idp->uio->uio_resid < dp->d_reclen) { 389 idp->eof = 0; 390 return -1; 391 } 392 393 if (idp->cookiep) { 394 if (idp->ncookies <= 0) { 395 idp->eof = 0; 396 return -1; 397 } 398 399 *idp->cookiep++ = off; 400 --idp->ncookies; 401 } 402 403 if ((error = uiomove((caddr_t)dp,dp->d_reclen,idp->uio))) 404 return error; 405 idp->uio_off = off; 406 return 0; 407} 408 409static int 410iso_shipdir(idp) 411 struct isoreaddir *idp; 412{ 413 struct dirent *dp; 414 int cl, sl, assoc; 415 int error; 416 char *cname, *sname; 417 418 cl = idp->current.d_namlen; 419 cname = idp->current.d_name; 420assoc = (cl > 1) && (*cname == ASSOCCHAR); 421 if (assoc) { 422 cl--; 423 cname++; 424 } 425 426 dp = &idp->saveent; 427 sname = dp->d_name; 428 if (!(sl = dp->d_namlen)) { 429 dp = &idp->assocent; 430 sname = dp->d_name + 1; 431 sl = dp->d_namlen - 1; 432 } 433 if (sl > 0) { 434 if (sl != cl 435 || bcmp(sname,cname,sl)) { 436 if (idp->assocent.d_namlen) { 437 if ((error = iso_uiodir(idp,&idp->assocent,idp->assocoff))) 438 return error; 439 idp->assocent.d_namlen = 0; 440 } 441 if (idp->saveent.d_namlen) { 442 if ((error = iso_uiodir(idp,&idp->saveent,idp->saveoff))) 443 return error; 444 idp->saveent.d_namlen = 0; 445 } 446 } 447 } 448 idp->current.d_reclen = DIRSIZ(&idp->current); 449 if (assoc) { 450 idp->assocoff = idp->curroff; 451 bcopy(&idp->current,&idp->assocent,idp->current.d_reclen); 452 } else { 453 idp->saveoff = idp->curroff; 454 bcopy(&idp->current,&idp->saveent,idp->current.d_reclen); 455 } 456 return 0; 457} 458 459/* 460 * Vnode op for readdir 461 * XXX make sure everything still works now that eofflagp and cookiep 462 * are no longer args. 463 */ 464int 465cd9660_readdir(ap) 466 struct vop_readdir_args /* { 467 struct vnode *a_vp; 468 struct uio *a_uio; 469 struct ucred *a_cred; 470 } */ *ap; 471{ 472 register struct uio *uio = ap->a_uio; 473 struct isoreaddir *idp; 474 int entryoffsetinblock; 475 int error = 0; 476 int endsearch; 477 struct iso_directory_record *ep; 478 u_short elen; 479 int reclen; 480 int isoflags; 481 struct iso_mnt *imp; 482 struct iso_node *ip; 483 struct buf *bp = NULL; 484 u_short tmplen; 485 int ncookies = 0; 486 u_int *cookies = NULL; 487 488 ip = VTOI(ap->a_vp); 489 imp = ip->i_mnt; 490 491 MALLOC(idp,struct isoreaddir *,sizeof(*idp),M_TEMP,M_WAITOK); 492 idp->saveent.d_namlen = 0; 493 idp->assocent.d_namlen = 0; 494 idp->uio = uio; 495 if (ap->a_ncookies != NULL) { 496 /* 497 * Guess the number of cookies needed. 498 */ 499 ncookies = uio->uio_resid / 16; 500 MALLOC(cookies, u_int *, ncookies * sizeof(u_int), M_TEMP, M_WAITOK); 501 idp->cookiep = cookies; 502 idp->ncookies = ncookies; 503 } else 504 idp->cookiep = 0; 505 idp->eof = 0; 506 idp->curroff = uio->uio_offset; 507 508 entryoffsetinblock = iso_blkoff(imp, idp->curroff); 509 if (entryoffsetinblock != 0) { 510 if ((error = iso_blkatoff(ip, idp->curroff, &bp))) { 511 FREE(idp,M_TEMP); 512 return (error); 513 } 514 } 515 516 endsearch = ip->i_size; 517 518 while (idp->curroff < endsearch) { 519 /* 520 * If offset is on a block boundary, 521 * read the next directory block. 522 * Release previous if it exists. 523 */ 524 525 if (iso_blkoff(imp, idp->curroff) == 0) { 526 if (bp != NULL) 527 brelse(bp); 528 if ((error = iso_blkatoff(ip, idp->curroff, &bp))) 529 break; 530 entryoffsetinblock = 0; 531 } 532 /* 533 * Get pointer to next entry. 534 */ 535 536 ep = (struct iso_directory_record *) 537 (bp->b_un.b_addr + entryoffsetinblock); 538 539 reclen = isonum_711 (ep->length); 540 isoflags = isonum_711(imp->iso_ftype == ISO_FTYPE_HIGH_SIERRA? 541 &ep->date[6]: ep->flags); 542 if (reclen == 0) { 543 /* skip to next block, if any */ 544 idp->curroff = roundup (idp->curroff, 545 imp->logical_block_size); 546 continue; 547 } 548 549 if (reclen < ISO_DIRECTORY_RECORD_SIZE) { 550 error = EINVAL; 551 /* illegal entry, stop */ 552 break; 553 } 554 555 if (entryoffsetinblock + reclen > imp->logical_block_size) { 556 error = EINVAL; 557 /* illegal directory, so stop looking */ 558 break; 559 } 560 561 /* XXX: be more intelligent if we can */ 562 idp->current.d_type = DT_UNKNOWN; 563 564 idp->current.d_namlen = isonum_711 (ep->name_len); 565 if (isoflags & 2) 566 isodirino(&idp->current.d_fileno,ep,imp); 567 else 568 idp->current.d_fileno = dbtob(bp->b_blkno) + 569 idp->curroff; 570 571 if (reclen < ISO_DIRECTORY_RECORD_SIZE + idp->current.d_namlen) { 572 error = EINVAL; 573 /* illegal entry, stop */ 574 break; 575 } 576 577 idp->curroff += reclen; 578 /* 579 * 580 */ 581 switch (imp->iso_ftype) { 582 case ISO_FTYPE_RRIP: 583 cd9660_rrip_getname(ep,idp->current.d_name, 584 &tmplen, 585 &idp->current.d_fileno,imp); 586 idp->current.d_namlen = tmplen; 587 if (idp->current.d_namlen) 588 error = iso_uiodir(idp,&idp->current,idp->curroff); 589 break; 590 default: /* ISO_FTYPE_DEFAULT || ISO_FTYPE_9660 || ISO_FTYPE_HIGH_SIERRA*/ 591 strcpy(idp->current.d_name,".."); 592 switch (ep->name[0]) { 593 case 0: 594 idp->current.d_namlen = 1; 595 error = iso_uiodir(idp,&idp->current,idp->curroff); 596 break; 597 case 1: 598 idp->current.d_namlen = 2; 599 error = iso_uiodir(idp,&idp->current,idp->curroff); 600 break; 601 default: 602 isofntrans(ep->name,idp->current.d_namlen, 603 idp->current.d_name, &elen, 604 imp->iso_ftype == ISO_FTYPE_9660, 605 isoflags & 4); 606 idp->current.d_namlen = (u_char)elen; 607 if (imp->iso_ftype == ISO_FTYPE_DEFAULT) 608 error = iso_shipdir(idp); 609 else 610 error = iso_uiodir(idp,&idp->current,idp->curroff); 611 break; 612 } 613 } 614 if (error) 615 break; 616 617 entryoffsetinblock += reclen; 618 } 619 620 if (!error && imp->iso_ftype == ISO_FTYPE_DEFAULT) { 621 idp->current.d_namlen = 0; 622 error = iso_shipdir(idp); 623 } 624 if (error < 0) 625 error = 0; 626 627 if (ap->a_ncookies != NULL) { 628 if (error) 629 FREE(cookies, M_TEMP); 630 else { 631 /* 632 * Work out the number of cookies actually used. 633 */ 634 *ap->a_ncookies = ncookies - idp->ncookies; 635 *ap->a_cookies = cookies; 636 } 637 } 638 639 if (bp) 640 brelse (bp); 641 642 uio->uio_offset = idp->uio_off; 643 if (ap->a_eofflag) 644 *ap->a_eofflag = idp->eof; 645 646 FREE(idp,M_TEMP); 647 648 return (error); 649} 650 651/* 652 * Return target name of a symbolic link 653 * Shouldn't we get the parent vnode and read the data from there? 654 * This could eventually result in deadlocks in cd9660_lookup. 655 * But otherwise the block read here is in the block buffer two times. 656 */ 657typedef struct iso_directory_record ISODIR; 658typedef struct iso_node ISONODE; 659typedef struct iso_mnt ISOMNT; 660int 661cd9660_readlink(ap) 662 struct vop_readlink_args /* { 663 struct vnode *a_vp; 664 struct uio *a_uio; 665 struct ucred *a_cred; 666 } */ *ap; 667{ 668 ISONODE *ip; 669 ISODIR *dirp; 670 ISOMNT *imp; 671 struct buf *bp; 672 u_short symlen; 673 int error; 674 char *symname; 675 676 ip = VTOI(ap->a_vp); 677 imp = ip->i_mnt; 678 679 if (imp->iso_ftype != ISO_FTYPE_RRIP) 680 return EINVAL; 681 682 /* 683 * Get parents directory record block that this inode included. 684 */ 685 error = bread(imp->im_devvp, 686 iso_dblkno(imp, ip->i_number), 687 imp->logical_block_size, 688 NOCRED, 689 &bp); 690 if (error) { 691 brelse(bp); 692 return EINVAL; 693 } 694 695 /* 696 * Setup the directory pointer for this inode 697 */ 698 dirp = (ISODIR *)(bp->b_un.b_addr + (ip->i_number & imp->im_bmask)); 699#ifdef DEBUG 700 printf("lbn=%d,off=%d,bsize=%d,DEV_BSIZE=%d, dirp= %08x, b_addr=%08x, offset=%08x(%08x)\n", 701 (daddr_t)(ip->i_number >> imp->im_bshift), 702 ip->i_number & imp->im_bmask, 703 imp->logical_block_size, 704 DEV_BSIZE, 705 dirp, 706 bp->b_un.b_addr, 707 ip->i_number, 708 ip->i_number & imp->im_bmask ); 709#endif 710 711 /* 712 * Just make sure, we have a right one.... 713 * 1: Check not cross boundary on block 714 */ 715 if ((ip->i_number & imp->im_bmask) + isonum_711(dirp->length) 716 > imp->logical_block_size) { 717 brelse(bp); 718 return EINVAL; 719 } 720 721 /* 722 * Now get a buffer 723 * Abuse a namei buffer for now. 724 */ 725 MALLOC(symname,char *,MAXPATHLEN,M_NAMEI,M_WAITOK); 726 727 /* 728 * Ok, we just gathering a symbolic name in SL record. 729 */ 730 if (cd9660_rrip_getsymname(dirp,symname,&symlen,imp) == 0) { 731 FREE(symname,M_NAMEI); 732 brelse(bp); 733 return EINVAL; 734 } 735 /* 736 * Don't forget before you leave from home ;-) 737 */ 738 brelse(bp); 739 740 /* 741 * return with the symbolic name to caller's. 742 */ 743 error = uiomove(symname,symlen,ap->a_uio); 744 745 FREE(symname,M_NAMEI); 746 747 return error; 748} 749 750/* 751 * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually 752 * done. If a buffer has been saved in anticipation of a CREATE, delete it. 753 */ 754int 755cd9660_abortop(ap) 756 struct vop_abortop_args /* { 757 struct vnode *a_dvp; 758 struct componentname *a_cnp; 759 } */ *ap; 760{ 761 if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) 762 FREE(ap->a_cnp->cn_pnbuf, M_NAMEI); 763 return 0; 764} 765 766/* 767 * Lock an inode. 768 */ 769int 770cd9660_lock(ap) 771 struct vop_lock_args /* { 772 struct vnode *a_vp; 773 } */ *ap; 774{ 775 register struct iso_node *ip = VTOI(ap->a_vp); 776 777 ISO_ILOCK(ip); 778 return 0; 779} 780 781/* 782 * Unlock an inode. 783 */ 784int 785cd9660_unlock(ap) 786 struct vop_unlock_args /* { 787 struct vnode *a_vp; 788 } */ *ap; 789{ 790 register struct iso_node *ip = VTOI(ap->a_vp); 791 792 if (!(ip->i_flag & ILOCKED)) 793 panic("cd9660_unlock NOT LOCKED"); 794 ISO_IUNLOCK(ip); 795 return 0; 796} 797 798/* 799 * Check for a locked inode. 800 */ 801int 802cd9660_islocked(ap) 803 struct vop_islocked_args /* { 804 struct vnode *a_vp; 805 } */ *ap; 806{ 807 808 if (VTOI(ap->a_vp)->i_flag & ILOCKED) 809 return 1; 810 return 0; 811} 812 813/* 814 * Calculate the logical to physical mapping if not done already, 815 * then call the device strategy routine. 816 */ 817int 818cd9660_strategy(ap) 819 struct vop_strategy_args /* { 820 struct buf *a_bp; 821 } */ *ap; 822{ 823 register struct buf *bp = ap->a_bp; 824 register struct vnode *vp = bp->b_vp; 825 register struct iso_node *ip; 826 int error; 827 828 ip = VTOI(vp); 829 if (vp->v_type == VBLK || vp->v_type == VCHR) 830 panic("cd9660_strategy: spec"); 831 if (bp->b_blkno == bp->b_lblkno) { 832 if ((error =
| 40 */ 41 42#include <sys/param.h> 43#include <sys/systm.h> 44#include <sys/namei.h> 45#include <sys/resourcevar.h> 46#include <sys/kernel.h> 47#include <sys/file.h> 48#include <sys/stat.h> 49#include <sys/buf.h> 50#include <sys/proc.h> 51#include <sys/conf.h> 52#include <sys/mount.h> 53#include <sys/vnode.h> 54#include <miscfs/specfs/specdev.h> 55#include <miscfs/fifofs/fifo.h> 56#include <sys/malloc.h> 57#include <sys/dir.h> 58 59#include <isofs/cd9660/iso.h> 60#include <isofs/cd9660/cd9660_node.h> 61#include <isofs/cd9660/iso_rrip.h> 62 63#if 0 64/* 65 * Mknod vnode call 66 * Actually remap the device number 67 */ 68cd9660_mknod(ndp, vap, cred, p) 69 struct nameidata *ndp; 70 struct ucred *cred; 71 struct vattr *vap; 72 struct proc *p; 73{ 74#ifndef ISODEVMAP 75 free(ndp->ni_pnbuf, M_NAMEI); 76 vput(ndp->ni_dvp); 77 vput(ndp->ni_vp); 78 return EINVAL; 79#else 80 register struct vnode *vp; 81 struct iso_node *ip; 82 struct iso_dnode *dp; 83 int error; 84 85 vp = ndp->ni_vp; 86 ip = VTOI(vp); 87 88 if (ip->i_mnt->iso_ftype != ISO_FTYPE_RRIP 89 || vap->va_type != vp->v_type 90 || (vap->va_type != VCHR && vap->va_type != VBLK)) { 91 free(ndp->ni_pnbuf, M_NAMEI); 92 vput(ndp->ni_dvp); 93 vput(ndp->ni_vp); 94 return EINVAL; 95 } 96 97 dp = iso_dmap(ip->i_dev,ip->i_number,1); 98 if (ip->inode.iso_rdev == vap->va_rdev || vap->va_rdev == VNOVAL) { 99 /* same as the unmapped one, delete the mapping */ 100 remque(dp); 101 FREE(dp,M_CACHE); 102 } else 103 /* enter new mapping */ 104 dp->d_dev = vap->va_rdev; 105 106 /* 107 * Remove inode so that it will be reloaded by iget and 108 * checked to see if it is an alias of an existing entry 109 * in the inode cache. 110 */ 111 vput(vp); 112 vp->v_type = VNON; 113 vgone(vp); 114 return (0); 115#endif 116} 117#endif 118 119/* 120 * Open called. 121 * 122 * Nothing to do. 123 */ 124/* ARGSUSED */ 125int 126cd9660_open(ap) 127 struct vop_open_args /* { 128 struct vnode *a_vp; 129 int a_mode; 130 struct ucred *a_cred; 131 struct proc *a_p; 132 } */ *ap; 133{ 134 return (0); 135} 136 137/* 138 * Close called 139 * 140 * Update the times on the inode on writeable file systems. 141 */ 142/* ARGSUSED */ 143int 144cd9660_close(ap) 145 struct vop_close_args /* { 146 struct vnode *a_vp; 147 int a_fflag; 148 struct ucred *a_cred; 149 struct proc *a_p; 150 } */ *ap; 151{ 152 return (0); 153} 154 155/* 156 * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC. 157 * The mode is shifted to select the owner/group/other fields. The 158 * super user is granted all permissions. 159 */ 160/* ARGSUSED */ 161int 162cd9660_access(ap) 163 struct vop_access_args /* { 164 struct vnode *a_vp; 165 int a_mode; 166 struct ucred *a_cred; 167 struct proc *a_p; 168 } */ *ap; 169{ 170 return (0); 171} 172 173int 174cd9660_getattr(ap) 175 struct vop_getattr_args /* { 176 struct vnode *a_vp; 177 struct vattr *a_vap; 178 struct ucred *a_cred; 179 struct proc *a_p; 180 } */ *ap; 181 182{ 183 struct vnode *vp = ap->a_vp; 184 register struct vattr *vap = ap->a_vap; 185 register struct iso_node *ip = VTOI(vp); 186 187 vap->va_fsid = ip->i_dev; 188 vap->va_fileid = ip->i_number; 189 190 vap->va_mode = ip->inode.iso_mode; 191 vap->va_nlink = ip->inode.iso_links; 192 vap->va_uid = ip->inode.iso_uid; 193 vap->va_gid = ip->inode.iso_gid; 194 vap->va_atime = ip->inode.iso_atime; 195 vap->va_mtime = ip->inode.iso_mtime; 196 vap->va_ctime = ip->inode.iso_ctime; 197 vap->va_rdev = ip->inode.iso_rdev; 198 199 vap->va_size = (u_quad_t) ip->i_size; 200 vap->va_flags = 0; 201 vap->va_gen = 1; 202 vap->va_blocksize = ip->i_mnt->logical_block_size; 203 vap->va_bytes = (u_quad_t) ip->i_size; 204 vap->va_type = vp->v_type; 205 vap->va_filerev = 0; 206 return (0); 207} 208 209#if ISO_DEFAULT_BLOCK_SIZE >= NBPG 210#ifdef DEBUG 211extern int doclusterread; 212#else 213#define doclusterread 1 214#endif 215#else 216/* XXX until cluster routines can handle block sizes less than one page */ 217#define doclusterread 0 218#endif 219 220/* 221 * Vnode op for reading. 222 */ 223int 224cd9660_read(ap) 225 struct vop_read_args /* { 226 struct vnode *a_vp; 227 struct uio *a_uio; 228 int a_ioflag; 229 struct ucred *a_cred; 230 } */ *ap; 231{ 232 struct vnode *vp = ap->a_vp; 233 register struct uio *uio = ap->a_uio; 234 register struct iso_node *ip = VTOI(vp); 235 register struct iso_mnt *imp; 236 struct buf *bp; 237 daddr_t lbn, rablock; 238 off_t diff; 239 int rasize, error = 0; 240 long size, n, on; 241 242 if (uio->uio_resid == 0) 243 return (0); 244 if (uio->uio_offset < 0) 245 return (EINVAL); 246 ip->i_flag |= IACC; 247 imp = ip->i_mnt; 248 do { 249 lbn = iso_lblkno(imp, uio->uio_offset); 250 on = iso_blkoff(imp, uio->uio_offset); 251 n = min((unsigned)(imp->logical_block_size - on), 252 uio->uio_resid); 253 diff = (off_t)ip->i_size - uio->uio_offset; 254 if (diff <= 0) 255 return (0); 256 if (diff < n) 257 n = diff; 258 size = iso_blksize(imp, ip, lbn); 259 rablock = lbn + 1; 260 if (doclusterread) { 261 if (iso_lblktosize(imp, rablock) <= ip->i_size) 262 error = cluster_read(vp, (off_t)ip->i_size, 263 lbn, size, NOCRED, &bp); 264 else 265 error = bread(vp, lbn, size, NOCRED, &bp); 266 } else { 267 if (vp->v_lastr + 1 == lbn && 268 iso_lblktosize(imp, rablock) < ip->i_size) { 269 rasize = iso_blksize(imp, ip, rablock); 270 error = breadn(vp, lbn, size, &rablock, 271 &rasize, 1, NOCRED, &bp); 272 } else 273 error = bread(vp, lbn, size, NOCRED, &bp); 274 } 275 vp->v_lastr = lbn; 276 n = min(n, size - bp->b_resid); 277 if (error) { 278 brelse(bp); 279 return (error); 280 } 281 282 error = uiomove(bp->b_un.b_addr + on, (int)n, uio); 283 brelse(bp); 284 } while (error == 0 && uio->uio_resid > 0 && n != 0); 285 return (error); 286} 287 288/* ARGSUSED */ 289int 290cd9660_ioctl(ap) 291 struct vop_ioctl_args /* { 292 struct vnode *a_vp; 293 int a_command; 294 caddr_t a_data; 295 int a_fflag; 296 struct ucred *a_cred; 297 struct proc *a_p; 298 } */ *ap; 299{ 300 printf("You did ioctl for isofs !!\n"); 301 return (ENOTTY); 302} 303 304/* ARGSUSED */ 305int 306cd9660_select(ap) 307 struct vop_select_args /* { 308 struct vnode *a_vp; 309 int a_which; 310 int a_fflags; 311 struct ucred *a_cred; 312 struct proc *a_p; 313 } */ *ap; 314{ 315 316 /* 317 * We should really check to see if I/O is possible. 318 */ 319 return (1); 320} 321 322/* 323 * Mmap a file 324 * 325 * NB Currently unsupported. 326 */ 327/* ARGSUSED */ 328int 329cd9660_mmap(ap) 330 struct vop_mmap_args /* { 331 struct vnode *a_vp; 332 int a_fflags; 333 struct ucred *a_cred; 334 struct proc *a_p; 335 } */ *ap; 336{ 337 338 return (EINVAL); 339} 340 341/* 342 * Seek on a file 343 * 344 * Nothing to do, so just return. 345 */ 346/* ARGSUSED */ 347int 348cd9660_seek(ap) 349 struct vop_seek_args /* { 350 struct vnode *a_vp; 351 off_t a_oldoff; 352 off_t a_newoff; 353 struct ucred *a_cred; 354 } */ *ap; 355{ 356 357 return (0); 358} 359 360/* 361 * Structure for reading directories 362 */ 363struct isoreaddir { 364 struct dirent saveent; 365 struct dirent assocent; 366 struct dirent current; 367 off_t saveoff; 368 off_t assocoff; 369 off_t curroff; 370 struct uio *uio; 371 off_t uio_off; 372 u_int *cookiep; 373 int ncookies; 374 int eof; 375}; 376 377static int 378iso_uiodir(idp,dp,off) 379 struct isoreaddir *idp; 380 struct dirent *dp; 381 off_t off; 382{ 383 int error; 384 385 dp->d_name[dp->d_namlen] = 0; 386 dp->d_reclen = DIRSIZ(dp); 387 388 if (idp->uio->uio_resid < dp->d_reclen) { 389 idp->eof = 0; 390 return -1; 391 } 392 393 if (idp->cookiep) { 394 if (idp->ncookies <= 0) { 395 idp->eof = 0; 396 return -1; 397 } 398 399 *idp->cookiep++ = off; 400 --idp->ncookies; 401 } 402 403 if ((error = uiomove((caddr_t)dp,dp->d_reclen,idp->uio))) 404 return error; 405 idp->uio_off = off; 406 return 0; 407} 408 409static int 410iso_shipdir(idp) 411 struct isoreaddir *idp; 412{ 413 struct dirent *dp; 414 int cl, sl, assoc; 415 int error; 416 char *cname, *sname; 417 418 cl = idp->current.d_namlen; 419 cname = idp->current.d_name; 420assoc = (cl > 1) && (*cname == ASSOCCHAR); 421 if (assoc) { 422 cl--; 423 cname++; 424 } 425 426 dp = &idp->saveent; 427 sname = dp->d_name; 428 if (!(sl = dp->d_namlen)) { 429 dp = &idp->assocent; 430 sname = dp->d_name + 1; 431 sl = dp->d_namlen - 1; 432 } 433 if (sl > 0) { 434 if (sl != cl 435 || bcmp(sname,cname,sl)) { 436 if (idp->assocent.d_namlen) { 437 if ((error = iso_uiodir(idp,&idp->assocent,idp->assocoff))) 438 return error; 439 idp->assocent.d_namlen = 0; 440 } 441 if (idp->saveent.d_namlen) { 442 if ((error = iso_uiodir(idp,&idp->saveent,idp->saveoff))) 443 return error; 444 idp->saveent.d_namlen = 0; 445 } 446 } 447 } 448 idp->current.d_reclen = DIRSIZ(&idp->current); 449 if (assoc) { 450 idp->assocoff = idp->curroff; 451 bcopy(&idp->current,&idp->assocent,idp->current.d_reclen); 452 } else { 453 idp->saveoff = idp->curroff; 454 bcopy(&idp->current,&idp->saveent,idp->current.d_reclen); 455 } 456 return 0; 457} 458 459/* 460 * Vnode op for readdir 461 * XXX make sure everything still works now that eofflagp and cookiep 462 * are no longer args. 463 */ 464int 465cd9660_readdir(ap) 466 struct vop_readdir_args /* { 467 struct vnode *a_vp; 468 struct uio *a_uio; 469 struct ucred *a_cred; 470 } */ *ap; 471{ 472 register struct uio *uio = ap->a_uio; 473 struct isoreaddir *idp; 474 int entryoffsetinblock; 475 int error = 0; 476 int endsearch; 477 struct iso_directory_record *ep; 478 u_short elen; 479 int reclen; 480 int isoflags; 481 struct iso_mnt *imp; 482 struct iso_node *ip; 483 struct buf *bp = NULL; 484 u_short tmplen; 485 int ncookies = 0; 486 u_int *cookies = NULL; 487 488 ip = VTOI(ap->a_vp); 489 imp = ip->i_mnt; 490 491 MALLOC(idp,struct isoreaddir *,sizeof(*idp),M_TEMP,M_WAITOK); 492 idp->saveent.d_namlen = 0; 493 idp->assocent.d_namlen = 0; 494 idp->uio = uio; 495 if (ap->a_ncookies != NULL) { 496 /* 497 * Guess the number of cookies needed. 498 */ 499 ncookies = uio->uio_resid / 16; 500 MALLOC(cookies, u_int *, ncookies * sizeof(u_int), M_TEMP, M_WAITOK); 501 idp->cookiep = cookies; 502 idp->ncookies = ncookies; 503 } else 504 idp->cookiep = 0; 505 idp->eof = 0; 506 idp->curroff = uio->uio_offset; 507 508 entryoffsetinblock = iso_blkoff(imp, idp->curroff); 509 if (entryoffsetinblock != 0) { 510 if ((error = iso_blkatoff(ip, idp->curroff, &bp))) { 511 FREE(idp,M_TEMP); 512 return (error); 513 } 514 } 515 516 endsearch = ip->i_size; 517 518 while (idp->curroff < endsearch) { 519 /* 520 * If offset is on a block boundary, 521 * read the next directory block. 522 * Release previous if it exists. 523 */ 524 525 if (iso_blkoff(imp, idp->curroff) == 0) { 526 if (bp != NULL) 527 brelse(bp); 528 if ((error = iso_blkatoff(ip, idp->curroff, &bp))) 529 break; 530 entryoffsetinblock = 0; 531 } 532 /* 533 * Get pointer to next entry. 534 */ 535 536 ep = (struct iso_directory_record *) 537 (bp->b_un.b_addr + entryoffsetinblock); 538 539 reclen = isonum_711 (ep->length); 540 isoflags = isonum_711(imp->iso_ftype == ISO_FTYPE_HIGH_SIERRA? 541 &ep->date[6]: ep->flags); 542 if (reclen == 0) { 543 /* skip to next block, if any */ 544 idp->curroff = roundup (idp->curroff, 545 imp->logical_block_size); 546 continue; 547 } 548 549 if (reclen < ISO_DIRECTORY_RECORD_SIZE) { 550 error = EINVAL; 551 /* illegal entry, stop */ 552 break; 553 } 554 555 if (entryoffsetinblock + reclen > imp->logical_block_size) { 556 error = EINVAL; 557 /* illegal directory, so stop looking */ 558 break; 559 } 560 561 /* XXX: be more intelligent if we can */ 562 idp->current.d_type = DT_UNKNOWN; 563 564 idp->current.d_namlen = isonum_711 (ep->name_len); 565 if (isoflags & 2) 566 isodirino(&idp->current.d_fileno,ep,imp); 567 else 568 idp->current.d_fileno = dbtob(bp->b_blkno) + 569 idp->curroff; 570 571 if (reclen < ISO_DIRECTORY_RECORD_SIZE + idp->current.d_namlen) { 572 error = EINVAL; 573 /* illegal entry, stop */ 574 break; 575 } 576 577 idp->curroff += reclen; 578 /* 579 * 580 */ 581 switch (imp->iso_ftype) { 582 case ISO_FTYPE_RRIP: 583 cd9660_rrip_getname(ep,idp->current.d_name, 584 &tmplen, 585 &idp->current.d_fileno,imp); 586 idp->current.d_namlen = tmplen; 587 if (idp->current.d_namlen) 588 error = iso_uiodir(idp,&idp->current,idp->curroff); 589 break; 590 default: /* ISO_FTYPE_DEFAULT || ISO_FTYPE_9660 || ISO_FTYPE_HIGH_SIERRA*/ 591 strcpy(idp->current.d_name,".."); 592 switch (ep->name[0]) { 593 case 0: 594 idp->current.d_namlen = 1; 595 error = iso_uiodir(idp,&idp->current,idp->curroff); 596 break; 597 case 1: 598 idp->current.d_namlen = 2; 599 error = iso_uiodir(idp,&idp->current,idp->curroff); 600 break; 601 default: 602 isofntrans(ep->name,idp->current.d_namlen, 603 idp->current.d_name, &elen, 604 imp->iso_ftype == ISO_FTYPE_9660, 605 isoflags & 4); 606 idp->current.d_namlen = (u_char)elen; 607 if (imp->iso_ftype == ISO_FTYPE_DEFAULT) 608 error = iso_shipdir(idp); 609 else 610 error = iso_uiodir(idp,&idp->current,idp->curroff); 611 break; 612 } 613 } 614 if (error) 615 break; 616 617 entryoffsetinblock += reclen; 618 } 619 620 if (!error && imp->iso_ftype == ISO_FTYPE_DEFAULT) { 621 idp->current.d_namlen = 0; 622 error = iso_shipdir(idp); 623 } 624 if (error < 0) 625 error = 0; 626 627 if (ap->a_ncookies != NULL) { 628 if (error) 629 FREE(cookies, M_TEMP); 630 else { 631 /* 632 * Work out the number of cookies actually used. 633 */ 634 *ap->a_ncookies = ncookies - idp->ncookies; 635 *ap->a_cookies = cookies; 636 } 637 } 638 639 if (bp) 640 brelse (bp); 641 642 uio->uio_offset = idp->uio_off; 643 if (ap->a_eofflag) 644 *ap->a_eofflag = idp->eof; 645 646 FREE(idp,M_TEMP); 647 648 return (error); 649} 650 651/* 652 * Return target name of a symbolic link 653 * Shouldn't we get the parent vnode and read the data from there? 654 * This could eventually result in deadlocks in cd9660_lookup. 655 * But otherwise the block read here is in the block buffer two times. 656 */ 657typedef struct iso_directory_record ISODIR; 658typedef struct iso_node ISONODE; 659typedef struct iso_mnt ISOMNT; 660int 661cd9660_readlink(ap) 662 struct vop_readlink_args /* { 663 struct vnode *a_vp; 664 struct uio *a_uio; 665 struct ucred *a_cred; 666 } */ *ap; 667{ 668 ISONODE *ip; 669 ISODIR *dirp; 670 ISOMNT *imp; 671 struct buf *bp; 672 u_short symlen; 673 int error; 674 char *symname; 675 676 ip = VTOI(ap->a_vp); 677 imp = ip->i_mnt; 678 679 if (imp->iso_ftype != ISO_FTYPE_RRIP) 680 return EINVAL; 681 682 /* 683 * Get parents directory record block that this inode included. 684 */ 685 error = bread(imp->im_devvp, 686 iso_dblkno(imp, ip->i_number), 687 imp->logical_block_size, 688 NOCRED, 689 &bp); 690 if (error) { 691 brelse(bp); 692 return EINVAL; 693 } 694 695 /* 696 * Setup the directory pointer for this inode 697 */ 698 dirp = (ISODIR *)(bp->b_un.b_addr + (ip->i_number & imp->im_bmask)); 699#ifdef DEBUG 700 printf("lbn=%d,off=%d,bsize=%d,DEV_BSIZE=%d, dirp= %08x, b_addr=%08x, offset=%08x(%08x)\n", 701 (daddr_t)(ip->i_number >> imp->im_bshift), 702 ip->i_number & imp->im_bmask, 703 imp->logical_block_size, 704 DEV_BSIZE, 705 dirp, 706 bp->b_un.b_addr, 707 ip->i_number, 708 ip->i_number & imp->im_bmask ); 709#endif 710 711 /* 712 * Just make sure, we have a right one.... 713 * 1: Check not cross boundary on block 714 */ 715 if ((ip->i_number & imp->im_bmask) + isonum_711(dirp->length) 716 > imp->logical_block_size) { 717 brelse(bp); 718 return EINVAL; 719 } 720 721 /* 722 * Now get a buffer 723 * Abuse a namei buffer for now. 724 */ 725 MALLOC(symname,char *,MAXPATHLEN,M_NAMEI,M_WAITOK); 726 727 /* 728 * Ok, we just gathering a symbolic name in SL record. 729 */ 730 if (cd9660_rrip_getsymname(dirp,symname,&symlen,imp) == 0) { 731 FREE(symname,M_NAMEI); 732 brelse(bp); 733 return EINVAL; 734 } 735 /* 736 * Don't forget before you leave from home ;-) 737 */ 738 brelse(bp); 739 740 /* 741 * return with the symbolic name to caller's. 742 */ 743 error = uiomove(symname,symlen,ap->a_uio); 744 745 FREE(symname,M_NAMEI); 746 747 return error; 748} 749 750/* 751 * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually 752 * done. If a buffer has been saved in anticipation of a CREATE, delete it. 753 */ 754int 755cd9660_abortop(ap) 756 struct vop_abortop_args /* { 757 struct vnode *a_dvp; 758 struct componentname *a_cnp; 759 } */ *ap; 760{ 761 if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) 762 FREE(ap->a_cnp->cn_pnbuf, M_NAMEI); 763 return 0; 764} 765 766/* 767 * Lock an inode. 768 */ 769int 770cd9660_lock(ap) 771 struct vop_lock_args /* { 772 struct vnode *a_vp; 773 } */ *ap; 774{ 775 register struct iso_node *ip = VTOI(ap->a_vp); 776 777 ISO_ILOCK(ip); 778 return 0; 779} 780 781/* 782 * Unlock an inode. 783 */ 784int 785cd9660_unlock(ap) 786 struct vop_unlock_args /* { 787 struct vnode *a_vp; 788 } */ *ap; 789{ 790 register struct iso_node *ip = VTOI(ap->a_vp); 791 792 if (!(ip->i_flag & ILOCKED)) 793 panic("cd9660_unlock NOT LOCKED"); 794 ISO_IUNLOCK(ip); 795 return 0; 796} 797 798/* 799 * Check for a locked inode. 800 */ 801int 802cd9660_islocked(ap) 803 struct vop_islocked_args /* { 804 struct vnode *a_vp; 805 } */ *ap; 806{ 807 808 if (VTOI(ap->a_vp)->i_flag & ILOCKED) 809 return 1; 810 return 0; 811} 812 813/* 814 * Calculate the logical to physical mapping if not done already, 815 * then call the device strategy routine. 816 */ 817int 818cd9660_strategy(ap) 819 struct vop_strategy_args /* { 820 struct buf *a_bp; 821 } */ *ap; 822{ 823 register struct buf *bp = ap->a_bp; 824 register struct vnode *vp = bp->b_vp; 825 register struct iso_node *ip; 826 int error; 827 828 ip = VTOI(vp); 829 if (vp->v_type == VBLK || vp->v_type == VCHR) 830 panic("cd9660_strategy: spec"); 831 if (bp->b_blkno == bp->b_lblkno) { 832 if ((error =
|
834 bp->b_error = error; 835 bp->b_flags |= B_ERROR; 836 biodone(bp); 837 return (error); 838 } 839 if ((long)bp->b_blkno == -1) 840 clrbuf(bp); 841 } 842 if ((long)bp->b_blkno == -1) { 843 biodone(bp); 844 return (0); 845 } 846 vp = ip->i_devvp; 847 bp->b_dev = vp->v_rdev; 848 VOCALL (vp->v_op, VOFFSET(vop_strategy), ap); 849 return (0); 850} 851 852/* 853 * Print out the contents of an inode. 854 */ 855int 856cd9660_print(ap) 857 struct vop_print_args /* { 858 struct vnode *a_vp; 859 } */ *ap; 860{ 861 printf("tag VT_ISOFS, isofs vnode\n"); 862 return 0; 863} 864 865/* 866 * Unsupported operation 867 */ 868int 869cd9660_enotsupp() 870{ 871 872 return (EOPNOTSUPP); 873} 874 875/* 876 * Global vfs data structures for isofs 877 */ 878#define cd9660_create \ 879 ((int (*) __P((struct vop_create_args *)))cd9660_enotsupp) 880#define cd9660_mknod ((int (*) __P((struct vop_mknod_args *)))cd9660_enotsupp) 881#define cd9660_setattr \ 882 ((int (*) __P((struct vop_setattr_args *)))cd9660_enotsupp) 883#define cd9660_write ((int (*) __P((struct vop_write_args *)))cd9660_enotsupp) 884#define cd9660_fsync ((int (*) __P((struct vop_fsync_args *)))nullop) 885#define cd9660_remove \ 886 ((int (*) __P((struct vop_remove_args *)))cd9660_enotsupp) 887#define cd9660_link ((int (*) __P((struct vop_link_args *)))cd9660_enotsupp) 888#define cd9660_rename \ 889 ((int (*) __P((struct vop_rename_args *)))cd9660_enotsupp) 890#define cd9660_mkdir ((int (*) __P((struct vop_mkdir_args *)))cd9660_enotsupp) 891#define cd9660_rmdir ((int (*) __P((struct vop_rmdir_args *)))cd9660_enotsupp) 892#define cd9660_symlink \ 893 ((int (*) __P((struct vop_symlink_args *)))cd9660_enotsupp) 894#define cd9660_pathconf \ 895 ((int (*) __P((struct vop_pathconf_args *)))cd9660_enotsupp) 896#define cd9660_advlock \ 897 ((int (*) __P((struct vop_advlock_args *)))cd9660_enotsupp) 898#define cd9660_blkatoff \ 899 ((int (*) __P((struct vop_blkatoff_args *)))cd9660_enotsupp) 900#define cd9660_valloc ((int(*) __P(( \ 901 struct vnode *pvp, \ 902 int mode, \ 903 struct ucred *cred, \ 904 struct vnode **vpp))) cd9660_enotsupp) 905#define cd9660_vfree ((int (*) __P((struct vop_vfree_args *)))cd9660_enotsupp) 906#define cd9660_truncate \ 907 ((int (*) __P((struct vop_truncate_args *)))cd9660_enotsupp) 908#define cd9660_update \ 909 ((int (*) __P((struct vop_update_args *)))cd9660_enotsupp) 910#define cd9660_bwrite \ 911 ((int (*) __P((struct vop_bwrite_args *)))cd9660_enotsupp) 912 913/* 914 * Global vfs data structures for nfs 915 */ 916int (**cd9660_vnodeop_p)(); 917struct vnodeopv_entry_desc cd9660_vnodeop_entries[] = { 918 { &vop_default_desc, vn_default_error }, 919 { &vop_lookup_desc, cd9660_lookup }, /* lookup */ 920 { &vop_create_desc, cd9660_create }, /* create */ 921 { &vop_mknod_desc, cd9660_mknod }, /* mknod */ 922 { &vop_open_desc, cd9660_open }, /* open */ 923 { &vop_close_desc, cd9660_close }, /* close */ 924 { &vop_access_desc, cd9660_access }, /* access */ 925 { &vop_getattr_desc, cd9660_getattr }, /* getattr */ 926 { &vop_setattr_desc, cd9660_setattr }, /* setattr */ 927 { &vop_read_desc, cd9660_read }, /* read */ 928 { &vop_write_desc, cd9660_write }, /* write */ 929 { &vop_ioctl_desc, cd9660_ioctl }, /* ioctl */ 930 { &vop_select_desc, cd9660_select }, /* select */ 931 { &vop_mmap_desc, cd9660_mmap }, /* mmap */ 932 { &vop_fsync_desc, cd9660_fsync }, /* fsync */ 933 { &vop_seek_desc, cd9660_seek }, /* seek */ 934 { &vop_remove_desc, cd9660_remove }, /* remove */ 935 { &vop_link_desc, cd9660_link }, /* link */ 936 { &vop_rename_desc, cd9660_rename }, /* rename */ 937 { &vop_mkdir_desc, cd9660_mkdir }, /* mkdir */ 938 { &vop_rmdir_desc, cd9660_rmdir }, /* rmdir */ 939 { &vop_symlink_desc, cd9660_symlink }, /* symlink */ 940 { &vop_readdir_desc, cd9660_readdir }, /* readdir */ 941 { &vop_readlink_desc, cd9660_readlink },/* readlink */ 942 { &vop_abortop_desc, cd9660_abortop }, /* abortop */ 943 { &vop_inactive_desc, cd9660_inactive },/* inactive */ 944 { &vop_reclaim_desc, cd9660_reclaim }, /* reclaim */ 945 { &vop_lock_desc, cd9660_lock }, /* lock */ 946 { &vop_unlock_desc, cd9660_unlock }, /* unlock */ 947 { &vop_bmap_desc, cd9660_bmap }, /* bmap */ 948 { &vop_strategy_desc, cd9660_strategy },/* strategy */ 949 { &vop_print_desc, cd9660_print }, /* print */ 950 { &vop_islocked_desc, cd9660_islocked },/* islocked */ 951 { &vop_pathconf_desc, cd9660_pathconf },/* pathconf */ 952 { &vop_advlock_desc, cd9660_advlock }, /* advlock */ 953 { &vop_blkatoff_desc, cd9660_blkatoff },/* blkatoff */ 954 { &vop_valloc_desc, cd9660_valloc }, /* valloc */ 955 { &vop_vfree_desc, cd9660_vfree }, /* vfree */ 956 { &vop_truncate_desc, cd9660_truncate },/* truncate */ 957 { &vop_update_desc, cd9660_update }, /* update */ 958 { &vop_bwrite_desc, vn_bwrite }, 959 { (struct vnodeop_desc*)NULL, (int(*)())NULL } 960}; 961struct vnodeopv_desc cd9660_vnodeop_opv_desc = 962 { &cd9660_vnodeop_p, cd9660_vnodeop_entries }; 963VNODEOP_SET(cd9660_vnodeop_opv_desc); 964 965/* 966 * Special device vnode ops 967 */ 968int (**cd9660_specop_p)(); 969struct vnodeopv_entry_desc cd9660_specop_entries[] = { 970 { &vop_default_desc, vn_default_error }, 971 { &vop_lookup_desc, spec_lookup }, /* lookup */ 972 { &vop_create_desc, cd9660_create }, /* create */ 973 { &vop_mknod_desc, cd9660_mknod }, /* mknod */ 974 { &vop_open_desc, spec_open }, /* open */ 975 { &vop_close_desc, spec_close }, /* close */ 976 { &vop_access_desc, cd9660_access }, /* access */ 977 { &vop_getattr_desc, cd9660_getattr }, /* getattr */ 978 { &vop_setattr_desc, cd9660_setattr }, /* setattr */ 979 { &vop_read_desc, spec_read }, /* read */ 980 { &vop_write_desc, spec_write }, /* write */ 981 { &vop_ioctl_desc, spec_ioctl }, /* ioctl */ 982 { &vop_select_desc, spec_select }, /* select */ 983 { &vop_mmap_desc, spec_mmap }, /* mmap */ 984 { &vop_fsync_desc, spec_fsync }, /* fsync */ 985 { &vop_seek_desc, spec_seek }, /* seek */ 986 { &vop_remove_desc, cd9660_remove }, /* remove */ 987 { &vop_link_desc, cd9660_link }, /* link */ 988 { &vop_rename_desc, cd9660_rename }, /* rename */ 989 { &vop_mkdir_desc, cd9660_mkdir }, /* mkdir */ 990 { &vop_rmdir_desc, cd9660_rmdir }, /* rmdir */ 991 { &vop_symlink_desc, cd9660_symlink }, /* symlink */ 992 { &vop_readdir_desc, spec_readdir }, /* readdir */ 993 { &vop_readlink_desc, spec_readlink }, /* readlink */ 994 { &vop_abortop_desc, spec_abortop }, /* abortop */ 995 { &vop_inactive_desc, cd9660_inactive },/* inactive */ 996 { &vop_reclaim_desc, cd9660_reclaim }, /* reclaim */ 997 { &vop_lock_desc, cd9660_lock }, /* lock */ 998 { &vop_unlock_desc, cd9660_unlock }, /* unlock */ 999 { &vop_bmap_desc, spec_bmap }, /* bmap */ 1000 { &vop_strategy_desc, spec_strategy }, /* strategy */ 1001 { &vop_print_desc, cd9660_print }, /* print */ 1002 { &vop_islocked_desc, cd9660_islocked },/* islocked */ 1003 { &vop_pathconf_desc, spec_pathconf }, /* pathconf */ 1004 { &vop_advlock_desc, spec_advlock }, /* advlock */ 1005 { &vop_blkatoff_desc, spec_blkatoff }, /* blkatoff */ 1006 { &vop_valloc_desc, spec_valloc }, /* valloc */ 1007 { &vop_vfree_desc, spec_vfree }, /* vfree */ 1008 { &vop_truncate_desc, spec_truncate }, /* truncate */ 1009 { &vop_update_desc, cd9660_update }, /* update */ 1010 { &vop_bwrite_desc, vn_bwrite }, 1011 { (struct vnodeop_desc*)NULL, (int(*)())NULL } 1012}; 1013struct vnodeopv_desc cd9660_specop_opv_desc = 1014 { &cd9660_specop_p, cd9660_specop_entries }; 1015VNODEOP_SET(cd9660_specop_opv_desc); 1016 1017int (**cd9660_fifoop_p)(); 1018struct vnodeopv_entry_desc cd9660_fifoop_entries[] = { 1019 { &vop_default_desc, vn_default_error }, 1020 { &vop_lookup_desc, fifo_lookup }, /* lookup */ 1021 { &vop_create_desc, cd9660_create }, /* create */ 1022 { &vop_mknod_desc, cd9660_mknod }, /* mknod */ 1023 { &vop_open_desc, fifo_open }, /* open */ 1024 { &vop_close_desc, fifo_close }, /* close */ 1025 { &vop_access_desc, cd9660_access }, /* access */ 1026 { &vop_getattr_desc, cd9660_getattr }, /* getattr */ 1027 { &vop_setattr_desc, cd9660_setattr }, /* setattr */ 1028 { &vop_read_desc, fifo_read }, /* read */ 1029 { &vop_write_desc, fifo_write }, /* write */ 1030 { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */ 1031 { &vop_select_desc, fifo_select }, /* select */ 1032 { &vop_mmap_desc, fifo_mmap }, /* mmap */ 1033 { &vop_fsync_desc, fifo_fsync }, /* fsync */ 1034 { &vop_seek_desc, fifo_seek }, /* seek */ 1035 { &vop_remove_desc, cd9660_remove }, /* remove */ 1036 { &vop_link_desc, cd9660_link }, /* link */ 1037 { &vop_rename_desc, cd9660_rename }, /* rename */ 1038 { &vop_mkdir_desc, cd9660_mkdir }, /* mkdir */ 1039 { &vop_rmdir_desc, cd9660_rmdir }, /* rmdir */ 1040 { &vop_symlink_desc, cd9660_symlink }, /* symlink */ 1041 { &vop_readdir_desc, fifo_readdir }, /* readdir */ 1042 { &vop_readlink_desc, fifo_readlink }, /* readlink */ 1043 { &vop_abortop_desc, fifo_abortop }, /* abortop */ 1044 { &vop_inactive_desc, cd9660_inactive },/* inactive */ 1045 { &vop_reclaim_desc, cd9660_reclaim }, /* reclaim */ 1046 { &vop_lock_desc, cd9660_lock }, /* lock */ 1047 { &vop_unlock_desc, cd9660_unlock }, /* unlock */ 1048 { &vop_bmap_desc, fifo_bmap }, /* bmap */ 1049 { &vop_strategy_desc, fifo_badop }, /* strategy */ 1050 { &vop_print_desc, cd9660_print }, /* print */ 1051 { &vop_islocked_desc, cd9660_islocked },/* islocked */ 1052 { &vop_pathconf_desc, fifo_pathconf }, /* pathconf */ 1053 { &vop_advlock_desc, fifo_advlock }, /* advlock */ 1054 { &vop_blkatoff_desc, fifo_blkatoff }, /* blkatoff */ 1055 { &vop_valloc_desc, fifo_valloc }, /* valloc */ 1056 { &vop_vfree_desc, fifo_vfree }, /* vfree */ 1057 { &vop_truncate_desc, fifo_truncate }, /* truncate */ 1058 { &vop_update_desc, cd9660_update }, /* update */ 1059 { &vop_bwrite_desc, vn_bwrite }, 1060 { (struct vnodeop_desc*)NULL, (int(*)())NULL } 1061}; 1062struct vnodeopv_desc cd9660_fifoop_opv_desc = 1063 { &cd9660_fifoop_p, cd9660_fifoop_entries }; 1064 1065VNODEOP_SET(cd9660_fifoop_opv_desc);
| 834 bp->b_error = error; 835 bp->b_flags |= B_ERROR; 836 biodone(bp); 837 return (error); 838 } 839 if ((long)bp->b_blkno == -1) 840 clrbuf(bp); 841 } 842 if ((long)bp->b_blkno == -1) { 843 biodone(bp); 844 return (0); 845 } 846 vp = ip->i_devvp; 847 bp->b_dev = vp->v_rdev; 848 VOCALL (vp->v_op, VOFFSET(vop_strategy), ap); 849 return (0); 850} 851 852/* 853 * Print out the contents of an inode. 854 */ 855int 856cd9660_print(ap) 857 struct vop_print_args /* { 858 struct vnode *a_vp; 859 } */ *ap; 860{ 861 printf("tag VT_ISOFS, isofs vnode\n"); 862 return 0; 863} 864 865/* 866 * Unsupported operation 867 */ 868int 869cd9660_enotsupp() 870{ 871 872 return (EOPNOTSUPP); 873} 874 875/* 876 * Global vfs data structures for isofs 877 */ 878#define cd9660_create \ 879 ((int (*) __P((struct vop_create_args *)))cd9660_enotsupp) 880#define cd9660_mknod ((int (*) __P((struct vop_mknod_args *)))cd9660_enotsupp) 881#define cd9660_setattr \ 882 ((int (*) __P((struct vop_setattr_args *)))cd9660_enotsupp) 883#define cd9660_write ((int (*) __P((struct vop_write_args *)))cd9660_enotsupp) 884#define cd9660_fsync ((int (*) __P((struct vop_fsync_args *)))nullop) 885#define cd9660_remove \ 886 ((int (*) __P((struct vop_remove_args *)))cd9660_enotsupp) 887#define cd9660_link ((int (*) __P((struct vop_link_args *)))cd9660_enotsupp) 888#define cd9660_rename \ 889 ((int (*) __P((struct vop_rename_args *)))cd9660_enotsupp) 890#define cd9660_mkdir ((int (*) __P((struct vop_mkdir_args *)))cd9660_enotsupp) 891#define cd9660_rmdir ((int (*) __P((struct vop_rmdir_args *)))cd9660_enotsupp) 892#define cd9660_symlink \ 893 ((int (*) __P((struct vop_symlink_args *)))cd9660_enotsupp) 894#define cd9660_pathconf \ 895 ((int (*) __P((struct vop_pathconf_args *)))cd9660_enotsupp) 896#define cd9660_advlock \ 897 ((int (*) __P((struct vop_advlock_args *)))cd9660_enotsupp) 898#define cd9660_blkatoff \ 899 ((int (*) __P((struct vop_blkatoff_args *)))cd9660_enotsupp) 900#define cd9660_valloc ((int(*) __P(( \ 901 struct vnode *pvp, \ 902 int mode, \ 903 struct ucred *cred, \ 904 struct vnode **vpp))) cd9660_enotsupp) 905#define cd9660_vfree ((int (*) __P((struct vop_vfree_args *)))cd9660_enotsupp) 906#define cd9660_truncate \ 907 ((int (*) __P((struct vop_truncate_args *)))cd9660_enotsupp) 908#define cd9660_update \ 909 ((int (*) __P((struct vop_update_args *)))cd9660_enotsupp) 910#define cd9660_bwrite \ 911 ((int (*) __P((struct vop_bwrite_args *)))cd9660_enotsupp) 912 913/* 914 * Global vfs data structures for nfs 915 */ 916int (**cd9660_vnodeop_p)(); 917struct vnodeopv_entry_desc cd9660_vnodeop_entries[] = { 918 { &vop_default_desc, vn_default_error }, 919 { &vop_lookup_desc, cd9660_lookup }, /* lookup */ 920 { &vop_create_desc, cd9660_create }, /* create */ 921 { &vop_mknod_desc, cd9660_mknod }, /* mknod */ 922 { &vop_open_desc, cd9660_open }, /* open */ 923 { &vop_close_desc, cd9660_close }, /* close */ 924 { &vop_access_desc, cd9660_access }, /* access */ 925 { &vop_getattr_desc, cd9660_getattr }, /* getattr */ 926 { &vop_setattr_desc, cd9660_setattr }, /* setattr */ 927 { &vop_read_desc, cd9660_read }, /* read */ 928 { &vop_write_desc, cd9660_write }, /* write */ 929 { &vop_ioctl_desc, cd9660_ioctl }, /* ioctl */ 930 { &vop_select_desc, cd9660_select }, /* select */ 931 { &vop_mmap_desc, cd9660_mmap }, /* mmap */ 932 { &vop_fsync_desc, cd9660_fsync }, /* fsync */ 933 { &vop_seek_desc, cd9660_seek }, /* seek */ 934 { &vop_remove_desc, cd9660_remove }, /* remove */ 935 { &vop_link_desc, cd9660_link }, /* link */ 936 { &vop_rename_desc, cd9660_rename }, /* rename */ 937 { &vop_mkdir_desc, cd9660_mkdir }, /* mkdir */ 938 { &vop_rmdir_desc, cd9660_rmdir }, /* rmdir */ 939 { &vop_symlink_desc, cd9660_symlink }, /* symlink */ 940 { &vop_readdir_desc, cd9660_readdir }, /* readdir */ 941 { &vop_readlink_desc, cd9660_readlink },/* readlink */ 942 { &vop_abortop_desc, cd9660_abortop }, /* abortop */ 943 { &vop_inactive_desc, cd9660_inactive },/* inactive */ 944 { &vop_reclaim_desc, cd9660_reclaim }, /* reclaim */ 945 { &vop_lock_desc, cd9660_lock }, /* lock */ 946 { &vop_unlock_desc, cd9660_unlock }, /* unlock */ 947 { &vop_bmap_desc, cd9660_bmap }, /* bmap */ 948 { &vop_strategy_desc, cd9660_strategy },/* strategy */ 949 { &vop_print_desc, cd9660_print }, /* print */ 950 { &vop_islocked_desc, cd9660_islocked },/* islocked */ 951 { &vop_pathconf_desc, cd9660_pathconf },/* pathconf */ 952 { &vop_advlock_desc, cd9660_advlock }, /* advlock */ 953 { &vop_blkatoff_desc, cd9660_blkatoff },/* blkatoff */ 954 { &vop_valloc_desc, cd9660_valloc }, /* valloc */ 955 { &vop_vfree_desc, cd9660_vfree }, /* vfree */ 956 { &vop_truncate_desc, cd9660_truncate },/* truncate */ 957 { &vop_update_desc, cd9660_update }, /* update */ 958 { &vop_bwrite_desc, vn_bwrite }, 959 { (struct vnodeop_desc*)NULL, (int(*)())NULL } 960}; 961struct vnodeopv_desc cd9660_vnodeop_opv_desc = 962 { &cd9660_vnodeop_p, cd9660_vnodeop_entries }; 963VNODEOP_SET(cd9660_vnodeop_opv_desc); 964 965/* 966 * Special device vnode ops 967 */ 968int (**cd9660_specop_p)(); 969struct vnodeopv_entry_desc cd9660_specop_entries[] = { 970 { &vop_default_desc, vn_default_error }, 971 { &vop_lookup_desc, spec_lookup }, /* lookup */ 972 { &vop_create_desc, cd9660_create }, /* create */ 973 { &vop_mknod_desc, cd9660_mknod }, /* mknod */ 974 { &vop_open_desc, spec_open }, /* open */ 975 { &vop_close_desc, spec_close }, /* close */ 976 { &vop_access_desc, cd9660_access }, /* access */ 977 { &vop_getattr_desc, cd9660_getattr }, /* getattr */ 978 { &vop_setattr_desc, cd9660_setattr }, /* setattr */ 979 { &vop_read_desc, spec_read }, /* read */ 980 { &vop_write_desc, spec_write }, /* write */ 981 { &vop_ioctl_desc, spec_ioctl }, /* ioctl */ 982 { &vop_select_desc, spec_select }, /* select */ 983 { &vop_mmap_desc, spec_mmap }, /* mmap */ 984 { &vop_fsync_desc, spec_fsync }, /* fsync */ 985 { &vop_seek_desc, spec_seek }, /* seek */ 986 { &vop_remove_desc, cd9660_remove }, /* remove */ 987 { &vop_link_desc, cd9660_link }, /* link */ 988 { &vop_rename_desc, cd9660_rename }, /* rename */ 989 { &vop_mkdir_desc, cd9660_mkdir }, /* mkdir */ 990 { &vop_rmdir_desc, cd9660_rmdir }, /* rmdir */ 991 { &vop_symlink_desc, cd9660_symlink }, /* symlink */ 992 { &vop_readdir_desc, spec_readdir }, /* readdir */ 993 { &vop_readlink_desc, spec_readlink }, /* readlink */ 994 { &vop_abortop_desc, spec_abortop }, /* abortop */ 995 { &vop_inactive_desc, cd9660_inactive },/* inactive */ 996 { &vop_reclaim_desc, cd9660_reclaim }, /* reclaim */ 997 { &vop_lock_desc, cd9660_lock }, /* lock */ 998 { &vop_unlock_desc, cd9660_unlock }, /* unlock */ 999 { &vop_bmap_desc, spec_bmap }, /* bmap */ 1000 { &vop_strategy_desc, spec_strategy }, /* strategy */ 1001 { &vop_print_desc, cd9660_print }, /* print */ 1002 { &vop_islocked_desc, cd9660_islocked },/* islocked */ 1003 { &vop_pathconf_desc, spec_pathconf }, /* pathconf */ 1004 { &vop_advlock_desc, spec_advlock }, /* advlock */ 1005 { &vop_blkatoff_desc, spec_blkatoff }, /* blkatoff */ 1006 { &vop_valloc_desc, spec_valloc }, /* valloc */ 1007 { &vop_vfree_desc, spec_vfree }, /* vfree */ 1008 { &vop_truncate_desc, spec_truncate }, /* truncate */ 1009 { &vop_update_desc, cd9660_update }, /* update */ 1010 { &vop_bwrite_desc, vn_bwrite }, 1011 { (struct vnodeop_desc*)NULL, (int(*)())NULL } 1012}; 1013struct vnodeopv_desc cd9660_specop_opv_desc = 1014 { &cd9660_specop_p, cd9660_specop_entries }; 1015VNODEOP_SET(cd9660_specop_opv_desc); 1016 1017int (**cd9660_fifoop_p)(); 1018struct vnodeopv_entry_desc cd9660_fifoop_entries[] = { 1019 { &vop_default_desc, vn_default_error }, 1020 { &vop_lookup_desc, fifo_lookup }, /* lookup */ 1021 { &vop_create_desc, cd9660_create }, /* create */ 1022 { &vop_mknod_desc, cd9660_mknod }, /* mknod */ 1023 { &vop_open_desc, fifo_open }, /* open */ 1024 { &vop_close_desc, fifo_close }, /* close */ 1025 { &vop_access_desc, cd9660_access }, /* access */ 1026 { &vop_getattr_desc, cd9660_getattr }, /* getattr */ 1027 { &vop_setattr_desc, cd9660_setattr }, /* setattr */ 1028 { &vop_read_desc, fifo_read }, /* read */ 1029 { &vop_write_desc, fifo_write }, /* write */ 1030 { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */ 1031 { &vop_select_desc, fifo_select }, /* select */ 1032 { &vop_mmap_desc, fifo_mmap }, /* mmap */ 1033 { &vop_fsync_desc, fifo_fsync }, /* fsync */ 1034 { &vop_seek_desc, fifo_seek }, /* seek */ 1035 { &vop_remove_desc, cd9660_remove }, /* remove */ 1036 { &vop_link_desc, cd9660_link }, /* link */ 1037 { &vop_rename_desc, cd9660_rename }, /* rename */ 1038 { &vop_mkdir_desc, cd9660_mkdir }, /* mkdir */ 1039 { &vop_rmdir_desc, cd9660_rmdir }, /* rmdir */ 1040 { &vop_symlink_desc, cd9660_symlink }, /* symlink */ 1041 { &vop_readdir_desc, fifo_readdir }, /* readdir */ 1042 { &vop_readlink_desc, fifo_readlink }, /* readlink */ 1043 { &vop_abortop_desc, fifo_abortop }, /* abortop */ 1044 { &vop_inactive_desc, cd9660_inactive },/* inactive */ 1045 { &vop_reclaim_desc, cd9660_reclaim }, /* reclaim */ 1046 { &vop_lock_desc, cd9660_lock }, /* lock */ 1047 { &vop_unlock_desc, cd9660_unlock }, /* unlock */ 1048 { &vop_bmap_desc, fifo_bmap }, /* bmap */ 1049 { &vop_strategy_desc, fifo_badop }, /* strategy */ 1050 { &vop_print_desc, cd9660_print }, /* print */ 1051 { &vop_islocked_desc, cd9660_islocked },/* islocked */ 1052 { &vop_pathconf_desc, fifo_pathconf }, /* pathconf */ 1053 { &vop_advlock_desc, fifo_advlock }, /* advlock */ 1054 { &vop_blkatoff_desc, fifo_blkatoff }, /* blkatoff */ 1055 { &vop_valloc_desc, fifo_valloc }, /* valloc */ 1056 { &vop_vfree_desc, fifo_vfree }, /* vfree */ 1057 { &vop_truncate_desc, fifo_truncate }, /* truncate */ 1058 { &vop_update_desc, cd9660_update }, /* update */ 1059 { &vop_bwrite_desc, vn_bwrite }, 1060 { (struct vnodeop_desc*)NULL, (int(*)())NULL } 1061}; 1062struct vnodeopv_desc cd9660_fifoop_opv_desc = 1063 { &cd9660_fifoop_p, cd9660_fifoop_entries }; 1064 1065VNODEOP_SET(cd9660_fifoop_opv_desc);
|