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