1 /* $NetBSD: cd9660_vnops.c,v 1.19 2005/12/11 12:24:25 christos 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.19 2005/12/11 12:24:25 christos 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(struct isoreaddir *, struct dirent *, off_t); 84 int iso_shipdir(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 PNBUF_PUT(ndp->ni_pnbuf); 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 PNBUF_PUT(ndp->ni_pnbuf); 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 lwp *a_l; 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 lwp *a_l; 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_lwp = NULL; 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 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); 315 return (error); 316 } 317 318 error = uiomove(bp->b_data + on, (int)n, uio); 319 brelse(bp); 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 struct ucred *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 / 16; 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); 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 ep = (struct iso_directory_record *) 496 ((char *)bp->b_data + entryoffsetinblock); 497 498 reclen = isonum_711(ep->length); 499 if (reclen == 0) { 500 /* skip to next block, if any */ 501 idp->curroff = 502 (idp->curroff & ~bmask) + imp->logical_block_size; 503 continue; 504 } 505 506 if (reclen < ISO_DIRECTORY_RECORD_SIZE) { 507 error = EINVAL; 508 /* illegal entry, stop */ 509 break; 510 } 511 512 if (entryoffsetinblock + reclen > imp->logical_block_size) { 513 error = EINVAL; 514 /* illegal directory, so stop looking */ 515 break; 516 } 517 518 idp->current.d_namlen = isonum_711(ep->name_len); 519 520 if (reclen < ISO_DIRECTORY_RECORD_SIZE + idp->current.d_namlen) { 521 error = EINVAL; 522 /* illegal entry, stop */ 523 break; 524 } 525 526 if (isonum_711(ep->flags)&2) 527 idp->current.d_fileno = isodirino(ep, imp); 528 else 529 idp->current.d_fileno = dbtob(bp->b_blkno) + 530 entryoffsetinblock; 531 532 idp->curroff += reclen; 533 534 switch (imp->iso_ftype) { 535 case ISO_FTYPE_RRIP: 536 cd9660_rrip_getname(ep, idp->current.d_name, &namelen, 537 &idp->current.d_fileno, imp); 538 idp->current.d_namlen = (u_char)namelen; 539 if (idp->current.d_namlen) 540 error = iso_uiodir(idp, &idp->current, 541 idp->curroff); 542 break; 543 default: /* ISO_FTYPE_DEFAULT || ISO_FTYPE_9660 */ 544 isofntrans(ep->name, idp->current.d_namlen, 545 idp->current.d_name, &namelen, 546 imp->iso_ftype == ISO_FTYPE_9660, 547 (imp->im_flags & ISOFSMNT_NOCASETRANS) == 0, 548 isonum_711(ep->flags)&4, 549 imp->im_joliet_level); 550 switch (idp->current.d_name[0]) { 551 case 0: 552 idp->current.d_name[0] = '.'; 553 idp->current.d_namlen = 1; 554 error = iso_uiodir(idp, &idp->current, 555 idp->curroff); 556 break; 557 case 1: 558 strlcpy(idp->current.d_name, "..", 559 sizeof(idp->current.d_name)); 560 idp->current.d_namlen = 2; 561 error = iso_uiodir(idp, &idp->current, 562 idp->curroff); 563 break; 564 default: 565 idp->current.d_namlen = (u_char)namelen; 566 if (imp->iso_ftype == ISO_FTYPE_DEFAULT) 567 error = iso_shipdir(idp); 568 else 569 error = iso_uiodir(idp, &idp->current, 570 idp->curroff); 571 break; 572 } 573 } 574 if (error) 575 break; 576 577 entryoffsetinblock += reclen; 578 } 579 580 if (!error && imp->iso_ftype == ISO_FTYPE_DEFAULT) { 581 idp->current.d_namlen = 0; 582 error = iso_shipdir(idp); 583 } 584 if (error < 0) 585 error = 0; 586 587 if (ap->a_ncookies != NULL) { 588 if (error) 589 free(cookies, M_TEMP); 590 else { 591 /* 592 * Work out the number of cookies actually used. 593 */ 594 *ap->a_ncookies = ncookies - idp->ncookies; 595 *ap->a_cookies = cookies; 596 } 597 } 598 599 if (bp) 600 brelse (bp); 601 602 uio->uio_offset = idp->uio_off; 603 *ap->a_eofflag = idp->eofflag; 604 605 FREE(idp, M_TEMP); 606 607 return (error); 608 } 609 610 /* 611 * Return target name of a symbolic link 612 * Shouldn't we get the parent vnode and read the data from there? 613 * This could eventually result in deadlocks in cd9660_lookup. 614 * But otherwise the block read here is in the block buffer two times. 615 */ 616 typedef struct iso_directory_record ISODIR; 617 typedef struct iso_node ISONODE; 618 typedef struct iso_mnt ISOMNT; 619 int 620 cd9660_readlink(v) 621 void *v; 622 { 623 struct vop_readlink_args /* { 624 struct vnode *a_vp; 625 struct uio *a_uio; 626 struct ucred *a_cred; 627 } */ *ap = v; 628 ISONODE *ip; 629 ISODIR *dirp; 630 ISOMNT *imp; 631 struct buf *bp; 632 struct uio *uio; 633 u_short symlen; 634 int error; 635 char *symname; 636 637 ip = VTOI(ap->a_vp); 638 imp = ip->i_mnt; 639 uio = ap->a_uio; 640 641 if (imp->iso_ftype != ISO_FTYPE_RRIP) 642 return (EINVAL); 643 644 /* 645 * Get parents directory record block that this inode included. 646 */ 647 error = bread(imp->im_devvp, 648 (ip->i_number >> imp->im_bshift) << 649 (imp->im_bshift - DEV_BSHIFT), 650 imp->logical_block_size, NOCRED, &bp); 651 if (error) { 652 brelse(bp); 653 return (EINVAL); 654 } 655 656 /* 657 * Setup the directory pointer for this inode 658 */ 659 dirp = (ISODIR *)(bp->b_data + (ip->i_number & imp->im_bmask)); 660 661 /* 662 * Just make sure, we have a right one.... 663 * 1: Check not cross boundary on block 664 */ 665 if ((ip->i_number & imp->im_bmask) + isonum_711(dirp->length) 666 > imp->logical_block_size) { 667 brelse(bp); 668 return (EINVAL); 669 } 670 671 /* 672 * Now get a buffer 673 * Abuse a namei buffer for now. 674 */ 675 if (uio->uio_segflg == UIO_SYSSPACE && 676 uio->uio_iov->iov_len >= MAXPATHLEN) 677 symname = uio->uio_iov->iov_base; 678 else 679 symname = PNBUF_GET(); 680 681 /* 682 * Ok, we just gathering a symbolic name in SL record. 683 */ 684 if (cd9660_rrip_getsymname(dirp, symname, &symlen, imp) == 0) { 685 if (uio->uio_segflg != UIO_SYSSPACE || 686 uio->uio_iov->iov_len < MAXPATHLEN) 687 PNBUF_PUT(symname); 688 brelse(bp); 689 return (EINVAL); 690 } 691 /* 692 * Don't forget before you leave from home ;-) 693 */ 694 brelse(bp); 695 696 /* 697 * return with the symbolic name to caller's. 698 */ 699 if (uio->uio_segflg != UIO_SYSSPACE || 700 uio->uio_iov->iov_len < MAXPATHLEN) { 701 error = uiomove(symname, symlen, uio); 702 PNBUF_PUT(symname); 703 return (error); 704 } 705 uio->uio_resid -= symlen; 706 uio->uio_iov->iov_base = (char *)uio->uio_iov->iov_base + symlen; 707 uio->uio_iov->iov_len -= symlen; 708 return (0); 709 } 710 711 int 712 cd9660_link(v) 713 void *v; 714 { 715 struct vop_link_args /* { 716 struct vnode *a_dvp; 717 struct vnode *a_vp; 718 struct componentname *a_cnp; 719 } */ *ap = v; 720 721 VOP_ABORTOP(ap->a_dvp, ap->a_cnp); 722 vput(ap->a_dvp); 723 return (EROFS); 724 } 725 726 int 727 cd9660_symlink(v) 728 void *v; 729 { 730 struct vop_symlink_args /* { 731 struct vnode *a_dvp; 732 struct vnode **a_vpp; 733 struct componentname *a_cnp; 734 struct vattr *a_vap; 735 char *a_target; 736 } */ *ap = v; 737 738 VOP_ABORTOP(ap->a_dvp, ap->a_cnp); 739 vput(ap->a_dvp); 740 return (EROFS); 741 } 742 743 /* 744 * Calculate the logical to physical mapping if not done already, 745 * then call the device strategy routine. 746 */ 747 int 748 cd9660_strategy(v) 749 void *v; 750 { 751 struct vop_strategy_args /* { 752 struct vnode *a_vp; 753 struct buf *a_bp; 754 } */ *ap = v; 755 struct buf *bp = ap->a_bp; 756 struct vnode *vp = ap->a_vp; 757 struct iso_node *ip; 758 int error; 759 760 ip = VTOI(vp); 761 if (vp->v_type == VBLK || vp->v_type == VCHR) 762 panic("cd9660_strategy: spec"); 763 if (bp->b_blkno == bp->b_lblkno) { 764 error = VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL); 765 if (error) { 766 bp->b_error = error; 767 bp->b_flags |= B_ERROR; 768 biodone(bp); 769 return (error); 770 } 771 if ((long)bp->b_blkno == -1) 772 clrbuf(bp); 773 } 774 if ((long)bp->b_blkno == -1) { 775 biodone(bp); 776 return (0); 777 } 778 vp = ip->i_devvp; 779 return (VOP_STRATEGY(vp, bp)); 780 } 781 782 /* 783 * Print out the contents of an inode. 784 */ 785 /*ARGSUSED*/ 786 int 787 cd9660_print(v) 788 void *v; 789 { 790 791 printf("tag VT_ISOFS, isofs vnode\n"); 792 return (0); 793 } 794 795 /* 796 * Return POSIX pathconf information applicable to cd9660 filesystems. 797 */ 798 int 799 cd9660_pathconf(v) 800 void *v; 801 { 802 struct vop_pathconf_args /* { 803 struct vnode *a_vp; 804 int a_name; 805 register_t *a_retval; 806 } */ *ap = v; 807 switch (ap->a_name) { 808 case _PC_LINK_MAX: 809 *ap->a_retval = 1; 810 return (0); 811 case _PC_NAME_MAX: 812 if (VTOI(ap->a_vp)->i_mnt->iso_ftype == ISO_FTYPE_RRIP) 813 *ap->a_retval = NAME_MAX; 814 else 815 *ap->a_retval = 37; 816 return (0); 817 case _PC_PATH_MAX: 818 *ap->a_retval = PATH_MAX; 819 return (0); 820 case _PC_PIPE_BUF: 821 *ap->a_retval = PIPE_BUF; 822 return (0); 823 case _PC_CHOWN_RESTRICTED: 824 *ap->a_retval = 1; 825 return (0); 826 case _PC_NO_TRUNC: 827 *ap->a_retval = 1; 828 return (0); 829 case _PC_SYNC_IO: 830 *ap->a_retval = 1; 831 return (0); 832 case _PC_FILESIZEBITS: 833 *ap->a_retval = 32; 834 return (0); 835 default: 836 return (EINVAL); 837 } 838 /* NOTREACHED */ 839 } 840 841 /* 842 * Allow changing the size for special files (and fifos). 843 */ 844 int 845 cd9660_setattr(v) 846 void *v; 847 { 848 struct vop_setattr_args /* { 849 struct vnodeop_desc *a_desc; 850 struct vnode *a_vp; 851 struct vattr *a_vap; 852 struct ucred *a_cred; 853 struct proc *a_p; 854 } */ *ap = v; 855 struct vattr *vap = ap->a_vap; 856 struct vnode *vp = ap->a_vp; 857 858 /* 859 * Only size is changeable. 860 */ 861 if (vap->va_type != VNON 862 || vap->va_nlink != (nlink_t)VNOVAL 863 || vap->va_fsid != VNOVAL 864 || vap->va_fileid != VNOVAL 865 || vap->va_blocksize != VNOVAL 866 || vap->va_rdev != (dev_t)VNOVAL 867 || (int)vap->va_bytes != VNOVAL 868 || vap->va_gen != VNOVAL 869 || vap->va_flags != VNOVAL 870 || vap->va_uid != (uid_t)VNOVAL 871 || vap->va_gid != (gid_t)VNOVAL 872 || vap->va_atime.tv_sec != VNOVAL 873 || vap->va_mtime.tv_sec != VNOVAL 874 || vap->va_mode != (mode_t)VNOVAL) 875 return EOPNOTSUPP; 876 877 if (vap->va_size != VNOVAL 878 && vp->v_type != VCHR 879 && vp->v_type != VBLK 880 && vp->v_type != VFIFO) 881 return EOPNOTSUPP; 882 883 return 0; 884 } 885 886 /* 887 * Global vfs data structures for isofs 888 */ 889 #define cd9660_create genfs_eopnotsupp 890 #define cd9660_mknod genfs_eopnotsupp 891 #define cd9660_write genfs_eopnotsupp 892 #define cd9660_lease_check genfs_lease_check 893 #define cd9660_fsync genfs_nullop 894 #define cd9660_remove genfs_eopnotsupp 895 #define cd9660_rename genfs_eopnotsupp 896 #define cd9660_mkdir genfs_eopnotsupp 897 #define cd9660_rmdir genfs_eopnotsupp 898 #define cd9660_advlock genfs_einval 899 #define cd9660_bwrite genfs_eopnotsupp 900 #define cd9660_revoke genfs_revoke 901 902 /* 903 * Global vfs data structures for cd9660 904 */ 905 int (**cd9660_vnodeop_p)(void *); 906 const struct vnodeopv_entry_desc cd9660_vnodeop_entries[] = { 907 { &vop_default_desc, vn_default_error }, 908 { &vop_lookup_desc, cd9660_lookup }, /* lookup */ 909 { &vop_create_desc, cd9660_create }, /* create */ 910 { &vop_mknod_desc, cd9660_mknod }, /* mknod */ 911 { &vop_open_desc, cd9660_open }, /* open */ 912 { &vop_close_desc, cd9660_close }, /* close */ 913 { &vop_access_desc, cd9660_access }, /* access */ 914 { &vop_getattr_desc, cd9660_getattr }, /* getattr */ 915 { &vop_setattr_desc, cd9660_setattr }, /* setattr */ 916 { &vop_read_desc, cd9660_read }, /* read */ 917 { &vop_write_desc, cd9660_write }, /* write */ 918 { &vop_lease_desc, cd9660_lease_check }, /* lease */ 919 { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */ 920 { &vop_ioctl_desc, cd9660_ioctl }, /* ioctl */ 921 { &vop_poll_desc, cd9660_poll }, /* poll */ 922 { &vop_revoke_desc, cd9660_revoke }, /* revoke */ 923 { &vop_mmap_desc, cd9660_mmap }, /* mmap */ 924 { &vop_fsync_desc, cd9660_fsync }, /* fsync */ 925 { &vop_seek_desc, cd9660_seek }, /* seek */ 926 { &vop_remove_desc, cd9660_remove }, /* remove */ 927 { &vop_link_desc, cd9660_link }, /* link */ 928 { &vop_rename_desc, cd9660_rename }, /* rename */ 929 { &vop_mkdir_desc, cd9660_mkdir }, /* mkdir */ 930 { &vop_rmdir_desc, cd9660_rmdir }, /* rmdir */ 931 { &vop_symlink_desc, cd9660_symlink }, /* symlink */ 932 { &vop_readdir_desc, cd9660_readdir }, /* readdir */ 933 { &vop_readlink_desc, cd9660_readlink }, /* readlink */ 934 { &vop_abortop_desc, cd9660_abortop }, /* abortop */ 935 { &vop_inactive_desc, cd9660_inactive }, /* inactive */ 936 { &vop_reclaim_desc, cd9660_reclaim }, /* reclaim */ 937 { &vop_lock_desc, genfs_lock }, /* lock */ 938 { &vop_unlock_desc, genfs_unlock }, /* unlock */ 939 { &vop_bmap_desc, cd9660_bmap }, /* bmap */ 940 { &vop_strategy_desc, cd9660_strategy }, /* strategy */ 941 { &vop_print_desc, cd9660_print }, /* print */ 942 { &vop_islocked_desc, genfs_islocked }, /* islocked */ 943 { &vop_pathconf_desc, cd9660_pathconf }, /* pathconf */ 944 { &vop_advlock_desc, cd9660_advlock }, /* advlock */ 945 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 946 { &vop_getpages_desc, genfs_getpages }, /* getpages */ 947 { &vop_putpages_desc, genfs_putpages }, /* putpages */ 948 { NULL, NULL } 949 }; 950 const struct vnodeopv_desc cd9660_vnodeop_opv_desc = 951 { &cd9660_vnodeop_p, cd9660_vnodeop_entries }; 952 953 /* 954 * Special device vnode ops 955 */ 956 int (**cd9660_specop_p)(void *); 957 const struct vnodeopv_entry_desc cd9660_specop_entries[] = { 958 { &vop_default_desc, vn_default_error }, 959 { &vop_lookup_desc, spec_lookup }, /* lookup */ 960 { &vop_create_desc, spec_create }, /* create */ 961 { &vop_mknod_desc, spec_mknod }, /* mknod */ 962 { &vop_open_desc, spec_open }, /* open */ 963 { &vop_close_desc, spec_close }, /* close */ 964 { &vop_access_desc, cd9660_access }, /* access */ 965 { &vop_getattr_desc, cd9660_getattr }, /* getattr */ 966 { &vop_setattr_desc, cd9660_setattr }, /* setattr */ 967 { &vop_read_desc, spec_read }, /* read */ 968 { &vop_write_desc, spec_write }, /* write */ 969 { &vop_lease_desc, spec_lease_check }, /* lease */ 970 { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */ 971 { &vop_ioctl_desc, spec_ioctl }, /* ioctl */ 972 { &vop_poll_desc, spec_poll }, /* poll */ 973 { &vop_kqfilter_desc, spec_kqfilter }, /* kqfilter */ 974 { &vop_revoke_desc, spec_revoke }, /* revoke */ 975 { &vop_mmap_desc, spec_mmap }, /* mmap */ 976 { &vop_fsync_desc, spec_fsync }, /* fsync */ 977 { &vop_seek_desc, spec_seek }, /* seek */ 978 { &vop_remove_desc, spec_remove }, /* remove */ 979 { &vop_link_desc, spec_link }, /* link */ 980 { &vop_rename_desc, spec_rename }, /* rename */ 981 { &vop_mkdir_desc, spec_mkdir }, /* mkdir */ 982 { &vop_rmdir_desc, spec_rmdir }, /* rmdir */ 983 { &vop_symlink_desc, spec_symlink }, /* symlink */ 984 { &vop_readdir_desc, spec_readdir }, /* readdir */ 985 { &vop_readlink_desc, spec_readlink }, /* readlink */ 986 { &vop_abortop_desc, spec_abortop }, /* abortop */ 987 { &vop_inactive_desc, cd9660_inactive }, /* inactive */ 988 { &vop_reclaim_desc, cd9660_reclaim }, /* reclaim */ 989 { &vop_lock_desc, genfs_lock }, /* lock */ 990 { &vop_unlock_desc, genfs_unlock }, /* unlock */ 991 { &vop_bmap_desc, spec_bmap }, /* bmap */ 992 { &vop_strategy_desc, spec_strategy }, /* strategy */ 993 { &vop_print_desc, cd9660_print }, /* print */ 994 { &vop_islocked_desc, genfs_islocked }, /* islocked */ 995 { &vop_pathconf_desc, spec_pathconf }, /* pathconf */ 996 { &vop_advlock_desc, spec_advlock }, /* advlock */ 997 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 998 { &vop_getpages_desc, spec_getpages }, /* getpages */ 999 { &vop_putpages_desc, spec_putpages }, /* putpages */ 1000 { NULL, NULL } 1001 }; 1002 const struct vnodeopv_desc cd9660_specop_opv_desc = 1003 { &cd9660_specop_p, cd9660_specop_entries }; 1004 1005 int (**cd9660_fifoop_p)(void *); 1006 const struct vnodeopv_entry_desc cd9660_fifoop_entries[] = { 1007 { &vop_default_desc, vn_default_error }, 1008 { &vop_lookup_desc, fifo_lookup }, /* lookup */ 1009 { &vop_create_desc, fifo_create }, /* create */ 1010 { &vop_mknod_desc, fifo_mknod }, /* mknod */ 1011 { &vop_open_desc, fifo_open }, /* open */ 1012 { &vop_close_desc, fifo_close }, /* close */ 1013 { &vop_access_desc, cd9660_access }, /* access */ 1014 { &vop_getattr_desc, cd9660_getattr }, /* getattr */ 1015 { &vop_setattr_desc, cd9660_setattr }, /* setattr */ 1016 { &vop_read_desc, fifo_read }, /* read */ 1017 { &vop_write_desc, fifo_write }, /* write */ 1018 { &vop_lease_desc, fifo_lease_check }, /* lease */ 1019 { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */ 1020 { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */ 1021 { &vop_poll_desc, fifo_poll }, /* poll */ 1022 { &vop_kqfilter_desc, fifo_kqfilter }, /* kqfilter */ 1023 { &vop_revoke_desc, fifo_revoke }, /* revoke */ 1024 { &vop_mmap_desc, fifo_mmap }, /* mmap */ 1025 { &vop_fsync_desc, fifo_fsync }, /* fsync */ 1026 { &vop_seek_desc, fifo_seek }, /* seek */ 1027 { &vop_remove_desc, fifo_remove }, /* remove */ 1028 { &vop_link_desc, fifo_link } , /* link */ 1029 { &vop_rename_desc, fifo_rename }, /* rename */ 1030 { &vop_mkdir_desc, fifo_mkdir }, /* mkdir */ 1031 { &vop_rmdir_desc, fifo_rmdir }, /* rmdir */ 1032 { &vop_symlink_desc, fifo_symlink }, /* symlink */ 1033 { &vop_readdir_desc, fifo_readdir }, /* readdir */ 1034 { &vop_readlink_desc, fifo_readlink }, /* readlink */ 1035 { &vop_abortop_desc, fifo_abortop }, /* abortop */ 1036 { &vop_inactive_desc, cd9660_inactive }, /* inactive */ 1037 { &vop_reclaim_desc, cd9660_reclaim }, /* reclaim */ 1038 { &vop_lock_desc, genfs_lock }, /* lock */ 1039 { &vop_unlock_desc, genfs_unlock }, /* unlock */ 1040 { &vop_bmap_desc, fifo_bmap }, /* bmap */ 1041 { &vop_strategy_desc, fifo_strategy }, /* strategy */ 1042 { &vop_print_desc, cd9660_print }, /* print */ 1043 { &vop_islocked_desc, genfs_islocked }, /* islocked */ 1044 { &vop_pathconf_desc, fifo_pathconf }, /* pathconf */ 1045 { &vop_advlock_desc, fifo_advlock }, /* advlock */ 1046 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 1047 { &vop_putpages_desc, fifo_putpages }, /* putpages */ 1048 { NULL, NULL } 1049 }; 1050 const struct vnodeopv_desc cd9660_fifoop_opv_desc = 1051 { &cd9660_fifoop_p, cd9660_fifoop_entries }; 1052