/* * Return buffer with the contents of block "offset" from the beginning of * directory "ip". If "res" is non-zero, fill it in with a pointer to the * remaining space in the directory. */ int cd9660_blkatoff(struct vnode *vp, off_t offset, char **res, struct buf **bpp) { struct iso_node *ip; struct iso_mnt *imp; struct buf *bp; daddr_t lbn; int bsize, error; ip = VTOI(vp); imp = ip->i_mnt; lbn = cd9660_lblkno(imp, offset); bsize = cd9660_blksize(imp, ip, lbn); if ((error = bread(vp, lbn, bsize, NOCRED, 0, &bp)) != 0) { *bpp = NULL; return (error); } if (res) *res = (char *)bp->b_data + cd9660_blkoff(imp, offset); *bpp = bp; return (0); }
/* * Vnode op for reading. */ int cd9660_read(void *v) { struct vop_read_args /* { struct vnode *a_vp; struct uio *a_uio; int a_ioflag; kauth_cred_t a_cred; } */ *ap = v; struct vnode *vp = ap->a_vp; struct uio *uio = ap->a_uio; struct iso_node *ip = VTOI(vp); struct iso_mnt *imp; struct buf *bp; daddr_t lbn, rablock; off_t diff; int rasize, error = 0; long size, n, on; if (uio->uio_resid == 0) return (0); if (uio->uio_offset < 0) return (EINVAL); if (uio->uio_offset >= ip->i_size) return 0; ip->i_flag |= IN_ACCESS; imp = ip->i_mnt; if (vp->v_type == VREG) { const int advice = IO_ADV_DECODE(ap->a_ioflag); error = 0; while (uio->uio_resid > 0) { vsize_t bytelen = MIN(ip->i_size - uio->uio_offset, uio->uio_resid); if (bytelen == 0) break; error = ubc_uiomove(&vp->v_uobj, uio, bytelen, advice, UBC_READ | UBC_PARTIALOK | UBC_UNMAP_FLAG(vp)); if (error) break; } goto out; } do { lbn = cd9660_lblkno(imp, uio->uio_offset); on = cd9660_blkoff(imp, uio->uio_offset); n = MIN(imp->logical_block_size - on, uio->uio_resid); diff = (off_t)ip->i_size - uio->uio_offset; if (diff <= 0) return (0); if (diff < n) n = diff; size = cd9660_blksize(imp, ip, lbn); rablock = lbn + 1; if (cd9660_lblktosize(imp, rablock) < ip->i_size) { rasize = cd9660_blksize(imp, ip, rablock); error = breadn(vp, lbn, size, &rablock, &rasize, 1, NOCRED, 0, &bp); } else { error = bread(vp, lbn, size, NOCRED, 0, &bp); } if (error) { return (error); } n = MIN(n, size - bp->b_resid); error = uiomove((char *)bp->b_data + on, (int)n, uio); brelse(bp, 0); } while (error == 0 && uio->uio_resid > 0 && n != 0); out: return (error); }