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