1 /* $NetBSD: cd9660_vnops.c,v 1.3 2003/06/07 12:00:07 reinoud 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. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by the University of 23 * California, Berkeley and its contributors. 24 * 4. Neither the name of the University nor the names of its contributors 25 * may be used to endorse or promote products derived from this software 26 * without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 * 40 * @(#)cd9660_vnops.c 8.15 (Berkeley) 5/27/95 41 */ 42 43 #include <sys/cdefs.h> 44 __KERNEL_RCSID(0, "$NetBSD: cd9660_vnops.c,v 1.3 2003/06/07 12:00:07 reinoud Exp $"); 45 46 #include <sys/param.h> 47 #include <sys/systm.h> 48 #include <sys/namei.h> 49 #include <sys/resourcevar.h> 50 #include <sys/kernel.h> 51 #include <sys/file.h> 52 #include <sys/stat.h> 53 #include <sys/buf.h> 54 #include <sys/proc.h> 55 #include <sys/mount.h> 56 #include <sys/vnode.h> 57 #include <sys/malloc.h> 58 #include <sys/dirent.h> 59 60 #include <miscfs/fifofs/fifo.h> 61 #include <miscfs/genfs/genfs.h> 62 #include <miscfs/specfs/specdev.h> 63 64 #include <fs/cd9660/iso.h> 65 #include <fs/cd9660/cd9660_extern.h> 66 #include <fs/cd9660/cd9660_node.h> 67 #include <fs/cd9660/iso_rrip.h> 68 #include <fs/cd9660/cd9660_mount.h> 69 70 /* 71 * Structure for reading directories 72 */ 73 struct isoreaddir { 74 struct dirent saveent; 75 struct dirent assocent; 76 struct dirent current; 77 off_t saveoff; 78 off_t assocoff; 79 off_t curroff; 80 struct uio *uio; 81 off_t uio_off; 82 int eofflag; 83 off_t *cookies; 84 int ncookies; 85 }; 86 87 int iso_uiodir __P((struct isoreaddir *, struct dirent *, off_t)); 88 int iso_shipdir __P((struct isoreaddir *)); 89 90 #if 0 91 /* 92 * Mknod vnode call 93 * Actually remap the device number 94 */ 95 int 96 cd9660_mknod(ndp, vap, cred, p) 97 struct nameidata *ndp; 98 struct ucred *cred; 99 struct vattr *vap; 100 struct proc *p; 101 { 102 #ifndef ISODEVMAP 103 free(ndp->ni_pnbuf, M_NAMEI); 104 vput(ndp->ni_dvp); 105 vput(ndp->ni_vp); 106 return (EINVAL); 107 #else 108 struct vnode *vp; 109 struct iso_node *ip; 110 struct iso_dnode *dp; 111 112 vp = ndp->ni_vp; 113 ip = VTOI(vp); 114 115 if (ip->i_mnt->iso_ftype != ISO_FTYPE_RRIP 116 || vap->va_type != vp->v_type 117 || (vap->va_type != VCHR && vap->va_type != VBLK)) { 118 free(ndp->ni_pnbuf, M_NAMEI); 119 vput(ndp->ni_dvp); 120 vput(ndp->ni_vp); 121 return (EINVAL); 122 } 123 124 dp = iso_dmap(ip->i_dev, ip->i_number, 1); 125 if (ip->inode.iso_rdev == vap->va_rdev || 126 vap->va_rdev == (dev_t)VNOVAL) { 127 /* same as the unmapped one, delete the mapping */ 128 LIST_REMOVE(dp, d_hash); 129 FREE(dp, M_CACHE); 130 } else 131 /* enter new mapping */ 132 dp->d_dev = vap->va_rdev; 133 134 /* 135 * Remove inode so that it will be reloaded by iget and 136 * checked to see if it is an alias of an existing entry 137 * in the inode cache. 138 */ 139 vput(vp); 140 vp->v_type = VNON; 141 vgone(vp); 142 return (0); 143 #endif 144 } 145 #endif 146 147 /* 148 * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC. 149 * The mode is shifted to select the owner/group/other fields. The 150 * super user is granted all permissions. 151 */ 152 int 153 cd9660_access(v) 154 void *v; 155 { 156 struct vop_access_args /* { 157 struct vnode *a_vp; 158 int a_mode; 159 struct ucred *a_cred; 160 struct proc *a_p; 161 } */ *ap = v; 162 struct vnode *vp = ap->a_vp; 163 struct iso_node *ip = VTOI(vp); 164 165 /* 166 * Disallow write attempts unless the file is a socket, 167 * fifo, or a block or character device resident on the 168 * file system. 169 */ 170 if (ap->a_mode & VWRITE) { 171 switch (vp->v_type) { 172 case VDIR: 173 case VLNK: 174 case VREG: 175 return (EROFS); 176 default: 177 break; 178 } 179 } 180 181 return (vaccess(vp->v_type, ip->inode.iso_mode & ALLPERMS, 182 ip->inode.iso_uid, ip->inode.iso_gid, ap->a_mode, ap->a_cred)); 183 } 184 185 int 186 cd9660_getattr(v) 187 void *v; 188 { 189 struct vop_getattr_args /* { 190 struct vnode *a_vp; 191 struct vattr *a_vap; 192 struct ucred *a_cred; 193 struct proc *a_p; 194 } */ *ap = v; 195 struct vnode *vp = ap->a_vp; 196 struct iso_node *ip = VTOI(vp); 197 struct vattr *vap = ap->a_vap; 198 199 vap->va_fsid = ip->i_dev; 200 vap->va_fileid = ip->i_number; 201 202 vap->va_mode = ip->inode.iso_mode & ALLPERMS; 203 vap->va_nlink = ip->inode.iso_links; 204 vap->va_uid = ip->inode.iso_uid; 205 vap->va_gid = ip->inode.iso_gid; 206 vap->va_atime = ip->inode.iso_atime; 207 vap->va_mtime = ip->inode.iso_mtime; 208 vap->va_ctime = ip->inode.iso_ctime; 209 vap->va_rdev = ip->inode.iso_rdev; 210 211 vap->va_size = (u_quad_t) ip->i_size; 212 if (ip->i_size == 0 && vp->v_type == VLNK) { 213 struct vop_readlink_args rdlnk; 214 struct iovec aiov; 215 struct uio auio; 216 char *cp; 217 218 MALLOC(cp, char *, MAXPATHLEN, M_TEMP, M_WAITOK); 219 aiov.iov_base = cp; 220 aiov.iov_len = MAXPATHLEN; 221 auio.uio_iov = &aiov; 222 auio.uio_iovcnt = 1; 223 auio.uio_offset = 0; 224 auio.uio_rw = UIO_READ; 225 auio.uio_segflg = UIO_SYSSPACE; 226 auio.uio_procp = ap->a_p; 227 auio.uio_resid = MAXPATHLEN; 228 rdlnk.a_uio = &auio; 229 rdlnk.a_vp = ap->a_vp; 230 rdlnk.a_cred = ap->a_cred; 231 if (cd9660_readlink(&rdlnk) == 0) 232 vap->va_size = MAXPATHLEN - auio.uio_resid; 233 FREE(cp, M_TEMP); 234 } 235 vap->va_flags = 0; 236 vap->va_gen = 1; 237 vap->va_blocksize = ip->i_mnt->logical_block_size; 238 vap->va_bytes = (u_quad_t) ip->i_size; 239 vap->va_type = vp->v_type; 240 return (0); 241 } 242 243 /* 244 * Vnode op for reading. 245 */ 246 int 247 cd9660_read(v) 248 void *v; 249 { 250 struct vop_read_args /* { 251 struct vnode *a_vp; 252 struct uio *a_uio; 253 int a_ioflag; 254 struct ucred *a_cred; 255 } */ *ap = v; 256 struct vnode *vp = ap->a_vp; 257 struct uio *uio = ap->a_uio; 258 struct iso_node *ip = VTOI(vp); 259 struct iso_mnt *imp; 260 struct buf *bp; 261 daddr_t lbn, rablock; 262 off_t diff; 263 int rasize, error = 0; 264 long size, n, on; 265 266 if (uio->uio_resid == 0) 267 return (0); 268 if (uio->uio_offset < 0) 269 return (EINVAL); 270 if (uio->uio_offset >= ip->i_size) 271 return 0; 272 ip->i_flag |= IN_ACCESS; 273 imp = ip->i_mnt; 274 275 if (vp->v_type == VREG) { 276 error = 0; 277 while (uio->uio_resid > 0) { 278 void *win; 279 vsize_t bytelen = MIN(ip->i_size - uio->uio_offset, 280 uio->uio_resid); 281 282 if (bytelen == 0) 283 break; 284 win = ubc_alloc(&vp->v_uobj, uio->uio_offset, 285 &bytelen, UBC_READ); 286 error = uiomove(win, bytelen, uio); 287 ubc_release(win, 0); 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((caddr_t)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 = VOP_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 = VOP_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 MALLOC(symname, char *, MAXPATHLEN, M_NAMEI, M_WAITOK); 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 FREE(symname, M_NAMEI); 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 FREE(symname, M_NAMEI); 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 buf *a_bp; 753 } */ *ap = v; 754 struct buf *bp = ap->a_bp; 755 struct vnode *vp = bp->b_vp; 756 struct iso_node *ip; 757 int error; 758 759 ip = VTOI(vp); 760 if (vp->v_type == VBLK || vp->v_type == VCHR) 761 panic("cd9660_strategy: spec"); 762 if (bp->b_blkno == bp->b_lblkno) { 763 error = VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL); 764 if (error) { 765 bp->b_error = error; 766 bp->b_flags |= B_ERROR; 767 biodone(bp); 768 return (error); 769 } 770 if ((long)bp->b_blkno == -1) 771 clrbuf(bp); 772 } 773 if ((long)bp->b_blkno == -1) { 774 biodone(bp); 775 return (0); 776 } 777 vp = ip->i_devvp; 778 bp->b_dev = vp->v_rdev; 779 VOCALL (vp->v_op, VOFFSET(vop_strategy), ap); 780 return (0); 781 } 782 783 /* 784 * Print out the contents of an inode. 785 */ 786 /*ARGSUSED*/ 787 int 788 cd9660_print(v) 789 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 struct ucred *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 ) 883 return EOPNOTSUPP; 884 885 return VOP_TRUNCATE(vp, vap->va_size, 0, ap->a_cred, ap->a_p); 886 } 887 888 /* 889 * Global vfs data structures for isofs 890 */ 891 #define cd9660_create genfs_eopnotsupp 892 #define cd9660_mknod genfs_eopnotsupp 893 #define cd9660_write genfs_eopnotsupp 894 #define cd9660_lease_check genfs_lease_check 895 #define cd9660_fsync genfs_nullop 896 #define cd9660_remove genfs_eopnotsupp 897 #define cd9660_rename genfs_eopnotsupp 898 #define cd9660_mkdir genfs_eopnotsupp 899 #define cd9660_rmdir genfs_eopnotsupp 900 #define cd9660_advlock genfs_einval 901 #define cd9660_valloc genfs_eopnotsupp 902 #define cd9660_vfree genfs_nullop 903 #define cd9660_truncate genfs_eopnotsupp 904 #define cd9660_update genfs_nullop 905 #define cd9660_bwrite genfs_eopnotsupp 906 #define cd9660_revoke genfs_revoke 907 908 /* 909 * Global vfs data structures for cd9660 910 */ 911 int (**cd9660_vnodeop_p) __P((void *)); 912 const struct vnodeopv_entry_desc cd9660_vnodeop_entries[] = { 913 { &vop_default_desc, vn_default_error }, 914 { &vop_lookup_desc, cd9660_lookup }, /* lookup */ 915 { &vop_create_desc, cd9660_create }, /* create */ 916 { &vop_mknod_desc, cd9660_mknod }, /* mknod */ 917 { &vop_open_desc, cd9660_open }, /* open */ 918 { &vop_close_desc, cd9660_close }, /* close */ 919 { &vop_access_desc, cd9660_access }, /* access */ 920 { &vop_getattr_desc, cd9660_getattr }, /* getattr */ 921 { &vop_setattr_desc, cd9660_setattr }, /* setattr */ 922 { &vop_read_desc, cd9660_read }, /* read */ 923 { &vop_write_desc, cd9660_write }, /* write */ 924 { &vop_lease_desc, cd9660_lease_check }, /* lease */ 925 { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */ 926 { &vop_ioctl_desc, cd9660_ioctl }, /* ioctl */ 927 { &vop_poll_desc, cd9660_poll }, /* poll */ 928 { &vop_revoke_desc, cd9660_revoke }, /* revoke */ 929 { &vop_mmap_desc, cd9660_mmap }, /* mmap */ 930 { &vop_fsync_desc, cd9660_fsync }, /* fsync */ 931 { &vop_seek_desc, cd9660_seek }, /* seek */ 932 { &vop_remove_desc, cd9660_remove }, /* remove */ 933 { &vop_link_desc, cd9660_link }, /* link */ 934 { &vop_rename_desc, cd9660_rename }, /* rename */ 935 { &vop_mkdir_desc, cd9660_mkdir }, /* mkdir */ 936 { &vop_rmdir_desc, cd9660_rmdir }, /* rmdir */ 937 { &vop_symlink_desc, cd9660_symlink }, /* symlink */ 938 { &vop_readdir_desc, cd9660_readdir }, /* readdir */ 939 { &vop_readlink_desc, cd9660_readlink }, /* readlink */ 940 { &vop_abortop_desc, cd9660_abortop }, /* abortop */ 941 { &vop_inactive_desc, cd9660_inactive }, /* inactive */ 942 { &vop_reclaim_desc, cd9660_reclaim }, /* reclaim */ 943 { &vop_lock_desc, genfs_lock }, /* lock */ 944 { &vop_unlock_desc, genfs_unlock }, /* unlock */ 945 { &vop_bmap_desc, cd9660_bmap }, /* bmap */ 946 { &vop_strategy_desc, cd9660_strategy }, /* strategy */ 947 { &vop_print_desc, cd9660_print }, /* print */ 948 { &vop_islocked_desc, genfs_islocked }, /* islocked */ 949 { &vop_pathconf_desc, cd9660_pathconf }, /* pathconf */ 950 { &vop_advlock_desc, cd9660_advlock }, /* advlock */ 951 { &vop_blkatoff_desc, cd9660_blkatoff }, /* blkatoff */ 952 { &vop_valloc_desc, cd9660_valloc }, /* valloc */ 953 { &vop_vfree_desc, cd9660_vfree }, /* vfree */ 954 { &vop_truncate_desc, cd9660_truncate }, /* truncate */ 955 { &vop_update_desc, cd9660_update }, /* update */ 956 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 957 { &vop_getpages_desc, genfs_getpages }, /* getpages */ 958 { &vop_putpages_desc, genfs_putpages }, /* putpages */ 959 { NULL, NULL } 960 }; 961 const struct vnodeopv_desc cd9660_vnodeop_opv_desc = 962 { &cd9660_vnodeop_p, cd9660_vnodeop_entries }; 963 964 /* 965 * Special device vnode ops 966 */ 967 int (**cd9660_specop_p) __P((void *)); 968 const struct vnodeopv_entry_desc cd9660_specop_entries[] = { 969 { &vop_default_desc, vn_default_error }, 970 { &vop_lookup_desc, spec_lookup }, /* lookup */ 971 { &vop_create_desc, spec_create }, /* create */ 972 { &vop_mknod_desc, spec_mknod }, /* mknod */ 973 { &vop_open_desc, spec_open }, /* open */ 974 { &vop_close_desc, spec_close }, /* close */ 975 { &vop_access_desc, cd9660_access }, /* access */ 976 { &vop_getattr_desc, cd9660_getattr }, /* getattr */ 977 { &vop_setattr_desc, cd9660_setattr }, /* setattr */ 978 { &vop_read_desc, spec_read }, /* read */ 979 { &vop_write_desc, spec_write }, /* write */ 980 { &vop_lease_desc, spec_lease_check }, /* lease */ 981 { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */ 982 { &vop_ioctl_desc, spec_ioctl }, /* ioctl */ 983 { &vop_poll_desc, spec_poll }, /* poll */ 984 { &vop_kqfilter_desc, spec_kqfilter }, /* kqfilter */ 985 { &vop_revoke_desc, spec_revoke }, /* revoke */ 986 { &vop_mmap_desc, spec_mmap }, /* mmap */ 987 { &vop_fsync_desc, spec_fsync }, /* fsync */ 988 { &vop_seek_desc, spec_seek }, /* seek */ 989 { &vop_remove_desc, spec_remove }, /* remove */ 990 { &vop_link_desc, spec_link }, /* link */ 991 { &vop_rename_desc, spec_rename }, /* rename */ 992 { &vop_mkdir_desc, spec_mkdir }, /* mkdir */ 993 { &vop_rmdir_desc, spec_rmdir }, /* rmdir */ 994 { &vop_symlink_desc, spec_symlink }, /* symlink */ 995 { &vop_readdir_desc, spec_readdir }, /* readdir */ 996 { &vop_readlink_desc, spec_readlink }, /* readlink */ 997 { &vop_abortop_desc, spec_abortop }, /* abortop */ 998 { &vop_inactive_desc, cd9660_inactive }, /* inactive */ 999 { &vop_reclaim_desc, cd9660_reclaim }, /* reclaim */ 1000 { &vop_lock_desc, genfs_lock }, /* lock */ 1001 { &vop_unlock_desc, genfs_unlock }, /* unlock */ 1002 { &vop_bmap_desc, spec_bmap }, /* bmap */ 1003 { &vop_strategy_desc, spec_strategy }, /* strategy */ 1004 { &vop_print_desc, cd9660_print }, /* print */ 1005 { &vop_islocked_desc, genfs_islocked }, /* islocked */ 1006 { &vop_pathconf_desc, spec_pathconf }, /* pathconf */ 1007 { &vop_advlock_desc, spec_advlock }, /* advlock */ 1008 { &vop_blkatoff_desc, spec_blkatoff }, /* blkatoff */ 1009 { &vop_valloc_desc, spec_valloc }, /* valloc */ 1010 { &vop_vfree_desc, spec_vfree }, /* vfree */ 1011 { &vop_truncate_desc, spec_truncate }, /* truncate */ 1012 { &vop_update_desc, cd9660_update }, /* update */ 1013 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 1014 { &vop_getpages_desc, spec_getpages }, /* getpages */ 1015 { &vop_putpages_desc, spec_putpages }, /* putpages */ 1016 { NULL, NULL } 1017 }; 1018 const struct vnodeopv_desc cd9660_specop_opv_desc = 1019 { &cd9660_specop_p, cd9660_specop_entries }; 1020 1021 int (**cd9660_fifoop_p) __P((void *)); 1022 const struct vnodeopv_entry_desc cd9660_fifoop_entries[] = { 1023 { &vop_default_desc, vn_default_error }, 1024 { &vop_lookup_desc, fifo_lookup }, /* lookup */ 1025 { &vop_create_desc, fifo_create }, /* create */ 1026 { &vop_mknod_desc, fifo_mknod }, /* mknod */ 1027 { &vop_open_desc, fifo_open }, /* open */ 1028 { &vop_close_desc, fifo_close }, /* close */ 1029 { &vop_access_desc, cd9660_access }, /* access */ 1030 { &vop_getattr_desc, cd9660_getattr }, /* getattr */ 1031 { &vop_setattr_desc, cd9660_setattr }, /* setattr */ 1032 { &vop_read_desc, fifo_read }, /* read */ 1033 { &vop_write_desc, fifo_write }, /* write */ 1034 { &vop_lease_desc, fifo_lease_check }, /* lease */ 1035 { &vop_fcntl_desc, genfs_fcntl }, /* fcntl */ 1036 { &vop_ioctl_desc, fifo_ioctl }, /* ioctl */ 1037 { &vop_poll_desc, fifo_poll }, /* poll */ 1038 { &vop_kqfilter_desc, fifo_kqfilter }, /* kqfilter */ 1039 { &vop_revoke_desc, fifo_revoke }, /* revoke */ 1040 { &vop_mmap_desc, fifo_mmap }, /* mmap */ 1041 { &vop_fsync_desc, fifo_fsync }, /* fsync */ 1042 { &vop_seek_desc, fifo_seek }, /* seek */ 1043 { &vop_remove_desc, fifo_remove }, /* remove */ 1044 { &vop_link_desc, fifo_link } , /* link */ 1045 { &vop_rename_desc, fifo_rename }, /* rename */ 1046 { &vop_mkdir_desc, fifo_mkdir }, /* mkdir */ 1047 { &vop_rmdir_desc, fifo_rmdir }, /* rmdir */ 1048 { &vop_symlink_desc, fifo_symlink }, /* symlink */ 1049 { &vop_readdir_desc, fifo_readdir }, /* readdir */ 1050 { &vop_readlink_desc, fifo_readlink }, /* readlink */ 1051 { &vop_abortop_desc, fifo_abortop }, /* abortop */ 1052 { &vop_inactive_desc, cd9660_inactive }, /* inactive */ 1053 { &vop_reclaim_desc, cd9660_reclaim }, /* reclaim */ 1054 { &vop_lock_desc, genfs_lock }, /* lock */ 1055 { &vop_unlock_desc, genfs_unlock }, /* unlock */ 1056 { &vop_bmap_desc, fifo_bmap }, /* bmap */ 1057 { &vop_strategy_desc, fifo_strategy }, /* strategy */ 1058 { &vop_print_desc, cd9660_print }, /* print */ 1059 { &vop_islocked_desc, genfs_islocked }, /* islocked */ 1060 { &vop_pathconf_desc, fifo_pathconf }, /* pathconf */ 1061 { &vop_advlock_desc, fifo_advlock }, /* advlock */ 1062 { &vop_blkatoff_desc, fifo_blkatoff }, /* blkatoff */ 1063 { &vop_valloc_desc, fifo_valloc }, /* valloc */ 1064 { &vop_vfree_desc, fifo_vfree }, /* vfree */ 1065 { &vop_truncate_desc, fifo_truncate }, /* truncate */ 1066 { &vop_update_desc, cd9660_update }, /* update */ 1067 { &vop_bwrite_desc, vn_bwrite }, /* bwrite */ 1068 { &vop_putpages_desc, fifo_putpages }, /* putpages */ 1069 { NULL, NULL } 1070 }; 1071 const struct vnodeopv_desc cd9660_fifoop_opv_desc = 1072 { &cd9660_fifoop_p, cd9660_fifoop_entries }; 1073