| Commit | Line | Data |
|---|---|---|
| 984263bc MD |
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 | * $FreeBSD: src/sys/isofs/cd9660/cd9660_vnops.c,v 1.62 1999/12/15 23:01:51 eivind Exp $ | |
| e92ca23a | 40 | * $DragonFly: src/sys/vfs/isofs/cd9660/cd9660_vnops.c,v 1.40 2008/06/19 23:27:39 dillon Exp $ |
| 984263bc MD |
41 | */ |
| 42 | ||
| 43 | #include <sys/param.h> | |
| 44 | #include <sys/systm.h> | |
| dadab5e9 | 45 | #include <sys/proc.h> |
| 984263bc MD |
46 | #include <sys/namei.h> |
| 47 | #include <sys/kernel.h> | |
| 48 | #include <sys/stat.h> | |
| 49 | #include <sys/buf.h> | |
| 50 | #include <sys/mount.h> | |
| 51 | #include <sys/vnode.h> | |
| 1f2de5d4 | 52 | #include <vfs/fifofs/fifo.h> |
| 984263bc MD |
53 | #include <sys/malloc.h> |
| 54 | #include <sys/dirent.h> | |
| 55 | #include <sys/unistd.h> | |
| 56 | #include <sys/filio.h> | |
| f308cd58 | 57 | #include <sys/lockf.h> |
| 70aac194 | 58 | #include <sys/objcache.h> |
| 984263bc MD |
59 | |
| 60 | #include <vm/vm.h> | |
| 984263bc MD |
61 | #include <vm/vnode_pager.h> |
| 62 | ||
| 1f2de5d4 MD |
63 | #include "iso.h" |
| 64 | #include "cd9660_node.h" | |
| 65 | #include "iso_rrip.h" | |
| 984263bc | 66 | |
| a6ee311a | 67 | static int cd9660_access (struct vop_access_args *); |
| f308cd58 | 68 | static int cd9660_advlock (struct vop_advlock_args *); |
| a6ee311a RG |
69 | static int cd9660_getattr (struct vop_getattr_args *); |
| 70 | static int cd9660_ioctl (struct vop_ioctl_args *); | |
| 71 | static int cd9660_pathconf (struct vop_pathconf_args *); | |
| 7540ab49 | 72 | static int cd9660_open (struct vop_open_args *); |
| a6ee311a | 73 | static int cd9660_read (struct vop_read_args *); |
| f308cd58 | 74 | static int cd9660_setattr (struct vop_setattr_args *); |
| 984263bc | 75 | struct isoreaddir; |
| a6ee311a RG |
76 | static int iso_uiodir (struct isoreaddir *idp, struct dirent *dp, |
| 77 | off_t off); | |
| 78 | static int iso_shipdir (struct isoreaddir *idp); | |
| 79 | static int cd9660_readdir (struct vop_readdir_args *); | |
| 80 | static int cd9660_readlink (struct vop_readlink_args *ap); | |
| 81 | static int cd9660_strategy (struct vop_strategy_args *); | |
| 82 | static int cd9660_print (struct vop_print_args *); | |
| 984263bc MD |
83 | |
| 84 | /* | |
| 85 | * Setattr call. Only allowed for block and character special devices. | |
| 3fa8192b | 86 | * |
| 31bd717a MD |
87 | * cd9660_setattr(struct vnode *a_vp, struct vattr *a_vap, |
| 88 | * struct ucred *a_cred, struct proc *a_p) | |
| 984263bc MD |
89 | */ |
| 90 | int | |
| 3fa8192b | 91 | cd9660_setattr(struct vop_setattr_args *ap) |
| 984263bc MD |
92 | { |
| 93 | struct vnode *vp = ap->a_vp; | |
| 94 | struct vattr *vap = ap->a_vap; | |
| 95 | ||
| 96 | if (vap->va_flags != (u_long)VNOVAL || vap->va_uid != (uid_t)VNOVAL || | |
| 97 | vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL || | |
| 98 | vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL) | |
| 99 | return (EROFS); | |
| 100 | if (vap->va_size != (u_quad_t)VNOVAL) { | |
| 101 | switch (vp->v_type) { | |
| 102 | case VDIR: | |
| 103 | return (EISDIR); | |
| 104 | case VLNK: | |
| 105 | case VREG: | |
| 50626622 | 106 | case VDATABASE: |
| 984263bc MD |
107 | return (EROFS); |
| 108 | case VCHR: | |
| 109 | case VBLK: | |
| 110 | case VSOCK: | |
| 111 | case VFIFO: | |
| 112 | case VNON: | |
| 113 | case VBAD: | |
| 114 | return (0); | |
| 115 | } | |
| 116 | } | |
| 117 | return (0); | |
| 118 | } | |
| 119 | ||
| 120 | /* | |
| 121 | * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC. | |
| 122 | * The mode is shifted to select the owner/group/other fields. The | |
| 123 | * super user is granted all permissions. | |
| 3fa8192b CP |
124 | * |
| 125 | * cd9660_access(struct vnode *a_vp, int a_mode, struct ucred *a_cred, | |
| 126 | * struct proc *a_p) | |
| 984263bc MD |
127 | */ |
| 128 | /* ARGSUSED */ | |
| 129 | static int | |
| 3fa8192b | 130 | cd9660_access(struct vop_access_args *ap) |
| 984263bc MD |
131 | { |
| 132 | struct vnode *vp = ap->a_vp; | |
| 133 | struct iso_node *ip = VTOI(vp); | |
| 134 | struct ucred *cred = ap->a_cred; | |
| 135 | mode_t mask, mode = ap->a_mode; | |
| 136 | gid_t *gp; | |
| 137 | int i; | |
| 138 | ||
| 139 | /* | |
| 140 | * Disallow write attempts unless the file is a socket, | |
| 141 | * fifo, or a block or character device resident on the | |
| 142 | * file system. | |
| 143 | */ | |
| 144 | if (mode & VWRITE) { | |
| 145 | switch (vp->v_type) { | |
| 146 | case VDIR: | |
| 147 | case VLNK: | |
| 148 | case VREG: | |
| 149 | return (EROFS); | |
| 150 | /* NOT REACHED */ | |
| 151 | default: | |
| 152 | break; | |
| 153 | } | |
| 154 | } | |
| 155 | ||
| 156 | /* User id 0 always gets access. */ | |
| 157 | if (cred->cr_uid == 0) | |
| 158 | return (0); | |
| 159 | ||
| 160 | mask = 0; | |
| 161 | ||
| 162 | /* Otherwise, check the owner. */ | |
| 163 | if (cred->cr_uid == ip->inode.iso_uid) { | |
| 164 | if (mode & VEXEC) | |
| 165 | mask |= S_IXUSR; | |
| 166 | if (mode & VREAD) | |
| 167 | mask |= S_IRUSR; | |
| 168 | if (mode & VWRITE) | |
| 169 | mask |= S_IWUSR; | |
| 170 | return ((ip->inode.iso_mode & mask) == mask ? 0 : EACCES); | |
| 171 | } | |
| 172 | ||
| 173 | /* Otherwise, check the groups. */ | |
| 174 | for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++) | |
| 175 | if (ip->inode.iso_gid == *gp) { | |
| 176 | if (mode & VEXEC) | |
| 177 | mask |= S_IXGRP; | |
| 178 | if (mode & VREAD) | |
| 179 | mask |= S_IRGRP; | |
| 180 | if (mode & VWRITE) | |
| 181 | mask |= S_IWGRP; | |
| 182 | return ((ip->inode.iso_mode & mask) == mask ? | |
| 183 | 0 : EACCES); | |
| 184 | } | |
| 185 | ||
| 186 | /* Otherwise, check everyone else. */ | |
| 187 | if (mode & VEXEC) | |
| 188 | mask |= S_IXOTH; | |
| 189 | if (mode & VREAD) | |
| 190 | mask |= S_IROTH; | |
| 191 | if (mode & VWRITE) | |
| 192 | mask |= S_IWOTH; | |
| 193 | return ((ip->inode.iso_mode & mask) == mask ? 0 : EACCES); | |
| 194 | } | |
| 195 | ||
| 3fa8192b | 196 | /* |
| b478fdce | 197 | * cd9660_getattr(struct vnode *a_vp, struct vattr *a_vap) |
| 3fa8192b | 198 | */ |
| 984263bc | 199 | static int |
| 3fa8192b | 200 | cd9660_getattr(struct vop_getattr_args *ap) |
| 984263bc MD |
201 | { |
| 202 | struct vnode *vp = ap->a_vp; | |
| 3a1b0fdc RG |
203 | struct vattr *vap = ap->a_vap; |
| 204 | struct iso_node *ip = VTOI(vp); | |
| 984263bc MD |
205 | |
| 206 | vap->va_fsid = dev2udev(ip->i_dev); | |
| 207 | vap->va_fileid = ip->i_number; | |
| 208 | ||
| 209 | vap->va_mode = ip->inode.iso_mode; | |
| 210 | vap->va_nlink = ip->inode.iso_links; | |
| 211 | vap->va_uid = ip->inode.iso_uid; | |
| 212 | vap->va_gid = ip->inode.iso_gid; | |
| 213 | vap->va_atime = ip->inode.iso_atime; | |
| 214 | vap->va_mtime = ip->inode.iso_mtime; | |
| 215 | vap->va_ctime = ip->inode.iso_ctime; | |
| 0e9b9130 MD |
216 | vap->va_rmajor = umajor(ip->inode.iso_rdev); |
| 217 | vap->va_rminor = uminor(ip->inode.iso_rdev); | |
| 984263bc | 218 | |
| 6d7c7288 | 219 | vap->va_size = (u_quad_t)(unsigned long)ip->i_size; |
| 984263bc MD |
220 | if (ip->i_size == 0 && (vap->va_mode & S_IFMT) == S_IFLNK) { |
| 221 | struct vop_readlink_args rdlnk; | |
| 222 | struct iovec aiov; | |
| 223 | struct uio auio; | |
| 224 | char *cp; | |
| 225 | ||
| 226 | MALLOC(cp, char *, MAXPATHLEN, M_TEMP, M_WAITOK); | |
| 227 | aiov.iov_base = cp; | |
| 228 | aiov.iov_len = MAXPATHLEN; | |
| 229 | auio.uio_iov = &aiov; | |
| 230 | auio.uio_iovcnt = 1; | |
| 231 | auio.uio_offset = 0; | |
| 232 | auio.uio_rw = UIO_READ; | |
| 233 | auio.uio_segflg = UIO_SYSSPACE; | |
| 87de5057 | 234 | auio.uio_td = curthread; |
| 984263bc MD |
235 | auio.uio_resid = MAXPATHLEN; |
| 236 | rdlnk.a_uio = &auio; | |
| 237 | rdlnk.a_vp = ap->a_vp; | |
| 3b568787 | 238 | rdlnk.a_cred = proc0.p_ucred; /* use root cred */ |
| 984263bc MD |
239 | if (cd9660_readlink(&rdlnk) == 0) |
| 240 | vap->va_size = MAXPATHLEN - auio.uio_resid; | |
| 241 | FREE(cp, M_TEMP); | |
| 242 | } | |
| 243 | vap->va_flags = 0; | |
| 244 | vap->va_gen = 1; | |
| 245 | vap->va_blocksize = ip->i_mnt->logical_block_size; | |
| 246 | vap->va_bytes = (u_quad_t) ip->i_size; | |
| 247 | vap->va_type = vp->v_type; | |
| 248 | vap->va_filerev = 0; | |
| 249 | return (0); | |
| 250 | } | |
| 251 | ||
| 252 | /* | |
| 253 | * Vnode op for ioctl. | |
| 3fa8192b CP |
254 | * |
| 255 | * cd9660_ioctl(struct vnode *a_vp, int a_command, caddr_t a_data, | |
| 256 | * int a_fflag, struct ucred *a_cred, struct proc *a_p) | |
| 984263bc MD |
257 | */ |
| 258 | static int | |
| 3fa8192b | 259 | cd9660_ioctl(struct vop_ioctl_args *ap) |
| 984263bc MD |
260 | { |
| 261 | struct vnode *vp = ap->a_vp; | |
| 262 | struct iso_node *ip = VTOI(vp); | |
| 263 | ||
| 264 | switch (ap->a_command) { | |
| 265 | ||
| 266 | case FIOGETLBA: | |
| 267 | *(int *)(ap->a_data) = ip->iso_start; | |
| 268 | return 0; | |
| 269 | default: | |
| 270 | return (ENOTTY); | |
| 271 | } | |
| 272 | } | |
| 273 | ||
| 274 | /* | |
| 7540ab49 MD |
275 | * open is called when the kernel intends to read or memory map a vnode. |
| 276 | */ | |
| 277 | static int | |
| 278 | cd9660_open(struct vop_open_args *ap) | |
| 279 | { | |
| 8ddc6004 | 280 | return(vop_stdopen(ap)); |
| 7540ab49 MD |
281 | } |
| 282 | ||
| 283 | /* | |
| 984263bc | 284 | * Vnode op for reading. |
| 3fa8192b CP |
285 | * |
| 286 | * cd9660_read(struct vnode *a_vp, struct uio *a_uio, int a_ioflag, | |
| 287 | * struct ucred *a_cred) | |
| 984263bc MD |
288 | */ |
| 289 | static int | |
| 3fa8192b | 290 | cd9660_read(struct vop_read_args *ap) |
| 984263bc MD |
291 | { |
| 292 | struct vnode *vp = ap->a_vp; | |
| 3a1b0fdc RG |
293 | struct uio *uio = ap->a_uio; |
| 294 | struct iso_node *ip = VTOI(vp); | |
| 295 | struct iso_mnt *imp; | |
| 984263bc MD |
296 | struct buf *bp; |
| 297 | daddr_t lbn, rablock; | |
| 54078292 MD |
298 | off_t raoffset; |
| 299 | off_t loffset; | |
| 984263bc MD |
300 | off_t diff; |
| 301 | int rasize, error = 0; | |
| 302 | int seqcount; | |
| 303 | long size, n, on; | |
| 304 | ||
| 305 | seqcount = ap->a_ioflag >> 16; | |
| 306 | ||
| 307 | if (uio->uio_resid == 0) | |
| 308 | return (0); | |
| 309 | if (uio->uio_offset < 0) | |
| 310 | return (EINVAL); | |
| 311 | ip->i_flag |= IN_ACCESS; | |
| 312 | imp = ip->i_mnt; | |
| 313 | do { | |
| 314 | lbn = lblkno(imp, uio->uio_offset); | |
| 54078292 | 315 | loffset = lblktooff(imp, lbn); |
| 984263bc | 316 | on = blkoff(imp, uio->uio_offset); |
| e54488bb MD |
317 | n = szmin((u_int)(imp->logical_block_size - on), |
| 318 | uio->uio_resid); | |
| 984263bc MD |
319 | diff = (off_t)ip->i_size - uio->uio_offset; |
| 320 | if (diff <= 0) | |
| 321 | return (0); | |
| 322 | if (diff < n) | |
| 323 | n = diff; | |
| 324 | size = blksize(imp, ip, lbn); | |
| 325 | rablock = lbn + 1; | |
| 54078292 | 326 | raoffset = lblktooff(imp, rablock); |
| 984263bc | 327 | if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) { |
| e54488bb | 328 | if (raoffset < ip->i_size) { |
| 984263bc | 329 | error = cluster_read(vp, (off_t)ip->i_size, |
| e54488bb MD |
330 | loffset, size, |
| 331 | uio->uio_resid, | |
| 332 | (ap->a_ioflag >> 16), | |
| 333 | &bp); | |
| 334 | } else { | |
| 54078292 | 335 | error = bread(vp, loffset, size, &bp); |
| e54488bb | 336 | } |
| 984263bc MD |
337 | } else { |
| 338 | if (seqcount > 1 && | |
| 339 | lblktosize(imp, rablock) < ip->i_size) { | |
| 340 | rasize = blksize(imp, ip, rablock); | |
| 54078292 | 341 | error = breadn(vp, loffset, size, &raoffset, |
| 3b568787 | 342 | &rasize, 1, &bp); |
| 984263bc | 343 | } else |
| 54078292 | 344 | error = bread(vp, loffset, size, &bp); |
| 984263bc | 345 | } |
| e54488bb | 346 | n = imin(n, size - bp->b_resid); |
| 984263bc MD |
347 | if (error) { |
| 348 | brelse(bp); | |
| 349 | return (error); | |
| 350 | } | |
| 351 | ||
| 352 | error = uiomove(bp->b_data + on, (int)n, uio); | |
| 353 | brelse(bp); | |
| 354 | } while (error == 0 && uio->uio_resid > 0 && n != 0); | |
| 355 | return (error); | |
| 356 | } | |
| 357 | ||
| 01f31ab3 JS |
358 | /* struct dirent + enough space for the maximum supported size */ |
| 359 | struct iso_dirent { | |
| 360 | struct dirent de; | |
| 361 | char de_name[_DIRENT_RECLEN(NAME_MAX) - sizeof(struct dirent)]; | |
| 362 | }; | |
| 363 | ||
| 984263bc MD |
364 | /* |
| 365 | * Structure for reading directories | |
| 366 | */ | |
| 367 | struct isoreaddir { | |
| 01f31ab3 JS |
368 | struct iso_dirent saveent; |
| 369 | struct iso_dirent assocent; | |
| 370 | struct iso_dirent current; | |
| 984263bc MD |
371 | off_t saveoff; |
| 372 | off_t assocoff; | |
| 373 | off_t curroff; | |
| 374 | struct uio *uio; | |
| 375 | off_t uio_off; | |
| 376 | int eofflag; | |
| 84009d92 | 377 | off_t *cookies; |
| 984263bc MD |
378 | int ncookies; |
| 379 | }; | |
| 380 | ||
| 381 | int | |
| 3fa8192b | 382 | iso_uiodir(struct isoreaddir *idp, struct dirent *dp, off_t off) |
| 984263bc MD |
383 | { |
| 384 | int error; | |
| 385 | ||
| 386 | dp->d_name[dp->d_namlen] = 0; | |
| 984263bc | 387 | |
| 01f31ab3 | 388 | if (idp->uio->uio_resid < _DIRENT_DIRSIZ(dp)) { |
| 984263bc MD |
389 | idp->eofflag = 0; |
| 390 | return (-1); | |
| 391 | } | |
| 392 | ||
| 393 | if (idp->cookies) { | |
| 394 | if (idp->ncookies <= 0) { | |
| 395 | idp->eofflag = 0; | |
| 396 | return (-1); | |
| 397 | } | |
| 398 | ||
| 399 | *idp->cookies++ = off; | |
| 400 | --idp->ncookies; | |
| 401 | } | |
| 402 | ||
| 01f31ab3 | 403 | if ((error = uiomove((caddr_t) dp,_DIRENT_DIRSIZ(dp),idp->uio)) != 0) |
| 984263bc MD |
404 | return (error); |
| 405 | idp->uio_off = off; | |
| 406 | return (0); | |
| 407 | } | |
| 408 | ||
| 409 | int | |
| 3fa8192b | 410 | iso_shipdir(struct isoreaddir *idp) |
| 984263bc MD |
411 | { |
| 412 | struct dirent *dp; | |
| 413 | int cl, sl, assoc; | |
| 414 | int error; | |
| 415 | char *cname, *sname; | |
| 416 | ||
| 01f31ab3 JS |
417 | cl = idp->current.de.d_namlen; |
| 418 | cname = idp->current.de.d_name; | |
| 984263bc MD |
419 | assoc = (cl > 1) && (*cname == ASSOCCHAR); |
| 420 | if (assoc) { | |
| 421 | cl--; | |
| 422 | cname++; | |
| 423 | } | |
| 424 | ||
| 01f31ab3 | 425 | dp = &idp->saveent.de; |
| 984263bc MD |
426 | sname = dp->d_name; |
| 427 | if (!(sl = dp->d_namlen)) { | |
| 01f31ab3 | 428 | dp = &idp->assocent.de; |
| 984263bc MD |
429 | sname = dp->d_name + 1; |
| 430 | sl = dp->d_namlen - 1; | |
| 431 | } | |
| 432 | if (sl > 0) { | |
| 433 | if (sl != cl | |
| 434 | || bcmp(sname,cname,sl)) { | |
| 01f31ab3 JS |
435 | if (idp->assocent.de.d_namlen) { |
| 436 | if ((error = iso_uiodir(idp,&idp->assocent.de,idp->assocoff)) != 0) | |
| 984263bc | 437 | return (error); |
| 01f31ab3 | 438 | idp->assocent.de.d_namlen = 0; |
| 984263bc | 439 | } |
| 01f31ab3 JS |
440 | if (idp->saveent.de.d_namlen) { |
| 441 | if ((error = iso_uiodir(idp,&idp->saveent.de,idp->saveoff)) != 0) | |
| 984263bc | 442 | return (error); |
| 01f31ab3 | 443 | idp->saveent.de.d_namlen = 0; |
| 984263bc MD |
444 | } |
| 445 | } | |
| 446 | } | |
| 984263bc MD |
447 | if (assoc) { |
| 448 | idp->assocoff = idp->curroff; | |
| 01f31ab3 | 449 | bcopy(&idp->current,&idp->assocent,_DIRENT_DIRSIZ(&idp->current.de)); |
| 984263bc MD |
450 | } else { |
| 451 | idp->saveoff = idp->curroff; | |
| 01f31ab3 | 452 | bcopy(&idp->current,&idp->saveent,_DIRENT_DIRSIZ(&idp->current.de)); |
| 984263bc MD |
453 | } |
| 454 | return (0); | |
| 455 | } | |
| 456 | ||
| 457 | /* | |
| 458 | * Vnode op for readdir | |
| 3fa8192b CP |
459 | * |
| 460 | * cd9660_readdir(struct vnode *a_vp, struct uio *a_uio, struct ucred *a_cred, | |
| 84009d92 | 461 | * int *a_eofflag, int *a_ncookies, off_t *a_cookies) |
| 984263bc MD |
462 | */ |
| 463 | static int | |
| 3fa8192b | 464 | cd9660_readdir(struct vop_readdir_args *ap) |
| 984263bc | 465 | { |
| 3a1b0fdc | 466 | struct uio *uio = ap->a_uio; |
| 984263bc MD |
467 | struct isoreaddir *idp; |
| 468 | struct vnode *vdp = ap->a_vp; | |
| 469 | struct iso_node *dp; | |
| 470 | struct iso_mnt *imp; | |
| 471 | struct buf *bp = NULL; | |
| 472 | struct iso_directory_record *ep; | |
| 473 | int entryoffsetinblock; | |
| 474 | doff_t endsearch; | |
| 475 | u_long bmask; | |
| 476 | int error = 0; | |
| 477 | int reclen; | |
| 478 | u_short namelen; | |
| 479 | int ncookies = 0; | |
| 84009d92 | 480 | off_t *cookies = NULL; |
| 984263bc MD |
481 | |
| 482 | dp = VTOI(vdp); | |
| 483 | imp = dp->i_mnt; | |
| 484 | bmask = imp->im_bmask; | |
| 485 | ||
| 885ecb13 MD |
486 | if ((error = vn_lock(vdp, LK_EXCLUSIVE|LK_RETRY)) != 0) |
| 487 | return (error); | |
| 488 | ||
| 984263bc | 489 | MALLOC(idp, struct isoreaddir *, sizeof(*idp), M_TEMP, M_WAITOK); |
| 01f31ab3 | 490 | idp->saveent.de.d_namlen = idp->assocent.de.d_namlen = 0; |
| 984263bc MD |
491 | /* |
| 492 | * XXX | |
| 493 | * Is it worth trying to figure out the type? | |
| 494 | */ | |
| 01f31ab3 JS |
495 | idp->saveent.de.d_type = DT_UNKNOWN; |
| 496 | idp->assocent.de.d_type = DT_UNKNOWN; | |
| 497 | idp->current.de.d_type = DT_UNKNOWN; | |
| 984263bc MD |
498 | idp->uio = uio; |
| 499 | if (ap->a_ncookies == NULL) { | |
| 500 | idp->cookies = NULL; | |
| 501 | } else { | |
| 502 | /* | |
| fb0466c9 MD |
503 | * Guess the number of cookies needed. Guess at least |
| 504 | * 1 to avoid a degenerate case in malloc, and cap at | |
| 505 | * a reasonable limit. | |
| 984263bc | 506 | */ |
| fb0466c9 MD |
507 | ncookies = uio->uio_resid / 16 + 1; |
| 508 | if (ncookies > 1024) | |
| 509 | ncookies = 1024; | |
| 84009d92 | 510 | MALLOC(cookies, off_t *, ncookies * sizeof(off_t), |
| fb0466c9 | 511 | M_TEMP, M_WAITOK); |
| 984263bc MD |
512 | idp->cookies = cookies; |
| 513 | idp->ncookies = ncookies; | |
| 514 | } | |
| 515 | idp->eofflag = 1; | |
| 516 | idp->curroff = uio->uio_offset; | |
| 517 | ||
| 518 | if ((entryoffsetinblock = idp->curroff & bmask) && | |
| 899483f5 | 519 | (error = cd9660_devblkatoff(vdp, (off_t)idp->curroff, NULL, &bp))) { |
| 984263bc | 520 | FREE(idp, M_TEMP); |
| 885ecb13 | 521 | goto done; |
| 984263bc MD |
522 | } |
| 523 | endsearch = dp->i_size; | |
| 524 | ||
| 525 | while (idp->curroff < endsearch) { | |
| 526 | /* | |
| 527 | * If offset is on a block boundary, | |
| 528 | * read the next directory block. | |
| 529 | * Release previous if it exists. | |
| 530 | */ | |
| 531 | if ((idp->curroff & bmask) == 0) { | |
| 532 | if (bp != NULL) | |
| 533 | brelse(bp); | |
| 534 | if ((error = | |
| 899483f5 | 535 | cd9660_devblkatoff(vdp, (off_t)idp->curroff, NULL, &bp)) != 0) |
| 984263bc MD |
536 | break; |
| 537 | entryoffsetinblock = 0; | |
| 538 | } | |
| 539 | /* | |
| 540 | * Get pointer to next entry. | |
| 541 | */ | |
| 542 | ep = (struct iso_directory_record *) | |
| 543 | ((char *)bp->b_data + entryoffsetinblock); | |
| 544 | ||
| 545 | reclen = isonum_711(ep->length); | |
| 546 | if (reclen == 0) { | |
| 547 | /* skip to next block, if any */ | |
| 548 | idp->curroff = | |
| 549 | (idp->curroff & ~bmask) + imp->logical_block_size; | |
| 550 | continue; | |
| 551 | } | |
| 552 | ||
| 553 | if (reclen < ISO_DIRECTORY_RECORD_SIZE) { | |
| 554 | error = EINVAL; | |
| 555 | /* illegal entry, stop */ | |
| 556 | break; | |
| 557 | } | |
| 558 | ||
| 559 | if (entryoffsetinblock + reclen > imp->logical_block_size) { | |
| 560 | error = EINVAL; | |
| 561 | /* illegal directory, so stop looking */ | |
| 562 | break; | |
| 563 | } | |
| 564 | ||
| 01f31ab3 | 565 | idp->current.de.d_namlen = isonum_711(ep->name_len); |
| 984263bc | 566 | |
| 01f31ab3 | 567 | if (reclen < ISO_DIRECTORY_RECORD_SIZE + idp->current.de.d_namlen) { |
| 984263bc MD |
568 | error = EINVAL; |
| 569 | /* illegal entry, stop */ | |
| 570 | break; | |
| 571 | } | |
| 572 | ||
| 573 | if (isonum_711(ep->flags)&2) | |
| 01f31ab3 | 574 | idp->current.de.d_ino = isodirino(ep, imp); |
| 984263bc | 575 | else |
| 899483f5 | 576 | idp->current.de.d_ino = bp->b_bio1.bio_offset + |
| 54078292 | 577 | entryoffsetinblock; |
| 984263bc MD |
578 | |
| 579 | idp->curroff += reclen; | |
| 580 | ||
| 581 | switch (imp->iso_ftype) { | |
| 582 | case ISO_FTYPE_RRIP: | |
| f91a71dd | 583 | { |
| 01f31ab3 JS |
584 | ino_t cur_fileno = idp->current.de.d_ino; |
| 585 | cd9660_rrip_getname(ep,idp->current.de.d_name, &namelen, | |
| f91a71dd | 586 | &cur_fileno,imp); |
| 01f31ab3 JS |
587 | idp->current.de.d_ino = cur_fileno; |
| 588 | idp->current.de.d_namlen = namelen; | |
| 589 | if (idp->current.de.d_namlen) | |
| 590 | error = iso_uiodir(idp,&idp->current.de,idp->curroff); | |
| 984263bc | 591 | break; |
| f91a71dd | 592 | } |
| 984263bc | 593 | default: /* ISO_FTYPE_DEFAULT || ISO_FTYPE_9660 || ISO_FTYPE_HIGH_SIERRA*/ |
| 01f31ab3 JS |
594 | strcpy(idp->current.de.d_name,".."); |
| 595 | if (idp->current.de.d_namlen == 1 && ep->name[0] == 0) { | |
| 596 | idp->current.de.d_namlen = 1; | |
| 597 | error = iso_uiodir(idp,&idp->current.de,idp->curroff); | |
| 598 | } else if (idp->current.de.d_namlen == 1 && ep->name[0] == 1) { | |
| 599 | idp->current.de.d_namlen = 2; | |
| 600 | error = iso_uiodir(idp,&idp->current.de,idp->curroff); | |
| 984263bc | 601 | } else { |
| 01f31ab3 JS |
602 | isofntrans(ep->name,idp->current.de.d_namlen, |
| 603 | idp->current.de.d_name, &namelen, | |
| 984263bc MD |
604 | imp->iso_ftype == ISO_FTYPE_9660, |
| 605 | isonum_711(ep->flags)&4, | |
| 606 | imp->joliet_level); | |
| 01f31ab3 | 607 | idp->current.de.d_namlen = namelen; |
| 984263bc MD |
608 | if (imp->iso_ftype == ISO_FTYPE_DEFAULT) |
| 609 | error = iso_shipdir(idp); | |
| 610 | else | |
| 01f31ab3 | 611 | error = iso_uiodir(idp,&idp->current.de,idp->curroff); |
| 984263bc MD |
612 | } |
| 613 | } | |
| 614 | if (error) | |
| 615 | break; | |
| 616 | ||
| 617 | entryoffsetinblock += reclen; | |
| 618 | } | |
| 619 | ||
| 620 | if (!error && imp->iso_ftype == ISO_FTYPE_DEFAULT) { | |
| 01f31ab3 | 621 | idp->current.de.d_namlen = 0; |
| 984263bc MD |
622 | error = iso_shipdir(idp); |
| 623 | } | |
| 624 | if (error < 0) | |
| 625 | error = 0; | |
| 626 | ||
| 627 | if (ap->a_ncookies != NULL) { | |
| 628 | if (error) | |
| efda3bd0 | 629 | kfree(cookies, M_TEMP); |
| 984263bc MD |
630 | else { |
| 631 | /* | |
| 632 | * Work out the number of cookies actually used. | |
| 633 | */ | |
| 634 | *ap->a_ncookies = ncookies - idp->ncookies; | |
| 635 | *ap->a_cookies = cookies; | |
| 636 | } | |
| 637 | } | |
| 638 | ||
| 639 | if (bp) | |
| 640 | brelse (bp); | |
| 641 | ||
| 642 | uio->uio_offset = idp->uio_off; | |
| 643 | *ap->a_eofflag = idp->eofflag; | |
| 644 | ||
| 645 | FREE(idp, M_TEMP); | |
| 646 | ||
| 885ecb13 MD |
647 | done: |
| 648 | vn_unlock(vdp); | |
| 984263bc MD |
649 | return (error); |
| 650 | } | |
| 651 | ||
| 652 | /* | |
| 653 | * Return target name of a symbolic link | |
| 654 | * Shouldn't we get the parent vnode and read the data from there? | |
| 655 | * This could eventually result in deadlocks in cd9660_lookup. | |
| 656 | * But otherwise the block read here is in the block buffer two times. | |
| 657 | */ | |
| 658 | typedef struct iso_directory_record ISODIR; | |
| 659 | typedef struct iso_node ISONODE; | |
| 660 | typedef struct iso_mnt ISOMNT; | |
| 3fa8192b CP |
661 | /* |
| 662 | * cd9660_readlink(struct vnode *a_vp, struct uio *a_uio, struct ucred *a_cred) | |
| 663 | */ | |
| 984263bc | 664 | static int |
| 3fa8192b | 665 | cd9660_readlink(struct vop_readlink_args *ap) |
| 984263bc MD |
666 | { |
| 667 | ISONODE *ip; | |
| 668 | ISODIR *dirp; | |
| 669 | ISOMNT *imp; | |
| 670 | struct buf *bp; | |
| 671 | struct uio *uio; | |
| 672 | u_short symlen; | |
| 673 | int error; | |
| 674 | char *symname; | |
| 675 | ||
| 676 | ip = VTOI(ap->a_vp); | |
| 677 | imp = ip->i_mnt; | |
| 678 | uio = ap->a_uio; | |
| 679 | ||
| 680 | if (imp->iso_ftype != ISO_FTYPE_RRIP) | |
| 681 | return (EINVAL); | |
| 682 | ||
| 683 | /* | |
| 684 | * Get parents directory record block that this inode included. | |
| 685 | */ | |
| 686 | error = bread(imp->im_devvp, | |
| 54078292 | 687 | (off_t)ip->i_number & ~((1 << imp->im_bshift) - 1), |
| 3b568787 | 688 | imp->logical_block_size, &bp); |
| 984263bc MD |
689 | if (error) { |
| 690 | brelse(bp); | |
| 691 | return (EINVAL); | |
| 692 | } | |
| 693 | ||
| 694 | /* | |
| 695 | * Setup the directory pointer for this inode | |
| 696 | */ | |
| 697 | dirp = (ISODIR *)(bp->b_data + (ip->i_number & imp->im_bmask)); | |
| 698 | ||
| 699 | /* | |
| 700 | * Just make sure, we have a right one.... | |
| 701 | * 1: Check not cross boundary on block | |
| 702 | */ | |
| 703 | if ((ip->i_number & imp->im_bmask) + isonum_711(dirp->length) | |
| 704 | > (unsigned)imp->logical_block_size) { | |
| 705 | brelse(bp); | |
| 706 | return (EINVAL); | |
| 707 | } | |
| 708 | ||
| 709 | /* | |
| 710 | * Now get a buffer | |
| 711 | * Abuse a namei buffer for now. | |
| 712 | */ | |
| 713 | if (uio->uio_segflg == UIO_SYSSPACE) | |
| 714 | symname = uio->uio_iov->iov_base; | |
| 715 | else | |
| 70aac194 | 716 | symname = objcache_get(namei_oc, M_WAITOK); |
| 984263bc MD |
717 | |
| 718 | /* | |
| 719 | * Ok, we just gathering a symbolic name in SL record. | |
| 720 | */ | |
| 721 | if (cd9660_rrip_getsymname(dirp, symname, &symlen, imp) == 0) { | |
| 722 | if (uio->uio_segflg != UIO_SYSSPACE) | |
| 70aac194 | 723 | objcache_put(namei_oc, symname); |
| 984263bc MD |
724 | brelse(bp); |
| 725 | return (EINVAL); | |
| 726 | } | |
| 727 | /* | |
| 728 | * Don't forget before you leave from home ;-) | |
| 729 | */ | |
| 730 | brelse(bp); | |
| 731 | ||
| 732 | /* | |
| 733 | * return with the symbolic name to caller's. | |
| 734 | */ | |
| 735 | if (uio->uio_segflg != UIO_SYSSPACE) { | |
| 736 | error = uiomove(symname, symlen, uio); | |
| 70aac194 | 737 | objcache_put(namei_oc, symname); |
| 984263bc MD |
738 | return (error); |
| 739 | } | |
| 740 | uio->uio_resid -= symlen; | |
| 656849c6 | 741 | uio->uio_iov->iov_base = (char *)uio->uio_iov->iov_base + symlen; |
| 984263bc MD |
742 | uio->uio_iov->iov_len -= symlen; |
| 743 | return (0); | |
| 744 | } | |
| 745 | ||
| 746 | /* | |
| 747 | * Calculate the logical to physical mapping if not done already, | |
| 748 | * then call the device strategy routine. | |
| 3fa8192b | 749 | * |
| 81b5c339 | 750 | * cd9660_strategy(struct buf *a_vp, struct buf *a_bio) |
| 984263bc MD |
751 | */ |
| 752 | static int | |
| 3fa8192b | 753 | cd9660_strategy(struct vop_strategy_args *ap) |
| 984263bc | 754 | { |
| 81b5c339 MD |
755 | struct bio *bio = ap->a_bio; |
| 756 | struct bio *nbio; | |
| 757 | struct buf *bp = bio->bio_buf; | |
| 758 | struct vnode *vp = ap->a_vp; | |
| 3a1b0fdc | 759 | struct iso_node *ip; |
| 984263bc MD |
760 | int error; |
| 761 | ||
| 762 | ip = VTOI(vp); | |
| 763 | if (vp->v_type == VBLK || vp->v_type == VCHR) | |
| 764 | panic("cd9660_strategy: spec"); | |
| 81b5c339 | 765 | nbio = push_bio(bio); |
| 54078292 | 766 | if (nbio->bio_offset == NOOFFSET) { |
| 08daea96 | 767 | error = VOP_BMAP(vp, bio->bio_offset, |
| e92ca23a | 768 | &nbio->bio_offset, NULL, NULL, bp->b_cmd); |
| 81b5c339 | 769 | if (error) { |
| 984263bc MD |
770 | bp->b_error = error; |
| 771 | bp->b_flags |= B_ERROR; | |
| 81b5c339 MD |
772 | /* I/O was never started on nbio, must biodone(bio) */ |
| 773 | biodone(bio); | |
| 984263bc MD |
774 | return (error); |
| 775 | } | |
| 54078292 | 776 | if (nbio->bio_offset == NOOFFSET) |
| 984263bc MD |
777 | clrbuf(bp); |
| 778 | } | |
| 54078292 | 779 | if (nbio->bio_offset == NOOFFSET) { |
| 81b5c339 MD |
780 | /* I/O was never started on nbio, must biodone(bio) */ |
| 781 | biodone(bio); | |
| 984263bc MD |
782 | return (0); |
| 783 | } | |
| 784 | vp = ip->i_devvp; | |
| 81b5c339 | 785 | vn_strategy(vp, nbio); |
| 984263bc MD |
786 | return (0); |
| 787 | } | |
| 788 | ||
| 789 | /* | |
| 790 | * Print out the contents of an inode. | |
| 3fa8192b CP |
791 | * |
| 792 | * cd9660_print(struct vnode *a_vp) | |
| 984263bc MD |
793 | */ |
| 794 | static int | |
| 3fa8192b | 795 | cd9660_print(struct vop_print_args *ap) |
| 984263bc | 796 | { |
| 086c1d7e | 797 | kprintf("tag VT_ISOFS, isofs vnode\n"); |
| 984263bc MD |
798 | return (0); |
| 799 | } | |
| 800 | ||
| 801 | /* | |
| 802 | * Return POSIX pathconf information applicable to cd9660 filesystems. | |
| 3fa8192b CP |
803 | * |
| 804 | * cd9660_pathconf(struct vnode *a_vp, int a_name, register_t *a_retval) | |
| 984263bc MD |
805 | */ |
| 806 | static int | |
| 3fa8192b | 807 | cd9660_pathconf(struct vop_pathconf_args *ap) |
| 984263bc | 808 | { |
| 984263bc MD |
809 | switch (ap->a_name) { |
| 810 | case _PC_LINK_MAX: | |
| 811 | *ap->a_retval = 1; | |
| 812 | return (0); | |
| 813 | case _PC_NAME_MAX: | |
| 814 | if (VTOI(ap->a_vp)->i_mnt->iso_ftype == ISO_FTYPE_RRIP) | |
| 815 | *ap->a_retval = NAME_MAX; | |
| 816 | else | |
| 817 | *ap->a_retval = 37; | |
| 818 | return (0); | |
| 819 | case _PC_PATH_MAX: | |
| 820 | *ap->a_retval = PATH_MAX; | |
| 821 | return (0); | |
| 822 | case _PC_PIPE_BUF: | |
| 823 | *ap->a_retval = PIPE_BUF; | |
| 824 | return (0); | |
| 825 | case _PC_CHOWN_RESTRICTED: | |
| 826 | *ap->a_retval = 1; | |
| 827 | return (0); | |
| 828 | case _PC_NO_TRUNC: | |
| 829 | *ap->a_retval = 1; | |
| 830 | return (0); | |
| 831 | default: | |
| 832 | return (EINVAL); | |
| 833 | } | |
| 834 | /* NOTREACHED */ | |
| 835 | } | |
| 836 | ||
| 837 | /* | |
| f308cd58 DR |
838 | * Advisory lock support |
| 839 | */ | |
| 840 | static int | |
| b1ce5639 | 841 | cd9660_advlock(struct vop_advlock_args *ap) |
| f308cd58 DR |
842 | { |
| 843 | struct iso_node *ip = VTOI(ap->a_vp); | |
| 844 | return (lf_advlock(ap, &(ip->i_lockf), ip->i_size)); | |
| 845 | } | |
| 846 | ||
| 847 | ||
| 848 | /* | |
| 984263bc MD |
849 | * Global vfs data structures for cd9660 |
| 850 | */ | |
| 66a1ddf5 MD |
851 | struct vop_ops cd9660_vnode_vops = { |
| 852 | .vop_default = vop_defaultop, | |
| 853 | .vop_open = cd9660_open, | |
| 854 | .vop_access = cd9660_access, | |
| 855 | .vop_advlock = cd9660_advlock, | |
| 856 | .vop_bmap = cd9660_bmap, | |
| 857 | .vop_old_lookup = cd9660_lookup, | |
| 858 | .vop_getattr = cd9660_getattr, | |
| 859 | .vop_inactive = cd9660_inactive, | |
| 860 | .vop_ioctl = cd9660_ioctl, | |
| 66a1ddf5 MD |
861 | .vop_pathconf = cd9660_pathconf, |
| 862 | .vop_print = cd9660_print, | |
| 863 | .vop_read = cd9660_read, | |
| 864 | .vop_readdir = cd9660_readdir, | |
| 865 | .vop_readlink = cd9660_readlink, | |
| 866 | .vop_reclaim = cd9660_reclaim, | |
| 867 | .vop_setattr = cd9660_setattr, | |
| 868 | .vop_strategy = cd9660_strategy, | |
| 1787385d MD |
869 | .vop_getpages = vop_stdgetpages, |
| 870 | .vop_putpages = vop_stdputpages | |
| 984263bc | 871 | }; |
| 984263bc MD |
872 | |
| 873 | /* | |
| 874 | * Special device vnode ops | |
| 875 | */ | |
| 66a1ddf5 | 876 | struct vop_ops cd9660_spec_vops = { |
| 8be7edad MD |
877 | .vop_default = vop_defaultop, |
| 878 | .vop_read = vop_stdnoread, | |
| 66a1ddf5 MD |
879 | .vop_access = cd9660_access, |
| 880 | .vop_getattr = cd9660_getattr, | |
| 881 | .vop_inactive = cd9660_inactive, | |
| 66a1ddf5 MD |
882 | .vop_print = cd9660_print, |
| 883 | .vop_reclaim = cd9660_reclaim, | |
| 884 | .vop_setattr = cd9660_setattr, | |
| 984263bc | 885 | }; |
| 984263bc | 886 | |
| 66a1ddf5 MD |
887 | struct vop_ops cd9660_fifo_vops = { |
| 888 | .vop_default = fifo_vnoperate, | |
| 889 | .vop_access = cd9660_access, | |
| 890 | .vop_getattr = cd9660_getattr, | |
| 891 | .vop_inactive = cd9660_inactive, | |
| 66a1ddf5 MD |
892 | .vop_print = cd9660_print, |
| 893 | .vop_reclaim = cd9660_reclaim, | |
| 894 | .vop_setattr = cd9660_setattr, | |
| 984263bc | 895 | }; |
| 984263bc | 896 |