1 /*- 2 * Copyright (c) 1994 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley 6 * by Pace Willisson (pace@blitz.com). The Rock Ridge Extension 7 * Support code is derived from software contributed to Berkeley 8 * by Atsushi Murai (amurai@spec.co.jp). 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 * 38 * @(#)cd9660_vnops.c 8.19 (Berkeley) 5/27/95 39 * $Id: cd9660_vnops.c,v 1.39 1997/09/21 04:22:40 dyson Exp $ 40 */ 41 42 #include <sys/param.h> 43 #include <sys/systm.h> 44 #include <sys/namei.h> 45 #include <sys/kernel.h> 46 #include <sys/stat.h> 47 #include <sys/sysctl.h> 48 #include <sys/buf.h> 49 #include <sys/mount.h> 50 #include <sys/vnode.h> 51 #include <miscfs/specfs/specdev.h> 52 #include <miscfs/fifofs/fifo.h> 53 #include <sys/malloc.h> 54 #include <sys/dirent.h> 55 #include <sys/unistd.h> 56 57 #include <isofs/cd9660/iso.h> 58 #include <isofs/cd9660/cd9660_node.h> 59 #include <isofs/cd9660/iso_rrip.h> 60 61 static int cd9660_setattr __P((struct vop_setattr_args *)); 62 static int cd9660_open __P((struct vop_open_args *)); 63 static int cd9660_close __P((struct vop_close_args *)); 64 static int cd9660_access __P((struct vop_access_args *)); 65 static int cd9660_getattr __P((struct vop_getattr_args *)); 66 static int cd9660_read __P((struct vop_read_args *)); 67 static int cd9660_ioctl __P((struct vop_ioctl_args *)); 68 static int cd9660_mmap __P((struct vop_mmap_args *)); 69 static int cd9660_seek __P((struct vop_seek_args *)); 70 struct isoreaddir; 71 static int iso_uiodir __P((struct isoreaddir *idp, struct dirent *dp, 72 off_t off)); 73 static int iso_shipdir __P((struct isoreaddir *idp)); 74 static int cd9660_readdir __P((struct vop_readdir_args *)); 75 static int cd9660_readlink __P((struct vop_readlink_args *ap)); 76 static int cd9660_abortop __P((struct vop_abortop_args *)); 77 static int cd9660_lock __P((struct vop_lock_args *)); 78 static int cd9660_unlock __P((struct vop_unlock_args *)); 79 static int cd9660_strategy __P((struct vop_strategy_args *)); 80 static int cd9660_print __P((struct vop_print_args *)); 81 static int cd9660_islocked __P((struct vop_islocked_args *)); 82 83 /* 84 * Setattr call. Only allowed for block and character special devices. 85 */ 86 int 87 cd9660_setattr(ap) 88 struct vop_setattr_args /* { 89 struct vnodeop_desc *a_desc; 90 struct vnode *a_vp; 91 struct vattr *a_vap; 92 struct ucred *a_cred; 93 struct proc *a_p; 94 } */ *ap; 95 { 96 struct vnode *vp = ap->a_vp; 97 struct vattr *vap = ap->a_vap; 98 99 if (vap->va_flags != (u_long)VNOVAL || vap->va_uid != (uid_t)VNOVAL || 100 vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL || 101 vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL) 102 return (EROFS); 103 if (vap->va_size != (u_quad_t)VNOVAL) { 104 switch (vp->v_type) { 105 case VDIR: 106 return (EISDIR); 107 case VLNK: 108 case VREG: 109 return (EROFS); 110 case VCHR: 111 case VBLK: 112 case VSOCK: 113 case VFIFO: 114 return (0); 115 } 116 } 117 return (0); 118 } 119 120 /* 121 * Open called. 122 * 123 * Nothing to do. 124 */ 125 /* ARGSUSED */ 126 static int 127 cd9660_open(ap) 128 struct vop_open_args /* { 129 struct vnode *a_vp; 130 int a_mode; 131 struct ucred *a_cred; 132 struct proc *a_p; 133 } */ *ap; 134 { 135 return (0); 136 } 137 138 /* 139 * Close called 140 * 141 * Update the times on the inode on writeable file systems. 142 */ 143 /* ARGSUSED */ 144 static int 145 cd9660_close(ap) 146 struct vop_close_args /* { 147 struct vnode *a_vp; 148 int a_fflag; 149 struct ucred *a_cred; 150 struct proc *a_p; 151 } */ *ap; 152 { 153 return (0); 154 } 155 156 /* 157 * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC. 158 * The mode is shifted to select the owner/group/other fields. The 159 * super user is granted all permissions. 160 */ 161 /* ARGSUSED */ 162 static int 163 cd9660_access(ap) 164 struct vop_access_args /* { 165 struct vnode *a_vp; 166 int a_mode; 167 struct ucred *a_cred; 168 struct proc *a_p; 169 } */ *ap; 170 { 171 struct vnode *vp = ap->a_vp; 172 struct iso_node *ip = VTOI(vp); 173 struct ucred *cred = ap->a_cred; 174 mode_t mask, mode = ap->a_mode; 175 gid_t *gp; 176 int i; 177 178 /* 179 * Disallow write attempts unless the file is a socket, 180 * fifo, or a block or character device resident on the 181 * file system. 182 */ 183 if (mode & VWRITE) { 184 switch (vp->v_type) { 185 case VDIR: 186 case VLNK: 187 case VREG: 188 return (EROFS); 189 } 190 } 191 192 /* User id 0 always gets access. */ 193 if (cred->cr_uid == 0) 194 return (0); 195 196 mask = 0; 197 198 /* Otherwise, check the owner. */ 199 if (cred->cr_uid == ip->inode.iso_uid) { 200 if (mode & VEXEC) 201 mask |= S_IXUSR; 202 if (mode & VREAD) 203 mask |= S_IRUSR; 204 if (mode & VWRITE) 205 mask |= S_IWUSR; 206 return ((ip->inode.iso_mode & mask) == mask ? 0 : EACCES); 207 } 208 209 /* Otherwise, check the groups. */ 210 for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++) 211 if (ip->inode.iso_gid == *gp) { 212 if (mode & VEXEC) 213 mask |= S_IXGRP; 214 if (mode & VREAD) 215 mask |= S_IRGRP; 216 if (mode & VWRITE) 217 mask |= S_IWGRP; 218 return ((ip->inode.iso_mode & mask) == mask ? 219 0 : EACCES); 220 } 221 222 /* Otherwise, check everyone else. */ 223 if (mode & VEXEC) 224 mask |= S_IXOTH; 225 if (mode & VREAD) 226 mask |= S_IROTH; 227 if (mode & VWRITE) 228 mask |= S_IWOTH; 229 return ((ip->inode.iso_mode & mask) == mask ? 0 : EACCES); 230 } 231 232 static int 233 cd9660_getattr(ap) 234 struct vop_getattr_args /* { 235 struct vnode *a_vp; 236 struct vattr *a_vap; 237 struct ucred *a_cred; 238 struct proc *a_p; 239 } */ *ap; 240 241 { 242 struct vnode *vp = ap->a_vp; 243 register struct vattr *vap = ap->a_vap; 244 register struct iso_node *ip = VTOI(vp); 245 246 vap->va_fsid = ip->i_dev; 247 vap->va_fileid = ip->i_number; 248 249 vap->va_mode = ip->inode.iso_mode; 250 vap->va_nlink = ip->inode.iso_links; 251 vap->va_uid = ip->inode.iso_uid; 252 vap->va_gid = ip->inode.iso_gid; 253 vap->va_atime = ip->inode.iso_atime; 254 vap->va_mtime = ip->inode.iso_mtime; 255 vap->va_ctime = ip->inode.iso_ctime; 256 vap->va_rdev = ip->inode.iso_rdev; 257 258 vap->va_size = (u_quad_t) ip->i_size; 259 if (ip->i_size == 0 && (vap->va_mode & S_IFMT) == S_IFLNK) { 260 struct vop_readlink_args rdlnk; 261 struct iovec aiov; 262 struct uio auio; 263 char *cp; 264 265 MALLOC(cp, char *, MAXPATHLEN, M_TEMP, M_WAITOK); 266 aiov.iov_base = cp; 267 aiov.iov_len = MAXPATHLEN; 268 auio.uio_iov = &aiov; 269 auio.uio_iovcnt = 1; 270 auio.uio_offset = 0; 271 auio.uio_rw = UIO_READ; 272 auio.uio_segflg = UIO_SYSSPACE; 273 auio.uio_procp = ap->a_p; 274 auio.uio_resid = MAXPATHLEN; 275 rdlnk.a_uio = &auio; 276 rdlnk.a_vp = ap->a_vp; 277 rdlnk.a_cred = ap->a_cred; 278 if (cd9660_readlink(&rdlnk) == 0) 279 vap->va_size = MAXPATHLEN - auio.uio_resid; 280 FREE(cp, M_TEMP); 281 } 282 vap->va_flags = 0; 283 vap->va_gen = 1; 284 vap->va_blocksize = ip->i_mnt->logical_block_size; 285 vap->va_bytes = (u_quad_t) ip->i_size; 286 vap->va_type = vp->v_type; 287 vap->va_filerev = 0; 288 return (0); 289 } 290 291 /* 292 * Vnode op for reading. 293 */ 294 static int 295 cd9660_read(ap) 296 struct vop_read_args /* { 297 struct vnode *a_vp; 298 struct uio *a_uio; 299 int a_ioflag; 300 struct ucred *a_cred; 301 } */ *ap; 302 { 303 struct vnode *vp = ap->a_vp; 304 register struct uio *uio = ap->a_uio; 305 register struct iso_node *ip = VTOI(vp); 306 register struct iso_mnt *imp; 307 struct buf *bp; 308 daddr_t lbn, rablock; 309 off_t diff; 310 int rasize, error = 0; 311 long size, n, on; 312 313 if (uio->uio_resid == 0) 314 return (0); 315 if (uio->uio_offset < 0) 316 return (EINVAL); 317 ip->i_flag |= IN_ACCESS; 318 imp = ip->i_mnt; 319 do { 320 lbn = lblkno(imp, uio->uio_offset); 321 on = blkoff(imp, uio->uio_offset); 322 n = min((u_int)(imp->logical_block_size - on), 323 uio->uio_resid); 324 diff = (off_t)ip->i_size - uio->uio_offset; 325 if (diff <= 0) 326 return (0); 327 if (diff < n) 328 n = diff; 329 size = blksize(imp, ip, lbn); 330 rablock = lbn + 1; 331 if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) { 332 if (lblktosize(imp, rablock) <= ip->i_size) 333 error = cluster_read(vp, (off_t)ip->i_size, 334 lbn, size, NOCRED, uio->uio_resid, 335 (ap->a_ioflag >> 16), &bp); 336 else 337 error = bread(vp, lbn, size, NOCRED, &bp); 338 } else { 339 if (vp->v_lastr + 1 == lbn && 340 lblktosize(imp, rablock) < ip->i_size) { 341 rasize = blksize(imp, ip, rablock); 342 error = breadn(vp, lbn, size, &rablock, 343 &rasize, 1, NOCRED, &bp); 344 } else 345 error = bread(vp, lbn, size, NOCRED, &bp); 346 } 347 vp->v_lastr = lbn; 348 n = min(n, size - bp->b_resid); 349 if (error) { 350 brelse(bp); 351 return (error); 352 } 353 354 error = uiomove(bp->b_data + on, (int)n, uio); 355 brelse(bp); 356 } while (error == 0 && uio->uio_resid > 0 && n != 0); 357 return (error); 358 } 359 360 /* ARGSUSED */ 361 static int 362 cd9660_ioctl(ap) 363 struct vop_ioctl_args /* { 364 struct vnode *a_vp; 365 u_long a_command; 366 caddr_t a_data; 367 int a_fflag; 368 struct ucred *a_cred; 369 struct proc *a_p; 370 } */ *ap; 371 { 372 printf("You did ioctl for isofs !!\n"); 373 return (ENOTTY); 374 } 375 376 /* 377 * Mmap a file 378 * 379 * NB Currently unsupported. 380 */ 381 /* ARGSUSED */ 382 static int 383 cd9660_mmap(ap) 384 struct vop_mmap_args /* { 385 struct vnode *a_vp; 386 int a_fflags; 387 struct ucred *a_cred; 388 struct proc *a_p; 389 } */ *ap; 390 { 391 392 return (EINVAL); 393 } 394 395 /* 396 * Seek on a file 397 * 398 * Nothing to do, so just return. 399 */ 400 /* ARGSUSED */ 401 static int 402 cd9660_seek(ap) 403 struct vop_seek_args /* { 404 struct vnode *a_vp; 405 off_t a_oldoff; 406 off_t a_newoff; 407 struct ucred *a_cred; 408 } */ *ap; 409 { 410 411 return (0); 412 } 413 414 /* 415 * Structure for reading directories 416 */ 417 struct isoreaddir { 418 struct dirent saveent; 419 struct dirent assocent; 420 struct dirent current; 421 off_t saveoff; 422 off_t assocoff; 423 off_t curroff; 424 struct uio *uio; 425 off_t uio_off; 426 int eofflag; 427 u_long *cookies; 428 int ncookies; 429 }; 430 431 int 432 iso_uiodir(idp,dp,off) 433 struct isoreaddir *idp; 434 struct dirent *dp; 435 off_t off; 436 { 437 int error; 438 439 dp->d_name[dp->d_namlen] = 0; 440 dp->d_reclen = GENERIC_DIRSIZ(dp); 441 442 if (idp->uio->uio_resid < dp->d_reclen) { 443 idp->eofflag = 0; 444 return (-1); 445 } 446 447 if (idp->cookies) { 448 if (idp->ncookies <= 0) { 449 idp->eofflag = 0; 450 return (-1); 451 } 452 453 *idp->cookies++ = off; 454 --idp->ncookies; 455 } 456 457 if (error = uiomove((caddr_t) dp,dp->d_reclen,idp->uio)) 458 return (error); 459 idp->uio_off = off; 460 return (0); 461 } 462 463 int 464 iso_shipdir(idp) 465 struct isoreaddir *idp; 466 { 467 struct dirent *dp; 468 int cl, sl, assoc; 469 int error; 470 char *cname, *sname; 471 472 cl = idp->current.d_namlen; 473 cname = idp->current.d_name; 474 assoc = (cl > 1) && (*cname == ASSOCCHAR); 475 if (assoc) { 476 cl--; 477 cname++; 478 } 479 480 dp = &idp->saveent; 481 sname = dp->d_name; 482 if (!(sl = dp->d_namlen)) { 483 dp = &idp->assocent; 484 sname = dp->d_name + 1; 485 sl = dp->d_namlen - 1; 486 } 487 if (sl > 0) { 488 if (sl != cl 489 || bcmp(sname,cname,sl)) { 490 if (idp->assocent.d_namlen) { 491 if (error = iso_uiodir(idp,&idp->assocent,idp->assocoff)) 492 return (error); 493 idp->assocent.d_namlen = 0; 494 } 495 if (idp->saveent.d_namlen) { 496 if (error = iso_uiodir(idp,&idp->saveent,idp->saveoff)) 497 return (error); 498 idp->saveent.d_namlen = 0; 499 } 500 } 501 } 502 idp->current.d_reclen = GENERIC_DIRSIZ(&idp->current); 503 if (assoc) { 504 idp->assocoff = idp->curroff; 505 bcopy(&idp->current,&idp->assocent,idp->current.d_reclen); 506 } else { 507 idp->saveoff = idp->curroff; 508 bcopy(&idp->current,&idp->saveent,idp->current.d_reclen); 509 } 510 return (0); 511 } 512 513 /* 514 * Vnode op for readdir 515 */ 516 static int 517 cd9660_readdir(ap) 518 struct vop_readdir_args /* { 519 struct vnode *a_vp; 520 struct uio *a_uio; 521 struct ucred *a_cred; 522 int *a_eofflag; 523 int *a_ncookies; 524 u_long *a_cookies; 525 } */ *ap; 526 { 527 register struct uio *uio = ap->a_uio; 528 struct isoreaddir *idp; 529 struct vnode *vdp = ap->a_vp; 530 struct iso_node *dp; 531 struct iso_mnt *imp; 532 struct buf *bp = NULL; 533 struct iso_directory_record *ep; 534 int entryoffsetinblock; 535 doff_t endsearch; 536 u_long bmask; 537 int error = 0; 538 int reclen; 539 u_short namelen; 540 int ncookies = 0; 541 u_long *cookies = NULL; 542 543 dp = VTOI(vdp); 544 imp = dp->i_mnt; 545 bmask = imp->im_bmask; 546 547 MALLOC(idp, struct isoreaddir *, sizeof(*idp), M_TEMP, M_WAITOK); 548 idp->saveent.d_namlen = idp->assocent.d_namlen = 0; 549 /* 550 * XXX 551 * Is it worth trying to figure out the type? 552 */ 553 idp->saveent.d_type = idp->assocent.d_type = idp->current.d_type = 554 DT_UNKNOWN; 555 idp->uio = uio; 556 if (ap->a_ncookies == NULL) { 557 idp->cookies = NULL; 558 } else { 559 /* 560 * Guess the number of cookies needed. 561 */ 562 ncookies = uio->uio_resid / 16; 563 MALLOC(cookies, u_long *, ncookies * sizeof(u_int), M_TEMP, 564 M_WAITOK); 565 idp->cookies = cookies; 566 idp->ncookies = ncookies; 567 } 568 idp->eofflag = 1; 569 idp->curroff = uio->uio_offset; 570 571 if ((entryoffsetinblock = idp->curroff & bmask) && 572 (error = VOP_BLKATOFF(vdp, (off_t)idp->curroff, NULL, &bp))) { 573 FREE(idp, M_TEMP); 574 return (error); 575 } 576 endsearch = dp->i_size; 577 578 while (idp->curroff < endsearch) { 579 /* 580 * If offset is on a block boundary, 581 * read the next directory block. 582 * Release previous if it exists. 583 */ 584 if ((idp->curroff & bmask) == 0) { 585 if (bp != NULL) 586 brelse(bp); 587 if (error = 588 VOP_BLKATOFF(vdp, (off_t)idp->curroff, NULL, &bp)) 589 break; 590 entryoffsetinblock = 0; 591 } 592 /* 593 * Get pointer to next entry. 594 */ 595 ep = (struct iso_directory_record *) 596 ((char *)bp->b_data + entryoffsetinblock); 597 598 reclen = isonum_711(ep->length); 599 if (reclen == 0) { 600 /* skip to next block, if any */ 601 idp->curroff = 602 (idp->curroff & ~bmask) + imp->logical_block_size; 603 continue; 604 } 605 606 if (reclen < ISO_DIRECTORY_RECORD_SIZE) { 607 error = EINVAL; 608 /* illegal entry, stop */ 609 break; 610 } 611 612 if (entryoffsetinblock + reclen > imp->logical_block_size) { 613 error = EINVAL; 614 /* illegal directory, so stop looking */ 615 break; 616 } 617 618 idp->current.d_namlen = isonum_711(ep->name_len); 619 620 if (reclen < ISO_DIRECTORY_RECORD_SIZE + idp->current.d_namlen) { 621 error = EINVAL; 622 /* illegal entry, stop */ 623 break; 624 } 625 626 if (isonum_711(ep->flags)&2) 627 idp->current.d_fileno = isodirino(ep, imp); 628 else 629 idp->current.d_fileno = dbtob(bp->b_blkno) + 630 entryoffsetinblock; 631 632 idp->curroff += reclen; 633 634 switch (imp->iso_ftype) { 635 case ISO_FTYPE_RRIP: 636 cd9660_rrip_getname(ep,idp->current.d_name, &namelen, 637 &idp->current.d_fileno,imp); 638 idp->current.d_namlen = (u_char)namelen; 639 if (idp->current.d_namlen) 640 error = iso_uiodir(idp,&idp->current,idp->curroff); 641 break; 642 default: /* ISO_FTYPE_DEFAULT || ISO_FTYPE_9660 || ISO_FTYPE_HIGH_SIERRA*/ 643 strcpy(idp->current.d_name,".."); 644 switch (ep->name[0]) { 645 case 0: 646 idp->current.d_namlen = 1; 647 error = iso_uiodir(idp,&idp->current,idp->curroff); 648 break; 649 case 1: 650 idp->current.d_namlen = 2; 651 error = iso_uiodir(idp,&idp->current,idp->curroff); 652 break; 653 default: 654 isofntrans(ep->name,idp->current.d_namlen, 655 idp->current.d_name, &namelen, 656 imp->iso_ftype == ISO_FTYPE_9660, 657 isonum_711(ep->flags)&4); 658 idp->current.d_namlen = (u_char)namelen; 659 if (imp->iso_ftype == ISO_FTYPE_DEFAULT) 660 error = iso_shipdir(idp); 661 else 662 error = iso_uiodir(idp,&idp->current,idp->curroff); 663 break; 664 } 665 } 666 if (error) 667 break; 668 669 entryoffsetinblock += reclen; 670 } 671 672 if (!error && imp->iso_ftype == ISO_FTYPE_DEFAULT) { 673 idp->current.d_namlen = 0; 674 error = iso_shipdir(idp); 675 } 676 if (error < 0) 677 error = 0; 678 679 if (ap->a_ncookies != NULL) { 680 if (error) 681 free(cookies, M_TEMP); 682 else { 683 /* 684 * Work out the number of cookies actually used. 685 */ 686 *ap->a_ncookies = ncookies - idp->ncookies; 687 *ap->a_cookies = cookies; 688 } 689 } 690 691 if (bp) 692 brelse (bp); 693 694 uio->uio_offset = idp->uio_off; 695 *ap->a_eofflag = idp->eofflag; 696 697 FREE(idp, M_TEMP); 698 699 return (error); 700 } 701 702 /* 703 * Return target name of a symbolic link 704 * Shouldn't we get the parent vnode and read the data from there? 705 * This could eventually result in deadlocks in cd9660_lookup. 706 * But otherwise the block read here is in the block buffer two times. 707 */ 708 typedef struct iso_directory_record ISODIR; 709 typedef struct iso_node ISONODE; 710 typedef struct iso_mnt ISOMNT; 711 static int 712 cd9660_readlink(ap) 713 struct vop_readlink_args /* { 714 struct vnode *a_vp; 715 struct uio *a_uio; 716 struct ucred *a_cred; 717 } */ *ap; 718 { 719 ISONODE *ip; 720 ISODIR *dirp; 721 ISOMNT *imp; 722 struct buf *bp; 723 struct uio *uio; 724 u_short symlen; 725 int error; 726 char *symname; 727 728 ip = VTOI(ap->a_vp); 729 imp = ip->i_mnt; 730 uio = ap->a_uio; 731 732 if (imp->iso_ftype != ISO_FTYPE_RRIP) 733 return (EINVAL); 734 735 /* 736 * Get parents directory record block that this inode included. 737 */ 738 error = bread(imp->im_devvp, 739 (ip->i_number >> imp->im_bshift) << 740 (imp->im_bshift - DEV_BSHIFT), 741 imp->logical_block_size, NOCRED, &bp); 742 if (error) { 743 brelse(bp); 744 return (EINVAL); 745 } 746 747 /* 748 * Setup the directory pointer for this inode 749 */ 750 dirp = (ISODIR *)(bp->b_data + (ip->i_number & imp->im_bmask)); 751 752 /* 753 * Just make sure, we have a right one.... 754 * 1: Check not cross boundary on block 755 */ 756 if ((ip->i_number & imp->im_bmask) + isonum_711(dirp->length) 757 > (unsigned)imp->logical_block_size) { 758 brelse(bp); 759 return (EINVAL); 760 } 761 762 /* 763 * Now get a buffer 764 * Abuse a namei buffer for now. 765 */ 766 if (uio->uio_segflg == UIO_SYSSPACE) 767 symname = uio->uio_iov->iov_base; 768 else 769 symname = zalloc(namei_zone); 770 771 /* 772 * Ok, we just gathering a symbolic name in SL record. 773 */ 774 if (cd9660_rrip_getsymname(dirp, symname, &symlen, imp) == 0) { 775 if (uio->uio_segflg != UIO_SYSSPACE) 776 zfree(namei_zone, symname); 777 brelse(bp); 778 return (EINVAL); 779 } 780 /* 781 * Don't forget before you leave from home ;-) 782 */ 783 brelse(bp); 784 785 /* 786 * return with the symbolic name to caller's. 787 */ 788 if (uio->uio_segflg != UIO_SYSSPACE) { 789 error = uiomove(symname, symlen, uio); 790 zfree(namei_zone, symname); 791 return (error); 792 } 793 uio->uio_resid -= symlen; 794 uio->uio_iov->iov_base += symlen; 795 uio->uio_iov->iov_len -= symlen; 796 return (0); 797 } 798 799 /* 800 * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually 801 * done. If a buffer has been saved in anticipation of a CREATE, delete it. 802 */ 803 static int 804 cd9660_abortop(ap) 805 struct vop_abortop_args /* { 806 struct vnode *a_dvp; 807 struct componentname *a_cnp; 808 } */ *ap; 809 { 810 if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF) 811 zfree(namei_zone, ap->a_cnp->cn_pnbuf); 812 return (0); 813 } 814 815 /* 816 * Lock an inode. 817 */ 818 static int 819 cd9660_lock(ap) 820 struct vop_lock_args /* { 821 struct vnode *a_vp; 822 int a_flags; 823 struct proc *a_p; 824 } */ *ap; 825 { 826 struct vnode *vp = ap->a_vp; 827 828 return (lockmgr(&VTOI(vp)->i_lock, ap->a_flags, &vp->v_interlock, 829 ap->a_p)); 830 } 831 832 /* 833 * Unlock an inode. 834 */ 835 static int 836 cd9660_unlock(ap) 837 struct vop_unlock_args /* { 838 struct vnode *a_vp; 839 int a_flags; 840 struct proc *a_p; 841 } */ *ap; 842 { 843 struct vnode *vp = ap->a_vp; 844 845 return (lockmgr(&VTOI(vp)->i_lock, ap->a_flags | LK_RELEASE, 846 &vp->v_interlock, ap->a_p)); 847 } 848 849 /* 850 * Calculate the logical to physical mapping if not done already, 851 * then call the device strategy routine. 852 */ 853 static int 854 cd9660_strategy(ap) 855 struct vop_strategy_args /* { 856 struct buf *a_bp; 857 } */ *ap; 858 { 859 register struct buf *bp = ap->a_bp; 860 register struct vnode *vp = bp->b_vp; 861 register struct iso_node *ip; 862 int error; 863 864 ip = VTOI(vp); 865 if (vp->v_type == VBLK || vp->v_type == VCHR) 866 panic("cd9660_strategy: spec"); 867 if (bp->b_blkno == bp->b_lblkno) { 868 if ((error = 869 VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL, NULL))) { 870 bp->b_error = error; 871 bp->b_flags |= B_ERROR; 872 biodone(bp); 873 return (error); 874 } 875 if ((long)bp->b_blkno == -1) 876 clrbuf(bp); 877 } 878 if ((long)bp->b_blkno == -1) { 879 biodone(bp); 880 return (0); 881 } 882 vp = ip->i_devvp; 883 bp->b_dev = vp->v_rdev; 884 VOCALL (vp->v_op, VOFFSET(vop_strategy), ap); 885 return (0); 886 } 887 888 /* 889 * Print out the contents of an inode. 890 */ 891 static int 892 cd9660_print(ap) 893 struct vop_print_args /* { 894 struct vnode *a_vp; 895 } */ *ap; 896 { 897 898 printf("tag VT_ISOFS, isofs vnode\n"); 899 return (0); 900 } 901 902 /* 903 * Check for a locked inode. 904 */ 905 int 906 cd9660_islocked(ap) 907 struct vop_islocked_args /* { 908 struct vnode *a_vp; 909 } */ *ap; 910 { 911 912 return (lockstatus(&VTOI(ap->a_vp)->i_lock)); 913 } 914 915 /* 916 * Return POSIX pathconf information applicable to cd9660 filesystems. 917 */ 918 int 919 cd9660_pathconf(ap) 920 struct vop_pathconf_args /* { 921 struct vnode *a_vp; 922 int a_name; 923 register_t *a_retval; 924 } */ *ap; 925 { 926 927 switch (ap->a_name) { 928 case _PC_LINK_MAX: 929 *ap->a_retval = 1; 930 return (0); 931 case _PC_NAME_MAX: 932 if (VTOI(ap->a_vp)->i_mnt->iso_ftype == ISO_FTYPE_RRIP) 933 *ap->a_retval = NAME_MAX; 934 else 935 *ap->a_retval = 37; 936 return (0); 937 case _PC_PATH_MAX: 938 *ap->a_retval = PATH_MAX; 939 return (0); 940 case _PC_PIPE_BUF: 941 *ap->a_retval = PIPE_BUF; 942 return (0); 943 case _PC_CHOWN_RESTRICTED: 944 *ap->a_retval = 1; 945 return (0); 946 case _PC_NO_TRUNC: 947 *ap->a_retval = 1; 948 return (0); 949 default: 950 return (EINVAL); 951 } 952 /* NOTREACHED */ 953 } 954 955 /* 956 * Global vfs data structures for isofs 957 */ 958 #define cd9660_create \ 959 ((int (*) __P((struct vop_create_args *)))eopnotsupp) 960 #define cd9660_mknod ((int (*) __P((struct vop_mknod_args *)))eopnotsupp) 961 #define cd9660_write ((int (*) __P((struct vop_write_args *)))eopnotsupp) 962 #ifdef NFS 963 #define cd9660_lease_check lease_check 964 #else 965 #define cd9660_lease_check ((int (*) __P((struct vop_lease_args *)))nullop) 966 #endif 967 #define cd9660_poll vop_nopoll 968 #define cd9660_fsync ((int (*) __P((struct vop_fsync_args *)))nullop) 969 #define cd9660_remove \ 970 ((int (*) __P((struct vop_remove_args *)))eopnotsupp) 971 #define cd9660_link ((int (*) __P((struct vop_link_args *)))eopnotsupp) 972 #define cd9660_rename \ 973 ((int (*) __P((struct vop_rename_args *)))eopnotsupp) 974 #define cd9660_mkdir ((int (*) __P((struct vop_mkdir_args *)))eopnotsupp) 975 #define cd9660_rmdir ((int (*) __P((struct vop_rmdir_args *)))eopnotsupp) 976 #define cd9660_symlink \ 977 ((int (*) __P((struct vop_symlink_args *)))eopnotsupp) 978 #define cd9660_advlock \ 979 ((int (*) __P((struct vop_advlock_args *)))eopnotsupp) 980 #define cd9660_valloc ((int(*) __P(( \ 981 struct vnode *pvp, \ 982 int mode, \ 983 struct ucred *cred, \ 984 struct vnode **vpp))) eopnotsupp) 985 #define cd9660_vfree ((int (*) __P((struct vop_vfree_args *)))eopnotsupp) 986 #define cd9660_truncate \ 987 ((int (*) __P((struct vop_truncate_args *)))eopnotsupp) 988 #define cd9660_update \ 989 ((int (*) __P((struct vop_update_args *)))eopnotsupp) 990 #define cd9660_bwrite \ 991 ((int (*) __P((struct vop_bwrite_args *)))eopnotsupp) 992 993 /* 994 * Global vfs data structures for cd9660 995 */ 996 vop_t **cd9660_vnodeop_p; 997 struct vnodeopv_entry_desc cd9660_vnodeop_entries[] = { 998 999 { &vop_default_desc, (vop_t *)vn_default_error }, 1000 { &vop_lookup_desc, (vop_t *)vfs_cache_lookup }, /* lookup */ 1001 { &vop_cachedlookup_desc, (vop_t *)cd9660_lookup }, /* lookup */ 1002 { &vop_create_desc, (vop_t *)cd9660_create }, /* create */ 1003 /* XXX: vop_whiteout */ 1004 { &vop_mknod_desc, (vop_t *)cd9660_mknod }, /* mknod */ 1005 { &vop_open_desc, (vop_t *)cd9660_open }, /* open */ 1006 { &vop_close_desc, (vop_t *)cd9660_close }, /* close */ 1007 { &vop_access_desc, (vop_t *)cd9660_access }, /* access */ 1008 { &vop_getattr_desc, (vop_t *)cd9660_getattr }, /* getattr */ 1009 { &vop_setattr_desc, (vop_t *)cd9660_setattr }, /* setattr */ 1010 { &vop_read_desc, (vop_t *)cd9660_read }, /* read */ 1011 { &vop_write_desc, (vop_t *)cd9660_write }, /* write */ 1012 { &vop_lease_desc, (vop_t *)cd9660_lease_check },/* lease */ 1013 { &vop_ioctl_desc, (vop_t *)cd9660_ioctl }, /* ioctl */ 1014 { &vop_poll_desc, (vop_t *)cd9660_poll }, /* poll */ 1015 { &vop_revoke_desc, (vop_t *)cd9660_revoke }, /* revoke */ 1016 { &vop_mmap_desc, (vop_t *)cd9660_mmap }, /* mmap */ 1017 { &vop_fsync_desc, (vop_t *)cd9660_fsync }, /* fsync */ 1018 { &vop_seek_desc, (vop_t *)cd9660_seek }, /* seek */ 1019 { &vop_remove_desc, (vop_t *)cd9660_remove }, /* remove */ 1020 { &vop_link_desc, (vop_t *)cd9660_link }, /* link */ 1021 { &vop_rename_desc, (vop_t *)cd9660_rename }, /* rename */ 1022 { &vop_mkdir_desc, (vop_t *)cd9660_mkdir }, /* mkdir */ 1023 { &vop_rmdir_desc, (vop_t *)cd9660_rmdir }, /* rmdir */ 1024 { &vop_symlink_desc, (vop_t *)cd9660_symlink }, /* symlink */ 1025 { &vop_readdir_desc, (vop_t *)cd9660_readdir }, /* readdir */ 1026 { &vop_readlink_desc, (vop_t *)cd9660_readlink },/* readlink */ 1027 { &vop_abortop_desc, (vop_t *)cd9660_abortop }, /* abortop */ 1028 { &vop_inactive_desc, (vop_t *)cd9660_inactive },/* inactive */ 1029 { &vop_reclaim_desc, (vop_t *)cd9660_reclaim }, /* reclaim */ 1030 { &vop_lock_desc, (vop_t *)cd9660_lock }, /* lock */ 1031 { &vop_unlock_desc, (vop_t *)cd9660_unlock }, /* unlock */ 1032 { &vop_bmap_desc, (vop_t *)cd9660_bmap }, /* bmap */ 1033 { &vop_strategy_desc, (vop_t *)cd9660_strategy },/* strategy */ 1034 { &vop_print_desc, (vop_t *)cd9660_print }, /* print */ 1035 { &vop_islocked_desc, (vop_t *)cd9660_islocked },/* islocked */ 1036 { &vop_pathconf_desc, (vop_t *)cd9660_pathconf },/* pathconf */ 1037 { &vop_advlock_desc, (vop_t *)cd9660_advlock }, /* advlock */ 1038 { &vop_blkatoff_desc, (vop_t *)cd9660_blkatoff },/* blkatoff */ 1039 { &vop_valloc_desc, (vop_t *)cd9660_valloc }, /* valloc */ 1040 /* XXX: vop_reallocblks */ 1041 { &vop_vfree_desc, (vop_t *)cd9660_vfree }, /* vfree */ 1042 { &vop_truncate_desc, (vop_t *)cd9660_truncate },/* truncate */ 1043 { &vop_update_desc, (vop_t *)cd9660_update }, /* update */ 1044 /* XXX: vop_getpages */ 1045 /* XXX: vop_putpages */ 1046 { &vop_bwrite_desc, (vop_t *)vn_bwrite }, 1047 { NULL, NULL } 1048 }; 1049 static struct vnodeopv_desc cd9660_vnodeop_opv_desc = 1050 { &cd9660_vnodeop_p, cd9660_vnodeop_entries }; 1051 VNODEOP_SET(cd9660_vnodeop_opv_desc); 1052 1053 /* 1054 * Special device vnode ops 1055 */ 1056 vop_t **cd9660_specop_p; 1057 struct vnodeopv_entry_desc cd9660_specop_entries[] = { 1058 { &vop_default_desc, (vop_t *)vn_default_error }, 1059 { &vop_lookup_desc, (vop_t *)spec_lookup }, /* lookup */ 1060 /* XXX: vop_cachedlookup */ 1061 { &vop_create_desc, (vop_t *)spec_create }, /* create */ 1062 /* XXX: vop_whiteout */ 1063 { &vop_mknod_desc, (vop_t *)spec_mknod }, /* mknod */ 1064 { &vop_open_desc, (vop_t *)spec_open }, /* open */ 1065 { &vop_close_desc, (vop_t *)spec_close }, /* close */ 1066 { &vop_access_desc, (vop_t *)cd9660_access }, /* access */ 1067 { &vop_getattr_desc, (vop_t *)cd9660_getattr }, /* getattr */ 1068 { &vop_setattr_desc, (vop_t *)cd9660_setattr }, /* setattr */ 1069 { &vop_read_desc, (vop_t *)spec_read }, /* read */ 1070 { &vop_write_desc, (vop_t *)spec_write }, /* write */ 1071 { &vop_lease_desc, (vop_t *)spec_lease_check }, /* lease */ 1072 { &vop_ioctl_desc, (vop_t *)spec_ioctl }, /* ioctl */ 1073 { &vop_poll_desc, (vop_t *)spec_poll }, /* poll */ 1074 { &vop_revoke_desc, (vop_t *)spec_revoke }, /* revoke */ 1075 { &vop_mmap_desc, (vop_t *)spec_mmap }, /* mmap */ 1076 { &vop_fsync_desc, (vop_t *)spec_fsync }, /* fsync */ 1077 { &vop_seek_desc, (vop_t *)spec_seek }, /* seek */ 1078 { &vop_remove_desc, (vop_t *)spec_remove }, /* remove */ 1079 { &vop_link_desc, (vop_t *)spec_link }, /* link */ 1080 { &vop_rename_desc, (vop_t *)spec_rename }, /* rename */ 1081 { &vop_mkdir_desc, (vop_t *)spec_mkdir }, /* mkdir */ 1082 { &vop_rmdir_desc, (vop_t *)spec_rmdir }, /* rmdir */ 1083 { &vop_symlink_desc, (vop_t *)spec_symlink }, /* symlink */ 1084 { &vop_readdir_desc, (vop_t *)spec_readdir }, /* readdir */ 1085 { &vop_readlink_desc, (vop_t *)spec_readlink }, /* readlink */ 1086 { &vop_abortop_desc, (vop_t *)spec_abortop }, /* abortop */ 1087 { &vop_inactive_desc, (vop_t *)cd9660_inactive },/* inactive */ 1088 { &vop_reclaim_desc, (vop_t *)cd9660_reclaim }, /* reclaim */ 1089 { &vop_lock_desc, (vop_t *)cd9660_lock }, /* lock */ 1090 { &vop_unlock_desc, (vop_t *)cd9660_unlock }, /* unlock */ 1091 { &vop_bmap_desc, (vop_t *)spec_bmap }, /* bmap */ 1092 { &vop_strategy_desc, (vop_t *)spec_strategy }, /* strategy */ 1093 { &vop_print_desc, (vop_t *)cd9660_print }, /* print */ 1094 { &vop_islocked_desc, (vop_t *)cd9660_islocked },/* islocked */ 1095 { &vop_pathconf_desc, (vop_t *)spec_pathconf }, /* pathconf */ 1096 { &vop_advlock_desc, (vop_t *)spec_advlock }, /* advlock */ 1097 { &vop_blkatoff_desc, (vop_t *)spec_blkatoff }, /* blkatoff */ 1098 { &vop_valloc_desc, (vop_t *)spec_valloc }, /* valloc */ 1099 /* XXX: vop_reallocblks */ 1100 { &vop_vfree_desc, (vop_t *)spec_vfree }, /* vfree */ 1101 { &vop_truncate_desc, (vop_t *)spec_truncate }, /* truncate */ 1102 { &vop_update_desc, (vop_t *)cd9660_update }, /* update */ 1103 /* XXX: vop_getpages */ 1104 /* XXX: vop_putpages */ 1105 { &vop_bwrite_desc, (vop_t *)vn_bwrite }, 1106 { NULL, NULL } 1107 }; 1108 static struct vnodeopv_desc cd9660_specop_opv_desc = 1109 { &cd9660_specop_p, cd9660_specop_entries }; 1110 VNODEOP_SET(cd9660_specop_opv_desc); 1111 1112 vop_t **cd9660_fifoop_p; 1113 struct vnodeopv_entry_desc cd9660_fifoop_entries[] = { 1114 { &vop_default_desc, (vop_t *)vn_default_error }, 1115 { &vop_lookup_desc, (vop_t *)fifo_lookup }, /* lookup */ 1116 /* XXX: vop_cachedlookup */ 1117 { &vop_create_desc, (vop_t *)fifo_create }, /* create */ 1118 /* XXX: vop_whiteout */ 1119 { &vop_mknod_desc, (vop_t *)fifo_mknod }, /* mknod */ 1120 { &vop_open_desc, (vop_t *)fifo_open }, /* open */ 1121 { &vop_close_desc, (vop_t *)fifo_close }, /* close */ 1122 { &vop_access_desc, (vop_t *)cd9660_access }, /* access */ 1123 { &vop_getattr_desc, (vop_t *)cd9660_getattr }, /* getattr */ 1124 { &vop_setattr_desc, (vop_t *)cd9660_setattr }, /* setattr */ 1125 { &vop_read_desc, (vop_t *)fifo_read }, /* read */ 1126 { &vop_write_desc, (vop_t *)fifo_write }, /* write */ 1127 { &vop_lease_desc, (vop_t *)fifo_lease_check }, /* lease */ 1128 { &vop_ioctl_desc, (vop_t *)fifo_ioctl }, /* ioctl */ 1129 { &vop_poll_desc, (vop_t *)fifo_poll }, /* poll */ 1130 { &vop_revoke_desc, (vop_t *)fifo_revoke }, /* revoke */ 1131 { &vop_mmap_desc, (vop_t *)fifo_mmap }, /* mmap */ 1132 { &vop_fsync_desc, (vop_t *)fifo_fsync }, /* fsync */ 1133 { &vop_seek_desc, (vop_t *)fifo_seek }, /* seek */ 1134 { &vop_remove_desc, (vop_t *)fifo_remove }, /* remove */ 1135 { &vop_link_desc, (vop_t *)fifo_link } , /* link */ 1136 { &vop_rename_desc, (vop_t *)fifo_rename }, /* rename */ 1137 { &vop_mkdir_desc, (vop_t *)fifo_mkdir }, /* mkdir */ 1138 { &vop_rmdir_desc, (vop_t *)fifo_rmdir }, /* rmdir */ 1139 { &vop_symlink_desc, (vop_t *)fifo_symlink }, /* symlink */ 1140 { &vop_readdir_desc, (vop_t *)fifo_readdir }, /* readdir */ 1141 { &vop_readlink_desc, (vop_t *)fifo_readlink }, /* readlink */ 1142 { &vop_abortop_desc, (vop_t *)fifo_abortop }, /* abortop */ 1143 { &vop_inactive_desc, (vop_t *)cd9660_inactive },/* inactive */ 1144 { &vop_reclaim_desc, (vop_t *)cd9660_reclaim }, /* reclaim */ 1145 { &vop_lock_desc, (vop_t *)cd9660_lock }, /* lock */ 1146 { &vop_unlock_desc, (vop_t *)cd9660_unlock }, /* unlock */ 1147 { &vop_bmap_desc, (vop_t *)fifo_bmap }, /* bmap */ 1148 { &vop_strategy_desc, (vop_t *)fifo_strategy }, /* strategy */ 1149 { &vop_print_desc, (vop_t *)cd9660_print }, /* print */ 1150 { &vop_islocked_desc, (vop_t *)cd9660_islocked },/* islocked */ 1151 { &vop_pathconf_desc, (vop_t *)fifo_pathconf }, /* pathconf */ 1152 { &vop_advlock_desc, (vop_t *)fifo_advlock }, /* advlock */ 1153 { &vop_blkatoff_desc, (vop_t *)fifo_blkatoff }, /* blkatoff */ 1154 { &vop_valloc_desc, (vop_t *)fifo_valloc }, /* valloc */ 1155 /* XXX: vop_reallocpages */ 1156 { &vop_vfree_desc, (vop_t *)fifo_vfree }, /* vfree */ 1157 { &vop_truncate_desc, (vop_t *)fifo_truncate }, /* truncate */ 1158 { &vop_update_desc, (vop_t *)cd9660_update }, /* update */ 1159 /* XXX: vop_getpages */ 1160 /* XXX: vop_putpages */ 1161 { &vop_bwrite_desc, (vop_t *)vn_bwrite }, 1162 { NULL, NULL } 1163 }; 1164 static struct vnodeopv_desc cd9660_fifoop_opv_desc = 1165 { &cd9660_fifoop_p, cd9660_fifoop_entries }; 1166 1167 VNODEOP_SET(cd9660_fifoop_opv_desc); 1168