1df8bae1dSRodney W. Grimes /*- 251369649SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 351369649SPedro F. Giffuni * 4df8bae1dSRodney W. Grimes * Copyright (c) 1994 5df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 6df8bae1dSRodney W. Grimes * 7df8bae1dSRodney W. Grimes * This code is derived from software contributed to Berkeley 8df8bae1dSRodney W. Grimes * by Pace Willisson (pace@blitz.com). The Rock Ridge Extension 9df8bae1dSRodney W. Grimes * Support code is derived from software contributed to Berkeley 10df8bae1dSRodney W. Grimes * by Atsushi Murai (amurai@spec.co.jp). 11df8bae1dSRodney W. Grimes * 12df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 13df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 14df8bae1dSRodney W. Grimes * are met: 15df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 16df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 17df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 18df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 19df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 20fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 21df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 22df8bae1dSRodney W. Grimes * without specific prior written permission. 23df8bae1dSRodney W. Grimes * 24df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34df8bae1dSRodney W. Grimes * SUCH DAMAGE. 35df8bae1dSRodney W. Grimes * 36996c772fSJohn Dyson * @(#)cd9660_vnops.c 8.19 (Berkeley) 5/27/95 37df8bae1dSRodney W. Grimes */ 38df8bae1dSRodney W. Grimes 398c9bbf48SDavid E. O'Brien #include <sys/cdefs.h> 408c9bbf48SDavid E. O'Brien __FBSDID("$FreeBSD$"); 418c9bbf48SDavid E. O'Brien 42df8bae1dSRodney W. Grimes #include <sys/param.h> 43df8bae1dSRodney W. Grimes #include <sys/systm.h> 44df8bae1dSRodney W. Grimes #include <sys/namei.h> 45df8bae1dSRodney W. Grimes #include <sys/kernel.h> 46dfb9f846SPoul-Henning Kamp #include <sys/conf.h> 47df8bae1dSRodney W. Grimes #include <sys/stat.h> 489626b608SPoul-Henning Kamp #include <sys/bio.h> 49df8bae1dSRodney W. Grimes #include <sys/buf.h> 50df8bae1dSRodney W. Grimes #include <sys/mount.h> 51df8bae1dSRodney W. Grimes #include <sys/vnode.h> 52df8bae1dSRodney W. Grimes #include <sys/malloc.h> 53c90607baSBruce Evans #include <sys/dirent.h> 54996c772fSJohn Dyson #include <sys/unistd.h> 55cb2a8dffSSøren Schmidt #include <sys/filio.h> 56c329ee71SKonstantin Belousov #include <sys/sysctl.h> 57df8bae1dSRodney W. Grimes 58651ae11eSMike Smith #include <vm/vm.h> 59651ae11eSMike Smith #include <vm/vnode_pager.h> 602684b6afSJeff Roberson #include <vm/uma.h> 61675ea6f0SBruce Evans 62a8d36d0dSCraig Rodrigues #include <fs/cd9660/iso.h> 63a8d36d0dSCraig Rodrigues #include <fs/cd9660/cd9660_node.h> 64a8d36d0dSCraig Rodrigues #include <fs/cd9660/iso_rrip.h> 65df8bae1dSRodney W. Grimes 666fde64c7SPoul-Henning Kamp static vop_setattr_t cd9660_setattr; 6772b3e305SPeter Edwards static vop_open_t cd9660_open; 686fde64c7SPoul-Henning Kamp static vop_access_t cd9660_access; 696fde64c7SPoul-Henning Kamp static vop_getattr_t cd9660_getattr; 706fde64c7SPoul-Henning Kamp static vop_ioctl_t cd9660_ioctl; 716fde64c7SPoul-Henning Kamp static vop_pathconf_t cd9660_pathconf; 726fde64c7SPoul-Henning Kamp static vop_read_t cd9660_read; 7310dd32cdSBruce Evans struct isoreaddir; 7489c9a483SAlfred Perlstein static int iso_uiodir(struct isoreaddir *idp, struct dirent *dp, off_t off); 7589c9a483SAlfred Perlstein static int iso_shipdir(struct isoreaddir *idp); 766fde64c7SPoul-Henning Kamp static vop_readdir_t cd9660_readdir; 776fde64c7SPoul-Henning Kamp static vop_readlink_t cd9660_readlink; 786fde64c7SPoul-Henning Kamp static vop_strategy_t cd9660_strategy; 7910bcafe9SPawel Jakub Dawidek static vop_vptofh_t cd9660_vptofh; 80c329ee71SKonstantin Belousov static vop_getpages_t cd9660_getpages; 8110dd32cdSBruce Evans 82df8bae1dSRodney W. Grimes /* 83de8583ceSDavid Greenman * Setattr call. Only allowed for block and character special devices. 84de8583ceSDavid Greenman */ 8537c84183SPoul-Henning Kamp static int 86de8583ceSDavid Greenman cd9660_setattr(ap) 87de8583ceSDavid Greenman struct vop_setattr_args /* { 88de8583ceSDavid Greenman struct vnodeop_desc *a_desc; 89de8583ceSDavid Greenman struct vnode *a_vp; 90de8583ceSDavid Greenman struct vattr *a_vap; 91de8583ceSDavid Greenman struct ucred *a_cred; 92de8583ceSDavid Greenman } */ *ap; 93de8583ceSDavid Greenman { 94de8583ceSDavid Greenman struct vnode *vp = ap->a_vp; 95de8583ceSDavid Greenman struct vattr *vap = ap->a_vap; 96de8583ceSDavid Greenman 9792579404SAlexander Langer if (vap->va_flags != (u_long)VNOVAL || vap->va_uid != (uid_t)VNOVAL || 9895a1574eSNate Williams vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL || 9995a1574eSNate Williams vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL) 100de8583ceSDavid Greenman return (EROFS); 10192579404SAlexander Langer if (vap->va_size != (u_quad_t)VNOVAL) { 102de8583ceSDavid Greenman switch (vp->v_type) { 103de8583ceSDavid Greenman case VDIR: 104de8583ceSDavid Greenman return (EISDIR); 105de8583ceSDavid Greenman case VLNK: 106de8583ceSDavid Greenman case VREG: 107de8583ceSDavid Greenman return (EROFS); 108de8583ceSDavid Greenman case VCHR: 109de8583ceSDavid Greenman case VBLK: 110de8583ceSDavid Greenman case VSOCK: 111de8583ceSDavid Greenman case VFIFO: 112d254af07SMatthew Dillon case VNON: 113d254af07SMatthew Dillon case VBAD: 11482be0a5aSTor Egge case VMARKER: 115de8583ceSDavid Greenman return (0); 116de8583ceSDavid Greenman } 117de8583ceSDavid Greenman } 118996c772fSJohn Dyson return (0); 119de8583ceSDavid Greenman } 120de8583ceSDavid Greenman 121de8583ceSDavid Greenman /* 122df8bae1dSRodney W. Grimes * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC. 123df8bae1dSRodney W. Grimes * The mode is shifted to select the owner/group/other fields. The 124df8bae1dSRodney W. Grimes * super user is granted all permissions. 125df8bae1dSRodney W. Grimes */ 126df8bae1dSRodney W. Grimes /* ARGSUSED */ 127605e9724SPoul-Henning Kamp static int 128df8bae1dSRodney W. Grimes cd9660_access(ap) 129df8bae1dSRodney W. Grimes struct vop_access_args /* { 130df8bae1dSRodney W. Grimes struct vnode *a_vp; 13115bc6b2bSEdward Tomasz Napierala accmode_t a_accmode; 132df8bae1dSRodney W. Grimes struct ucred *a_cred; 133b40ce416SJulian Elischer struct thread *a_td; 134df8bae1dSRodney W. Grimes } */ *ap; 135df8bae1dSRodney W. Grimes { 136996c772fSJohn Dyson struct vnode *vp = ap->a_vp; 137996c772fSJohn Dyson struct iso_node *ip = VTOI(vp); 13815bc6b2bSEdward Tomasz Napierala accmode_t accmode = ap->a_accmode; 139996c772fSJohn Dyson 140bc710003SPoul-Henning Kamp if (vp->v_type == VCHR || vp->v_type == VBLK) 141a3679878SPoul-Henning Kamp return (EOPNOTSUPP); 142a3679878SPoul-Henning Kamp 143ba14c327SDavid Greenman /* 144996c772fSJohn Dyson * Disallow write attempts unless the file is a socket, 145996c772fSJohn Dyson * fifo, or a block or character device resident on the 146996c772fSJohn Dyson * filesystem. 147ba14c327SDavid Greenman */ 14815bc6b2bSEdward Tomasz Napierala if (accmode & VWRITE) { 149996c772fSJohn Dyson switch (vp->v_type) { 150ba14c327SDavid Greenman case VDIR: 151ba14c327SDavid Greenman case VLNK: 152ba14c327SDavid Greenman case VREG: 153ba14c327SDavid Greenman return (EROFS); 154d254af07SMatthew Dillon /* NOT REACHED */ 155d254af07SMatthew Dillon default: 156d254af07SMatthew Dillon break; 157ba14c327SDavid Greenman } 158ba14c327SDavid Greenman } 159ba14c327SDavid Greenman 160e39c53edSPoul-Henning Kamp return (vaccess(vp->v_type, ip->inode.iso_mode, ip->inode.iso_uid, 16115bc6b2bSEdward Tomasz Napierala ip->inode.iso_gid, ap->a_accmode, ap->a_cred, NULL)); 162df8bae1dSRodney W. Grimes } 163df8bae1dSRodney W. Grimes 164605e9724SPoul-Henning Kamp static int 16572b3e305SPeter Edwards cd9660_open(ap) 16672b3e305SPeter Edwards struct vop_open_args /* { 16772b3e305SPeter Edwards struct vnode *a_vp; 16872b3e305SPeter Edwards int a_mode; 16972b3e305SPeter Edwards struct ucred *a_cred; 17072b3e305SPeter Edwards struct thread *a_td; 171d6da6408SKonstantin Belousov struct file *a_fp; 17272b3e305SPeter Edwards } */ *ap; 17372b3e305SPeter Edwards { 17404c98d46SJohn Baldwin struct vnode *vp = ap->a_vp; 17504c98d46SJohn Baldwin struct iso_node *ip = VTOI(vp); 17672b3e305SPeter Edwards 17704c98d46SJohn Baldwin if (vp->v_type == VCHR || vp->v_type == VBLK) 17804c98d46SJohn Baldwin return (EOPNOTSUPP); 17904c98d46SJohn Baldwin 18004c98d46SJohn Baldwin vnode_create_vobject(vp, ip->i_size, ap->a_td); 18104c98d46SJohn Baldwin return (0); 18272b3e305SPeter Edwards } 18372b3e305SPeter Edwards 18472b3e305SPeter Edwards 18572b3e305SPeter Edwards static int 186df8bae1dSRodney W. Grimes cd9660_getattr(ap) 187df8bae1dSRodney W. Grimes struct vop_getattr_args /* { 188df8bae1dSRodney W. Grimes struct vnode *a_vp; 189df8bae1dSRodney W. Grimes struct vattr *a_vap; 190df8bae1dSRodney W. Grimes struct ucred *a_cred; 191df8bae1dSRodney W. Grimes } */ *ap; 192df8bae1dSRodney W. Grimes 193df8bae1dSRodney W. Grimes { 194df8bae1dSRodney W. Grimes struct vnode *vp = ap->a_vp; 1958994a245SDag-Erling Smørgrav struct vattr *vap = ap->a_vap; 1968994a245SDag-Erling Smørgrav struct iso_node *ip = VTOI(vp); 197df8bae1dSRodney W. Grimes 198e3b803b1SPoul-Henning Kamp vap->va_fsid = dev2udev(ip->i_mnt->im_dev); 19982c0aec8STim J. Robbins vap->va_fileid = ip->i_number; 200df8bae1dSRodney W. Grimes 201df8bae1dSRodney W. Grimes vap->va_mode = ip->inode.iso_mode; 202df8bae1dSRodney W. Grimes vap->va_nlink = ip->inode.iso_links; 203df8bae1dSRodney W. Grimes vap->va_uid = ip->inode.iso_uid; 204df8bae1dSRodney W. Grimes vap->va_gid = ip->inode.iso_gid; 205df8bae1dSRodney W. Grimes vap->va_atime = ip->inode.iso_atime; 206df8bae1dSRodney W. Grimes vap->va_mtime = ip->inode.iso_mtime; 207df8bae1dSRodney W. Grimes vap->va_ctime = ip->inode.iso_ctime; 208df8bae1dSRodney W. Grimes vap->va_rdev = ip->inode.iso_rdev; 209df8bae1dSRodney W. Grimes 210df8bae1dSRodney W. Grimes vap->va_size = (u_quad_t) ip->i_size; 211996c772fSJohn Dyson if (ip->i_size == 0 && (vap->va_mode & S_IFMT) == S_IFLNK) { 212996c772fSJohn Dyson struct vop_readlink_args rdlnk; 213996c772fSJohn Dyson struct iovec aiov; 214996c772fSJohn Dyson struct uio auio; 215996c772fSJohn Dyson char *cp; 216996c772fSJohn Dyson 2171ede983cSDag-Erling Smørgrav cp = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 218996c772fSJohn Dyson aiov.iov_base = cp; 219996c772fSJohn Dyson aiov.iov_len = MAXPATHLEN; 220996c772fSJohn Dyson auio.uio_iov = &aiov; 221996c772fSJohn Dyson auio.uio_iovcnt = 1; 222996c772fSJohn Dyson auio.uio_offset = 0; 223996c772fSJohn Dyson auio.uio_rw = UIO_READ; 224996c772fSJohn Dyson auio.uio_segflg = UIO_SYSSPACE; 2250359a12eSAttilio Rao auio.uio_td = curthread; 226996c772fSJohn Dyson auio.uio_resid = MAXPATHLEN; 227996c772fSJohn Dyson rdlnk.a_uio = &auio; 228996c772fSJohn Dyson rdlnk.a_vp = ap->a_vp; 229996c772fSJohn Dyson rdlnk.a_cred = ap->a_cred; 230996c772fSJohn Dyson if (cd9660_readlink(&rdlnk) == 0) 231996c772fSJohn Dyson vap->va_size = MAXPATHLEN - auio.uio_resid; 2321ede983cSDag-Erling Smørgrav free(cp, M_TEMP); 233996c772fSJohn Dyson } 234df8bae1dSRodney W. Grimes vap->va_flags = 0; 235df8bae1dSRodney W. Grimes vap->va_gen = 1; 236df8bae1dSRodney W. Grimes vap->va_blocksize = ip->i_mnt->logical_block_size; 237df8bae1dSRodney W. Grimes vap->va_bytes = (u_quad_t) ip->i_size; 238df8bae1dSRodney W. Grimes vap->va_type = vp->v_type; 23994a8606fSDoug Rabson vap->va_filerev = 0; 240df8bae1dSRodney W. Grimes return (0); 241df8bae1dSRodney W. Grimes } 242df8bae1dSRodney W. Grimes 243df8bae1dSRodney W. Grimes /* 244cb2a8dffSSøren Schmidt * Vnode op for ioctl. 245cb2a8dffSSøren Schmidt */ 246cb2a8dffSSøren Schmidt static int 247cb2a8dffSSøren Schmidt cd9660_ioctl(ap) 248cb2a8dffSSøren Schmidt struct vop_ioctl_args /* { 249cb2a8dffSSøren Schmidt struct vnode *a_vp; 250bc9d8a9aSPoul-Henning Kamp u_long a_command; 251cb2a8dffSSøren Schmidt caddr_t a_data; 252cb2a8dffSSøren Schmidt int a_fflag; 253cb2a8dffSSøren Schmidt struct ucred *a_cred; 254b40ce416SJulian Elischer struct thread *a_td; 255cb2a8dffSSøren Schmidt } */ *ap; 256cb2a8dffSSøren Schmidt { 257c4df27d5SKonstantin Belousov struct vnode *vp; 258c4df27d5SKonstantin Belousov struct iso_node *ip; 259c4df27d5SKonstantin Belousov int error; 260cb2a8dffSSøren Schmidt 261c4df27d5SKonstantin Belousov vp = ap->a_vp; 262c4df27d5SKonstantin Belousov vn_lock(vp, LK_SHARED | LK_RETRY); 26393bc76dcSKonstantin Belousov if (vp->v_iflag & VI_DOOMED) { 26493bc76dcSKonstantin Belousov VOP_UNLOCK(vp, 0); 26593bc76dcSKonstantin Belousov return (EBADF); 26693bc76dcSKonstantin Belousov } 267c4df27d5SKonstantin Belousov if (vp->v_type == VCHR || vp->v_type == VBLK) { 268c4df27d5SKonstantin Belousov VOP_UNLOCK(vp, 0); 269a3679878SPoul-Henning Kamp return (EOPNOTSUPP); 270c4df27d5SKonstantin Belousov } 271c4df27d5SKonstantin Belousov 272c4df27d5SKonstantin Belousov ip = VTOI(vp); 273c4df27d5SKonstantin Belousov error = 0; 274a3679878SPoul-Henning Kamp 275cb2a8dffSSøren Schmidt switch (ap->a_command) { 276cb2a8dffSSøren Schmidt case FIOGETLBA: 277cb2a8dffSSøren Schmidt *(int *)(ap->a_data) = ip->iso_start; 278c4df27d5SKonstantin Belousov break; 279cb2a8dffSSøren Schmidt default: 280c4df27d5SKonstantin Belousov error = ENOTTY; 281c4df27d5SKonstantin Belousov break; 282cb2a8dffSSøren Schmidt } 283c4df27d5SKonstantin Belousov 284c4df27d5SKonstantin Belousov VOP_UNLOCK(vp, 0); 285c4df27d5SKonstantin Belousov return (error); 286cb2a8dffSSøren Schmidt } 287cb2a8dffSSøren Schmidt 288cb2a8dffSSøren Schmidt /* 289df8bae1dSRodney W. Grimes * Vnode op for reading. 290df8bae1dSRodney W. Grimes */ 291605e9724SPoul-Henning Kamp static int 292df8bae1dSRodney W. Grimes cd9660_read(ap) 293df8bae1dSRodney W. Grimes struct vop_read_args /* { 294df8bae1dSRodney W. Grimes struct vnode *a_vp; 295df8bae1dSRodney W. Grimes struct uio *a_uio; 296df8bae1dSRodney W. Grimes int a_ioflag; 297df8bae1dSRodney W. Grimes struct ucred *a_cred; 298df8bae1dSRodney W. Grimes } */ *ap; 299df8bae1dSRodney W. Grimes { 300df8bae1dSRodney W. Grimes struct vnode *vp = ap->a_vp; 3018994a245SDag-Erling Smørgrav struct uio *uio = ap->a_uio; 3028994a245SDag-Erling Smørgrav struct iso_node *ip = VTOI(vp); 3038994a245SDag-Erling Smørgrav struct iso_mnt *imp; 304df8bae1dSRodney W. Grimes struct buf *bp; 3051295d82eSGary Palmer daddr_t lbn, rablock; 306df8bae1dSRodney W. Grimes off_t diff; 307df8bae1dSRodney W. Grimes int rasize, error = 0; 30867ddfcafSMatthew Dillon int seqcount; 309df8bae1dSRodney W. Grimes long size, n, on; 310df8bae1dSRodney W. Grimes 311bc710003SPoul-Henning Kamp if (vp->v_type == VCHR || vp->v_type == VBLK) 312a3679878SPoul-Henning Kamp return (EOPNOTSUPP); 313a3679878SPoul-Henning Kamp 3146bd39fe9SAlexander Kabaev seqcount = ap->a_ioflag >> IO_SEQSHIFT; 31567ddfcafSMatthew Dillon 316df8bae1dSRodney W. Grimes if (uio->uio_resid == 0) 317df8bae1dSRodney W. Grimes return (0); 318df8bae1dSRodney W. Grimes if (uio->uio_offset < 0) 319df8bae1dSRodney W. Grimes return (EINVAL); 320df8bae1dSRodney W. Grimes imp = ip->i_mnt; 321df8bae1dSRodney W. Grimes do { 322996c772fSJohn Dyson lbn = lblkno(imp, uio->uio_offset); 323996c772fSJohn Dyson on = blkoff(imp, uio->uio_offset); 324ea407244SKonstantin Belousov n = MIN(imp->logical_block_size - on, uio->uio_resid); 325df8bae1dSRodney W. Grimes diff = (off_t)ip->i_size - uio->uio_offset; 326df8bae1dSRodney W. Grimes if (diff <= 0) 327df8bae1dSRodney W. Grimes return (0); 328df8bae1dSRodney W. Grimes if (diff < n) 329df8bae1dSRodney W. Grimes n = diff; 330996c772fSJohn Dyson size = blksize(imp, ip, lbn); 331df8bae1dSRodney W. Grimes rablock = lbn + 1; 33281bca6ddSKATO Takenori if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) { 3335a5573fdSBruce Evans if (lblktosize(imp, rablock) < ip->i_size) 334996c772fSJohn Dyson error = cluster_read(vp, (off_t)ip->i_size, 3358b612c4bSJohn Dyson lbn, size, NOCRED, uio->uio_resid, 336c535690bSKonstantin Belousov (ap->a_ioflag >> 16), 0, &bp); 337df8bae1dSRodney W. Grimes else 338df8bae1dSRodney W. Grimes error = bread(vp, lbn, size, NOCRED, &bp); 339df8bae1dSRodney W. Grimes } else { 34067ddfcafSMatthew Dillon if (seqcount > 1 && 341996c772fSJohn Dyson lblktosize(imp, rablock) < ip->i_size) { 342996c772fSJohn Dyson rasize = blksize(imp, ip, rablock); 343df8bae1dSRodney W. Grimes error = breadn(vp, lbn, size, &rablock, 344df8bae1dSRodney W. Grimes &rasize, 1, NOCRED, &bp); 345df8bae1dSRodney W. Grimes } else 346df8bae1dSRodney W. Grimes error = bread(vp, lbn, size, NOCRED, &bp); 347df8bae1dSRodney W. Grimes } 348cc4916adSKonstantin Belousov if (error != 0) 349df8bae1dSRodney W. Grimes return (error); 350cc4916adSKonstantin Belousov n = MIN(n, size - bp->b_resid); 351df8bae1dSRodney W. Grimes 352996c772fSJohn Dyson error = uiomove(bp->b_data + on, (int)n, uio); 353df8bae1dSRodney W. Grimes brelse(bp); 354df8bae1dSRodney W. Grimes } while (error == 0 && uio->uio_resid > 0 && n != 0); 355df8bae1dSRodney W. Grimes return (error); 356df8bae1dSRodney W. Grimes } 357df8bae1dSRodney W. Grimes 358df8bae1dSRodney W. Grimes /* 359df8bae1dSRodney W. Grimes * Structure for reading directories 360df8bae1dSRodney W. Grimes */ 361df8bae1dSRodney W. Grimes struct isoreaddir { 362df8bae1dSRodney W. Grimes struct dirent saveent; 363df8bae1dSRodney W. Grimes struct dirent assocent; 364df8bae1dSRodney W. Grimes struct dirent current; 365df8bae1dSRodney W. Grimes off_t saveoff; 366df8bae1dSRodney W. Grimes off_t assocoff; 367df8bae1dSRodney W. Grimes off_t curroff; 368df8bae1dSRodney W. Grimes struct uio *uio; 369df8bae1dSRodney W. Grimes off_t uio_off; 370996c772fSJohn Dyson int eofflag; 371996c772fSJohn Dyson u_long *cookies; 372df8bae1dSRodney W. Grimes int ncookies; 373df8bae1dSRodney W. Grimes }; 374df8bae1dSRodney W. Grimes 37537c84183SPoul-Henning Kamp static int 376df8bae1dSRodney W. Grimes iso_uiodir(idp,dp,off) 377df8bae1dSRodney W. Grimes struct isoreaddir *idp; 378df8bae1dSRodney W. Grimes struct dirent *dp; 379df8bae1dSRodney W. Grimes off_t off; 380df8bae1dSRodney W. Grimes { 381df8bae1dSRodney W. Grimes int error; 382df8bae1dSRodney W. Grimes 383df8bae1dSRodney W. Grimes dp->d_name[dp->d_namlen] = 0; 384c90607baSBruce Evans dp->d_reclen = GENERIC_DIRSIZ(dp); 385df8bae1dSRodney W. Grimes 386df8bae1dSRodney W. Grimes if (idp->uio->uio_resid < dp->d_reclen) { 387996c772fSJohn Dyson idp->eofflag = 0; 388996c772fSJohn Dyson return (-1); 389df8bae1dSRodney W. Grimes } 390df8bae1dSRodney W. Grimes 391996c772fSJohn Dyson if (idp->cookies) { 392df8bae1dSRodney W. Grimes if (idp->ncookies <= 0) { 393996c772fSJohn Dyson idp->eofflag = 0; 394996c772fSJohn Dyson return (-1); 395df8bae1dSRodney W. Grimes } 396df8bae1dSRodney W. Grimes 397996c772fSJohn Dyson *idp->cookies++ = off; 398df8bae1dSRodney W. Grimes --idp->ncookies; 399df8bae1dSRodney W. Grimes } 400df8bae1dSRodney W. Grimes 401c9524588SDag-Erling Smørgrav if ((error = uiomove(dp, dp->d_reclen, idp->uio)) != 0) 402996c772fSJohn Dyson return (error); 403df8bae1dSRodney W. Grimes idp->uio_off = off; 404996c772fSJohn Dyson return (0); 405df8bae1dSRodney W. Grimes } 406df8bae1dSRodney W. Grimes 40737c84183SPoul-Henning Kamp static int 408df8bae1dSRodney W. Grimes iso_shipdir(idp) 409df8bae1dSRodney W. Grimes struct isoreaddir *idp; 410df8bae1dSRodney W. Grimes { 411df8bae1dSRodney W. Grimes struct dirent *dp; 412df8bae1dSRodney W. Grimes int cl, sl, assoc; 413df8bae1dSRodney W. Grimes int error; 414df8bae1dSRodney W. Grimes char *cname, *sname; 415df8bae1dSRodney W. Grimes 416df8bae1dSRodney W. Grimes cl = idp->current.d_namlen; 417df8bae1dSRodney W. Grimes cname = idp->current.d_name; 4181295d82eSGary Palmer assoc = (cl > 1) && (*cname == ASSOCCHAR); 4191295d82eSGary Palmer if (assoc) { 420df8bae1dSRodney W. Grimes cl--; 421df8bae1dSRodney W. Grimes cname++; 422df8bae1dSRodney W. Grimes } 423df8bae1dSRodney W. Grimes 424df8bae1dSRodney W. Grimes dp = &idp->saveent; 425df8bae1dSRodney W. Grimes sname = dp->d_name; 426df8bae1dSRodney W. Grimes if (!(sl = dp->d_namlen)) { 427df8bae1dSRodney W. Grimes dp = &idp->assocent; 428df8bae1dSRodney W. Grimes sname = dp->d_name + 1; 429df8bae1dSRodney W. Grimes sl = dp->d_namlen - 1; 430df8bae1dSRodney W. Grimes } 431df8bae1dSRodney W. Grimes if (sl > 0) { 432df8bae1dSRodney W. Grimes if (sl != cl 433df8bae1dSRodney W. Grimes || bcmp(sname,cname,sl)) { 434df8bae1dSRodney W. Grimes if (idp->assocent.d_namlen) { 435d254af07SMatthew Dillon if ((error = iso_uiodir(idp,&idp->assocent,idp->assocoff)) != 0) 436996c772fSJohn Dyson return (error); 437df8bae1dSRodney W. Grimes idp->assocent.d_namlen = 0; 438df8bae1dSRodney W. Grimes } 439df8bae1dSRodney W. Grimes if (idp->saveent.d_namlen) { 440d254af07SMatthew Dillon if ((error = iso_uiodir(idp,&idp->saveent,idp->saveoff)) != 0) 441996c772fSJohn Dyson return (error); 442df8bae1dSRodney W. Grimes idp->saveent.d_namlen = 0; 443df8bae1dSRodney W. Grimes } 444df8bae1dSRodney W. Grimes } 445df8bae1dSRodney W. Grimes } 446c90607baSBruce Evans idp->current.d_reclen = GENERIC_DIRSIZ(&idp->current); 447df8bae1dSRodney W. Grimes if (assoc) { 448df8bae1dSRodney W. Grimes idp->assocoff = idp->curroff; 449a6274b81SEd Maste memcpy(&idp->assocent, &idp->current, idp->current.d_reclen); 450df8bae1dSRodney W. Grimes } else { 451df8bae1dSRodney W. Grimes idp->saveoff = idp->curroff; 452a6274b81SEd Maste memcpy(&idp->saveent, &idp->current, idp->current.d_reclen); 453df8bae1dSRodney W. Grimes } 454996c772fSJohn Dyson return (0); 455df8bae1dSRodney W. Grimes } 456df8bae1dSRodney W. Grimes 457df8bae1dSRodney W. Grimes /* 458df8bae1dSRodney W. Grimes * Vnode op for readdir 459df8bae1dSRodney W. Grimes */ 460605e9724SPoul-Henning Kamp static int 461df8bae1dSRodney W. Grimes cd9660_readdir(ap) 462df8bae1dSRodney W. Grimes struct vop_readdir_args /* { 463df8bae1dSRodney W. Grimes struct vnode *a_vp; 464df8bae1dSRodney W. Grimes struct uio *a_uio; 465df8bae1dSRodney W. Grimes struct ucred *a_cred; 466996c772fSJohn Dyson int *a_eofflag; 467996c772fSJohn Dyson int *a_ncookies; 468f71cc868STim J. Robbins u_long **a_cookies; 469df8bae1dSRodney W. Grimes } */ *ap; 470df8bae1dSRodney W. Grimes { 4718994a245SDag-Erling Smørgrav struct uio *uio = ap->a_uio; 472df8bae1dSRodney W. Grimes struct isoreaddir *idp; 473996c772fSJohn Dyson struct vnode *vdp = ap->a_vp; 474996c772fSJohn Dyson struct iso_node *dp; 475df8bae1dSRodney W. Grimes struct iso_mnt *imp; 476df8bae1dSRodney W. Grimes struct buf *bp = NULL; 477996c772fSJohn Dyson struct iso_directory_record *ep; 478996c772fSJohn Dyson int entryoffsetinblock; 479996c772fSJohn Dyson doff_t endsearch; 480996c772fSJohn Dyson u_long bmask; 481996c772fSJohn Dyson int error = 0; 482996c772fSJohn Dyson int reclen; 483996c772fSJohn Dyson u_short namelen; 484d821d364SPedro F. Giffuni u_int ncookies = 0; 485996c772fSJohn Dyson u_long *cookies = NULL; 486dbaab6e6SConrad Meyer cd_ino_t ino; 487df8bae1dSRodney W. Grimes 488996c772fSJohn Dyson dp = VTOI(vdp); 489996c772fSJohn Dyson imp = dp->i_mnt; 490996c772fSJohn Dyson bmask = imp->im_bmask; 491df8bae1dSRodney W. Grimes 4921ede983cSDag-Erling Smørgrav idp = malloc(sizeof(*idp), M_TEMP, M_WAITOK); 493996c772fSJohn Dyson idp->saveent.d_namlen = idp->assocent.d_namlen = 0; 494996c772fSJohn Dyson /* 495996c772fSJohn Dyson * XXX 496996c772fSJohn Dyson * Is it worth trying to figure out the type? 497996c772fSJohn Dyson */ 498996c772fSJohn Dyson idp->saveent.d_type = idp->assocent.d_type = idp->current.d_type = 499996c772fSJohn Dyson DT_UNKNOWN; 500df8bae1dSRodney W. Grimes idp->uio = uio; 501996c772fSJohn Dyson if (ap->a_ncookies == NULL) { 502996c772fSJohn Dyson idp->cookies = NULL; 503996c772fSJohn Dyson } else { 5049abf4d6eSDoug Rabson /* 5059abf4d6eSDoug Rabson * Guess the number of cookies needed. 5069abf4d6eSDoug Rabson */ 5079abf4d6eSDoug Rabson ncookies = uio->uio_resid / 16; 5081ede983cSDag-Erling Smørgrav cookies = malloc(ncookies * sizeof(u_long), 509224f219bSTim J. Robbins M_TEMP, M_WAITOK); 510996c772fSJohn Dyson idp->cookies = cookies; 511df8bae1dSRodney W. Grimes idp->ncookies = ncookies; 512996c772fSJohn Dyson } 513996c772fSJohn Dyson idp->eofflag = 1; 514df8bae1dSRodney W. Grimes idp->curroff = uio->uio_offset; 515ac8b6eddSKonstantin Belousov idp->uio_off = uio->uio_offset; 516df8bae1dSRodney W. Grimes 517996c772fSJohn Dyson if ((entryoffsetinblock = idp->curroff & bmask) && 518cec0f20cSPoul-Henning Kamp (error = cd9660_blkatoff(vdp, (off_t)idp->curroff, NULL, &bp))) { 5191ede983cSDag-Erling Smørgrav free(idp, M_TEMP); 520df8bae1dSRodney W. Grimes return (error); 521df8bae1dSRodney W. Grimes } 522996c772fSJohn Dyson endsearch = dp->i_size; 523df8bae1dSRodney W. Grimes 524df8bae1dSRodney W. Grimes while (idp->curroff < endsearch) { 525df8bae1dSRodney W. Grimes /* 526df8bae1dSRodney W. Grimes * If offset is on a block boundary, 527df8bae1dSRodney W. Grimes * read the next directory block. 528df8bae1dSRodney W. Grimes * Release previous if it exists. 529df8bae1dSRodney W. Grimes */ 530996c772fSJohn Dyson if ((idp->curroff & bmask) == 0) { 531df8bae1dSRodney W. Grimes if (bp != NULL) 532df8bae1dSRodney W. Grimes brelse(bp); 533d254af07SMatthew Dillon if ((error = 534d254af07SMatthew Dillon cd9660_blkatoff(vdp, (off_t)idp->curroff, NULL, &bp)) != 0) 535df8bae1dSRodney W. Grimes break; 536df8bae1dSRodney W. Grimes entryoffsetinblock = 0; 537df8bae1dSRodney W. Grimes } 538df8bae1dSRodney W. Grimes /* 539df8bae1dSRodney W. Grimes * Get pointer to next entry. 540df8bae1dSRodney W. Grimes */ 541df8bae1dSRodney W. Grimes ep = (struct iso_directory_record *) 542996c772fSJohn Dyson ((char *)bp->b_data + entryoffsetinblock); 543df8bae1dSRodney W. Grimes 544df8bae1dSRodney W. Grimes reclen = isonum_711(ep->length); 545df8bae1dSRodney W. Grimes if (reclen == 0) { 546df8bae1dSRodney W. Grimes /* skip to next block, if any */ 547996c772fSJohn Dyson idp->curroff = 548996c772fSJohn Dyson (idp->curroff & ~bmask) + imp->logical_block_size; 549df8bae1dSRodney W. Grimes continue; 550df8bae1dSRodney W. Grimes } 551df8bae1dSRodney W. Grimes 552df8bae1dSRodney W. Grimes if (reclen < ISO_DIRECTORY_RECORD_SIZE) { 553df8bae1dSRodney W. Grimes error = EINVAL; 554df8bae1dSRodney W. Grimes /* illegal entry, stop */ 555df8bae1dSRodney W. Grimes break; 556df8bae1dSRodney W. Grimes } 557df8bae1dSRodney W. Grimes 558df8bae1dSRodney W. Grimes if (entryoffsetinblock + reclen > imp->logical_block_size) { 559df8bae1dSRodney W. Grimes error = EINVAL; 560df8bae1dSRodney W. Grimes /* illegal directory, so stop looking */ 561df8bae1dSRodney W. Grimes break; 562df8bae1dSRodney W. Grimes } 563df8bae1dSRodney W. Grimes 564996c772fSJohn Dyson idp->current.d_namlen = isonum_711(ep->name_len); 565996c772fSJohn Dyson 566996c772fSJohn Dyson if (reclen < ISO_DIRECTORY_RECORD_SIZE + idp->current.d_namlen) { 56781ec856aSJoerg Wunsch error = EINVAL; 56881ec856aSJoerg Wunsch /* illegal entry, stop */ 56981ec856aSJoerg Wunsch break; 57081ec856aSJoerg Wunsch } 57181ec856aSJoerg Wunsch 57282c0aec8STim J. Robbins if (isonum_711(ep->flags)&2) 57382c0aec8STim J. Robbins idp->current.d_fileno = isodirino(ep, imp); 57482c0aec8STim J. Robbins else 57582c0aec8STim J. Robbins idp->current.d_fileno = dbtob(bp->b_blkno) + 57682c0aec8STim J. Robbins entryoffsetinblock; 577df8bae1dSRodney W. Grimes 578df8bae1dSRodney W. Grimes idp->curroff += reclen; 579*1c4ca778SKonstantin Belousov /* NOTE: d_off is the offset of *next* entry. */ 580*1c4ca778SKonstantin Belousov idp->current.d_off = idp->curroff; 581996c772fSJohn Dyson 582df8bae1dSRodney W. Grimes switch (imp->iso_ftype) { 583df8bae1dSRodney W. Grimes case ISO_FTYPE_RRIP: 584dbaab6e6SConrad Meyer ino = idp->current.d_fileno; 585996c772fSJohn Dyson cd9660_rrip_getname(ep, idp->current.d_name, &namelen, 586dbaab6e6SConrad Meyer &ino, imp); 587dbaab6e6SConrad Meyer idp->current.d_fileno = ino; 588996c772fSJohn Dyson idp->current.d_namlen = (u_char)namelen; 589df8bae1dSRodney W. Grimes if (idp->current.d_namlen) 590df8bae1dSRodney W. Grimes error = iso_uiodir(idp,&idp->current,idp->curroff); 591df8bae1dSRodney W. Grimes break; 592988fa8efSJoerg Wunsch default: /* ISO_FTYPE_DEFAULT || ISO_FTYPE_9660 || ISO_FTYPE_HIGH_SIERRA*/ 593df8bae1dSRodney W. Grimes strcpy(idp->current.d_name,".."); 59444e568e2SDaniel C. Sobral if (idp->current.d_namlen == 1 && ep->name[0] == 0) { 595df8bae1dSRodney W. Grimes idp->current.d_namlen = 1; 596df8bae1dSRodney W. Grimes error = iso_uiodir(idp,&idp->current,idp->curroff); 59744e568e2SDaniel C. Sobral } else if (idp->current.d_namlen == 1 && ep->name[0] == 1) { 598df8bae1dSRodney W. Grimes idp->current.d_namlen = 2; 599df8bae1dSRodney W. Grimes error = iso_uiodir(idp,&idp->current,idp->curroff); 60044e568e2SDaniel C. Sobral } else { 601df8bae1dSRodney W. Grimes isofntrans(ep->name,idp->current.d_namlen, 602996c772fSJohn Dyson idp->current.d_name, &namelen, 603df8bae1dSRodney W. Grimes imp->iso_ftype == ISO_FTYPE_9660, 60444e568e2SDaniel C. Sobral isonum_711(ep->flags)&4, 605c4f02a89SMax Khon imp->joliet_level, 606c4f02a89SMax Khon imp->im_flags, 607c4f02a89SMax Khon imp->im_d2l); 608996c772fSJohn Dyson idp->current.d_namlen = (u_char)namelen; 609df8bae1dSRodney W. Grimes if (imp->iso_ftype == ISO_FTYPE_DEFAULT) 610df8bae1dSRodney W. Grimes error = iso_shipdir(idp); 611df8bae1dSRodney W. Grimes else 612df8bae1dSRodney W. Grimes error = iso_uiodir(idp,&idp->current,idp->curroff); 613df8bae1dSRodney W. Grimes } 614df8bae1dSRodney W. Grimes } 615df8bae1dSRodney W. Grimes if (error) 616df8bae1dSRodney W. Grimes break; 617df8bae1dSRodney W. Grimes 618df8bae1dSRodney W. Grimes entryoffsetinblock += reclen; 619df8bae1dSRodney W. Grimes } 620df8bae1dSRodney W. Grimes 621df8bae1dSRodney W. Grimes if (!error && imp->iso_ftype == ISO_FTYPE_DEFAULT) { 622df8bae1dSRodney W. Grimes idp->current.d_namlen = 0; 623df8bae1dSRodney W. Grimes error = iso_shipdir(idp); 624df8bae1dSRodney W. Grimes } 625df8bae1dSRodney W. Grimes if (error < 0) 626df8bae1dSRodney W. Grimes error = 0; 627df8bae1dSRodney W. Grimes 6289abf4d6eSDoug Rabson if (ap->a_ncookies != NULL) { 6299abf4d6eSDoug Rabson if (error) 630996c772fSJohn Dyson free(cookies, M_TEMP); 6319abf4d6eSDoug Rabson else { 6329abf4d6eSDoug Rabson /* 6339abf4d6eSDoug Rabson * Work out the number of cookies actually used. 6349abf4d6eSDoug Rabson */ 6359abf4d6eSDoug Rabson *ap->a_ncookies = ncookies - idp->ncookies; 6369abf4d6eSDoug Rabson *ap->a_cookies = cookies; 6379abf4d6eSDoug Rabson } 6389abf4d6eSDoug Rabson } 6399abf4d6eSDoug Rabson 640df8bae1dSRodney W. Grimes if (bp) 641df8bae1dSRodney W. Grimes brelse (bp); 642df8bae1dSRodney W. Grimes 643df8bae1dSRodney W. Grimes uio->uio_offset = idp->uio_off; 644996c772fSJohn Dyson *ap->a_eofflag = idp->eofflag; 645df8bae1dSRodney W. Grimes 6461ede983cSDag-Erling Smørgrav free(idp, M_TEMP); 647df8bae1dSRodney W. Grimes 648df8bae1dSRodney W. Grimes return (error); 649df8bae1dSRodney W. Grimes } 650df8bae1dSRodney W. Grimes 651df8bae1dSRodney W. Grimes /* 652df8bae1dSRodney W. Grimes * Return target name of a symbolic link 653df8bae1dSRodney W. Grimes * Shouldn't we get the parent vnode and read the data from there? 654df8bae1dSRodney W. Grimes * This could eventually result in deadlocks in cd9660_lookup. 655df8bae1dSRodney W. Grimes * But otherwise the block read here is in the block buffer two times. 656df8bae1dSRodney W. Grimes */ 657df8bae1dSRodney W. Grimes typedef struct iso_directory_record ISODIR; 658df8bae1dSRodney W. Grimes typedef struct iso_node ISONODE; 659df8bae1dSRodney W. Grimes typedef struct iso_mnt ISOMNT; 660605e9724SPoul-Henning Kamp static int 661df8bae1dSRodney W. Grimes cd9660_readlink(ap) 662df8bae1dSRodney W. Grimes struct vop_readlink_args /* { 663df8bae1dSRodney W. Grimes struct vnode *a_vp; 664df8bae1dSRodney W. Grimes struct uio *a_uio; 665df8bae1dSRodney W. Grimes struct ucred *a_cred; 666df8bae1dSRodney W. Grimes } */ *ap; 667df8bae1dSRodney W. Grimes { 668df8bae1dSRodney W. Grimes ISONODE *ip; 669df8bae1dSRodney W. Grimes ISODIR *dirp; 670df8bae1dSRodney W. Grimes ISOMNT *imp; 671df8bae1dSRodney W. Grimes struct buf *bp; 672996c772fSJohn Dyson struct uio *uio; 673df8bae1dSRodney W. Grimes u_short symlen; 674df8bae1dSRodney W. Grimes int error; 675df8bae1dSRodney W. Grimes char *symname; 676df8bae1dSRodney W. Grimes 677df8bae1dSRodney W. Grimes ip = VTOI(ap->a_vp); 678df8bae1dSRodney W. Grimes imp = ip->i_mnt; 679996c772fSJohn Dyson uio = ap->a_uio; 680df8bae1dSRodney W. Grimes 681df8bae1dSRodney W. Grimes if (imp->iso_ftype != ISO_FTYPE_RRIP) 682996c772fSJohn Dyson return (EINVAL); 683df8bae1dSRodney W. Grimes 684df8bae1dSRodney W. Grimes /* 685df8bae1dSRodney W. Grimes * Get parents directory record block that this inode included. 686df8bae1dSRodney W. Grimes */ 687df8bae1dSRodney W. Grimes error = bread(imp->im_devvp, 688996c772fSJohn Dyson (ip->i_number >> imp->im_bshift) << 689996c772fSJohn Dyson (imp->im_bshift - DEV_BSHIFT), 690996c772fSJohn Dyson imp->logical_block_size, NOCRED, &bp); 691df8bae1dSRodney W. Grimes if (error) { 692df8bae1dSRodney W. Grimes brelse(bp); 693996c772fSJohn Dyson return (EINVAL); 694df8bae1dSRodney W. Grimes } 695df8bae1dSRodney W. Grimes 696df8bae1dSRodney W. Grimes /* 697df8bae1dSRodney W. Grimes * Setup the directory pointer for this inode 698df8bae1dSRodney W. Grimes */ 699996c772fSJohn Dyson dirp = (ISODIR *)(bp->b_data + (ip->i_number & imp->im_bmask)); 700df8bae1dSRodney W. Grimes 701df8bae1dSRodney W. Grimes /* 702df8bae1dSRodney W. Grimes * Just make sure, we have a right one.... 703df8bae1dSRodney W. Grimes * 1: Check not cross boundary on block 704df8bae1dSRodney W. Grimes */ 705df8bae1dSRodney W. Grimes if ((ip->i_number & imp->im_bmask) + isonum_711(dirp->length) 70692579404SAlexander Langer > (unsigned)imp->logical_block_size) { 707df8bae1dSRodney W. Grimes brelse(bp); 708996c772fSJohn Dyson return (EINVAL); 709df8bae1dSRodney W. Grimes } 710df8bae1dSRodney W. Grimes 711df8bae1dSRodney W. Grimes /* 712df8bae1dSRodney W. Grimes * Now get a buffer 713df8bae1dSRodney W. Grimes * Abuse a namei buffer for now. 714df8bae1dSRodney W. Grimes */ 715996c772fSJohn Dyson if (uio->uio_segflg == UIO_SYSSPACE) 716996c772fSJohn Dyson symname = uio->uio_iov->iov_base; 717996c772fSJohn Dyson else 718a163d034SWarner Losh symname = uma_zalloc(namei_zone, M_WAITOK); 719df8bae1dSRodney W. Grimes 720df8bae1dSRodney W. Grimes /* 721df8bae1dSRodney W. Grimes * Ok, we just gathering a symbolic name in SL record. 722df8bae1dSRodney W. Grimes */ 723df8bae1dSRodney W. Grimes if (cd9660_rrip_getsymname(dirp, symname, &symlen, imp) == 0) { 724996c772fSJohn Dyson if (uio->uio_segflg != UIO_SYSSPACE) 7252684b6afSJeff Roberson uma_zfree(namei_zone, symname); 726df8bae1dSRodney W. Grimes brelse(bp); 727996c772fSJohn Dyson return (EINVAL); 728df8bae1dSRodney W. Grimes } 729df8bae1dSRodney W. Grimes /* 730df8bae1dSRodney W. Grimes * Don't forget before you leave from home ;-) 731df8bae1dSRodney W. Grimes */ 732df8bae1dSRodney W. Grimes brelse(bp); 733df8bae1dSRodney W. Grimes 734df8bae1dSRodney W. Grimes /* 735df8bae1dSRodney W. Grimes * return with the symbolic name to caller's. 736df8bae1dSRodney W. Grimes */ 737996c772fSJohn Dyson if (uio->uio_segflg != UIO_SYSSPACE) { 738996c772fSJohn Dyson error = uiomove(symname, symlen, uio); 7392684b6afSJeff Roberson uma_zfree(namei_zone, symname); 740996c772fSJohn Dyson return (error); 741996c772fSJohn Dyson } 742996c772fSJohn Dyson uio->uio_resid -= symlen; 7432b7f24d2SMike Barcroft uio->uio_iov->iov_base = (char *)uio->uio_iov->iov_base + symlen; 744996c772fSJohn Dyson uio->uio_iov->iov_len -= symlen; 745996c772fSJohn Dyson return (0); 746df8bae1dSRodney W. Grimes } 747df8bae1dSRodney W. Grimes 748df8bae1dSRodney W. Grimes /* 749df8bae1dSRodney W. Grimes * Calculate the logical to physical mapping if not done already, 750df8bae1dSRodney W. Grimes * then call the device strategy routine. 751df8bae1dSRodney W. Grimes */ 752605e9724SPoul-Henning Kamp static int 753df8bae1dSRodney W. Grimes cd9660_strategy(ap) 754df8bae1dSRodney W. Grimes struct vop_strategy_args /* { 755fd5d1124SJulian Elischer struct buf *a_vp; 756df8bae1dSRodney W. Grimes struct buf *a_bp; 757df8bae1dSRodney W. Grimes } */ *ap; 758df8bae1dSRodney W. Grimes { 7598994a245SDag-Erling Smørgrav struct buf *bp = ap->a_bp; 760d83b7498SPoul-Henning Kamp struct vnode *vp = ap->a_vp; 7618994a245SDag-Erling Smørgrav struct iso_node *ip; 762bf7e2ae1SPoul-Henning Kamp struct bufobj *bo; 763df8bae1dSRodney W. Grimes 764df8bae1dSRodney W. Grimes ip = VTOI(vp); 765df8bae1dSRodney W. Grimes if (vp->v_type == VBLK || vp->v_type == VCHR) 766df8bae1dSRodney W. Grimes panic("cd9660_strategy: spec"); 767df8bae1dSRodney W. Grimes if (bp->b_blkno == bp->b_lblkno) { 768e9d19a11SPoul-Henning Kamp bp->b_blkno = (ip->iso_start + bp->b_lblkno) << 769e9d19a11SPoul-Henning Kamp (ip->i_mnt->im_bshift - DEV_BSHIFT); 770df8bae1dSRodney W. Grimes } 7712c18019fSPoul-Henning Kamp bp->b_iooffset = dbtob(bp->b_blkno); 772bf7e2ae1SPoul-Henning Kamp bo = ip->i_mnt->im_bo; 7730391e5a1SPoul-Henning Kamp BO_STRATEGY(bo, bp); 774df8bae1dSRodney W. Grimes return (0); 775df8bae1dSRodney W. Grimes } 776df8bae1dSRodney W. Grimes 777df8bae1dSRodney W. Grimes /* 778996c772fSJohn Dyson * Return POSIX pathconf information applicable to cd9660 filesystems. 779996c772fSJohn Dyson */ 780f041a9bdSPoul-Henning Kamp static int 781996c772fSJohn Dyson cd9660_pathconf(ap) 782996c772fSJohn Dyson struct vop_pathconf_args /* { 783996c772fSJohn Dyson struct vnode *a_vp; 784996c772fSJohn Dyson int a_name; 785996c772fSJohn Dyson register_t *a_retval; 786996c772fSJohn Dyson } */ *ap; 787996c772fSJohn Dyson { 788996c772fSJohn Dyson 789996c772fSJohn Dyson switch (ap->a_name) { 790eb3d4cccSJohn Baldwin case _PC_FILESIZEBITS: 791eb3d4cccSJohn Baldwin *ap->a_retval = 32; 792eb3d4cccSJohn Baldwin return (0); 793996c772fSJohn Dyson case _PC_LINK_MAX: 794996c772fSJohn Dyson *ap->a_retval = 1; 795996c772fSJohn Dyson return (0); 796996c772fSJohn Dyson case _PC_NAME_MAX: 797996c772fSJohn Dyson if (VTOI(ap->a_vp)->i_mnt->iso_ftype == ISO_FTYPE_RRIP) 798996c772fSJohn Dyson *ap->a_retval = NAME_MAX; 799996c772fSJohn Dyson else 800996c772fSJohn Dyson *ap->a_retval = 37; 801996c772fSJohn Dyson return (0); 802eb3d4cccSJohn Baldwin case _PC_SYMLINK_MAX: 803eb3d4cccSJohn Baldwin if (VTOI(ap->a_vp)->i_mnt->iso_ftype == ISO_FTYPE_RRIP) { 804eb3d4cccSJohn Baldwin *ap->a_retval = MAXPATHLEN; 805eb3d4cccSJohn Baldwin return (0); 806eb3d4cccSJohn Baldwin } 807eb3d4cccSJohn Baldwin return (EINVAL); 808996c772fSJohn Dyson case _PC_NO_TRUNC: 809996c772fSJohn Dyson *ap->a_retval = 1; 810996c772fSJohn Dyson return (0); 811996c772fSJohn Dyson default: 81215a88f81SJohn Baldwin return (vop_stdpathconf(ap)); 813996c772fSJohn Dyson } 814996c772fSJohn Dyson /* NOTREACHED */ 815df8bae1dSRodney W. Grimes } 816df8bae1dSRodney W. Grimes 817df8bae1dSRodney W. Grimes /* 81810bcafe9SPawel Jakub Dawidek * Vnode pointer to File handle 81910bcafe9SPawel Jakub Dawidek */ 82010bcafe9SPawel Jakub Dawidek static int 82110bcafe9SPawel Jakub Dawidek cd9660_vptofh(ap) 82210bcafe9SPawel Jakub Dawidek struct vop_vptofh_args /* { 82310bcafe9SPawel Jakub Dawidek struct vnode *a_vp; 82410bcafe9SPawel Jakub Dawidek struct fid *a_fhp; 82510bcafe9SPawel Jakub Dawidek } */ *ap; 82610bcafe9SPawel Jakub Dawidek { 8279251d56fSMarius Strobl struct ifid ifh; 82810bcafe9SPawel Jakub Dawidek struct iso_node *ip = VTOI(ap->a_vp); 82910bcafe9SPawel Jakub Dawidek 8309251d56fSMarius Strobl ifh.ifid_len = sizeof(struct ifid); 83110bcafe9SPawel Jakub Dawidek 8329251d56fSMarius Strobl ifh.ifid_ino = ip->i_number; 8339251d56fSMarius Strobl ifh.ifid_start = ip->iso_start; 8349251d56fSMarius Strobl /* 8359251d56fSMarius Strobl * This intentionally uses sizeof(ifh) in order to not copy stack 8369251d56fSMarius Strobl * garbage on ILP32. 8379251d56fSMarius Strobl */ 8389251d56fSMarius Strobl memcpy(ap->a_fhp, &ifh, sizeof(ifh)); 83910bcafe9SPawel Jakub Dawidek 84010bcafe9SPawel Jakub Dawidek #ifdef ISOFS_DBG 841dbaab6e6SConrad Meyer printf("vptofh: ino %jd, start %ld\n", 842dbaab6e6SConrad Meyer (uintmax_t)ifh.ifid_ino, ifh.ifid_start); 84310bcafe9SPawel Jakub Dawidek #endif 8449251d56fSMarius Strobl 8459251d56fSMarius Strobl return (0); 84610bcafe9SPawel Jakub Dawidek } 84710bcafe9SPawel Jakub Dawidek 848c329ee71SKonstantin Belousov SYSCTL_NODE(_vfs, OID_AUTO, cd9660, CTLFLAG_RW, 0, "cd9660 filesystem"); 849c329ee71SKonstantin Belousov static int use_buf_pager = 1; 850c329ee71SKonstantin Belousov SYSCTL_INT(_vfs_cd9660, OID_AUTO, use_buf_pager, CTLFLAG_RWTUN, 851c329ee71SKonstantin Belousov &use_buf_pager, 0, 852c329ee71SKonstantin Belousov "Use buffer pager instead of bmap"); 853c329ee71SKonstantin Belousov 854c329ee71SKonstantin Belousov static daddr_t 855c329ee71SKonstantin Belousov cd9660_gbp_getblkno(struct vnode *vp, vm_ooffset_t off) 856c329ee71SKonstantin Belousov { 857c329ee71SKonstantin Belousov 858c329ee71SKonstantin Belousov return (lblkno(VTOI(vp)->i_mnt, off)); 859c329ee71SKonstantin Belousov } 860c329ee71SKonstantin Belousov 861c329ee71SKonstantin Belousov static int 862c329ee71SKonstantin Belousov cd9660_gbp_getblksz(struct vnode *vp, daddr_t lbn) 863c329ee71SKonstantin Belousov { 864c329ee71SKonstantin Belousov struct iso_node *ip; 865c329ee71SKonstantin Belousov 866c329ee71SKonstantin Belousov ip = VTOI(vp); 867c329ee71SKonstantin Belousov return (blksize(ip->i_mnt, ip, lbn)); 868c329ee71SKonstantin Belousov } 869c329ee71SKonstantin Belousov 870c329ee71SKonstantin Belousov static int 871c329ee71SKonstantin Belousov cd9660_getpages(struct vop_getpages_args *ap) 872c329ee71SKonstantin Belousov { 873c329ee71SKonstantin Belousov struct vnode *vp; 874c329ee71SKonstantin Belousov 875c329ee71SKonstantin Belousov vp = ap->a_vp; 876c329ee71SKonstantin Belousov if (vp->v_type == VCHR || vp->v_type == VBLK) 877c329ee71SKonstantin Belousov return (EOPNOTSUPP); 878c329ee71SKonstantin Belousov 879c329ee71SKonstantin Belousov if (use_buf_pager) 880c329ee71SKonstantin Belousov return (vfs_bio_getpages(vp, ap->a_m, ap->a_count, 881c329ee71SKonstantin Belousov ap->a_rbehind, ap->a_rahead, cd9660_gbp_getblkno, 882c329ee71SKonstantin Belousov cd9660_gbp_getblksz)); 883c329ee71SKonstantin Belousov return (vnode_pager_generic_getpages(vp, ap->a_m, ap->a_count, 884c329ee71SKonstantin Belousov ap->a_rbehind, ap->a_rahead, NULL, NULL)); 885c329ee71SKonstantin Belousov } 886c329ee71SKonstantin Belousov 88710bcafe9SPawel Jakub Dawidek /* 888996c772fSJohn Dyson * Global vfs data structures for cd9660 889df8bae1dSRodney W. Grimes */ 890aec0fb7bSPoul-Henning Kamp struct vop_vector cd9660_vnodeops = { 891aec0fb7bSPoul-Henning Kamp .vop_default = &default_vnodeops, 89272b3e305SPeter Edwards .vop_open = cd9660_open, 893aec0fb7bSPoul-Henning Kamp .vop_access = cd9660_access, 894aec0fb7bSPoul-Henning Kamp .vop_bmap = cd9660_bmap, 895aec0fb7bSPoul-Henning Kamp .vop_cachedlookup = cd9660_lookup, 896aec0fb7bSPoul-Henning Kamp .vop_getattr = cd9660_getattr, 897aec0fb7bSPoul-Henning Kamp .vop_inactive = cd9660_inactive, 898aec0fb7bSPoul-Henning Kamp .vop_ioctl = cd9660_ioctl, 899aec0fb7bSPoul-Henning Kamp .vop_lookup = vfs_cache_lookup, 900aec0fb7bSPoul-Henning Kamp .vop_pathconf = cd9660_pathconf, 901aec0fb7bSPoul-Henning Kamp .vop_read = cd9660_read, 902aec0fb7bSPoul-Henning Kamp .vop_readdir = cd9660_readdir, 903aec0fb7bSPoul-Henning Kamp .vop_readlink = cd9660_readlink, 904aec0fb7bSPoul-Henning Kamp .vop_reclaim = cd9660_reclaim, 905aec0fb7bSPoul-Henning Kamp .vop_setattr = cd9660_setattr, 906aec0fb7bSPoul-Henning Kamp .vop_strategy = cd9660_strategy, 90710bcafe9SPawel Jakub Dawidek .vop_vptofh = cd9660_vptofh, 908c329ee71SKonstantin Belousov .vop_getpages = cd9660_getpages, 909df8bae1dSRodney W. Grimes }; 910df8bae1dSRodney W. Grimes 911df8bae1dSRodney W. Grimes /* 912df8bae1dSRodney W. Grimes * Special device vnode ops 913df8bae1dSRodney W. Grimes */ 914df8bae1dSRodney W. Grimes 915aec0fb7bSPoul-Henning Kamp struct vop_vector cd9660_fifoops = { 916aec0fb7bSPoul-Henning Kamp .vop_default = &fifo_specops, 917aec0fb7bSPoul-Henning Kamp .vop_access = cd9660_access, 918aec0fb7bSPoul-Henning Kamp .vop_getattr = cd9660_getattr, 919aec0fb7bSPoul-Henning Kamp .vop_inactive = cd9660_inactive, 920aec0fb7bSPoul-Henning Kamp .vop_reclaim = cd9660_reclaim, 921aec0fb7bSPoul-Henning Kamp .vop_setattr = cd9660_setattr, 92210bcafe9SPawel Jakub Dawidek .vop_vptofh = cd9660_vptofh, 923df8bae1dSRodney W. Grimes }; 924