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