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