xref: /openbsd/sys/isofs/cd9660/cd9660_vnops.c (revision 3cab2bb3)
1 /*	$OpenBSD: cd9660_vnops.c,v 1.85 2020/06/11 09:18:43 mpi Exp $	*/
2 /*	$NetBSD: cd9660_vnops.c,v 1.42 1997/10/16 23:56:57 christos Exp $	*/
3 
4 /*-
5  * Copyright (c) 1994
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley
9  * by Pace Willisson (pace@blitz.com).  The Rock Ridge Extension
10  * Support code is derived from software contributed to Berkeley
11  * by Atsushi Murai (amurai@spec.co.jp).
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  * 3. Neither the name of the University nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  *
37  *	@(#)cd9660_vnops.c	8.15 (Berkeley) 12/5/94
38  */
39 
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/namei.h>
43 #include <sys/resourcevar.h>
44 #include <sys/kernel.h>
45 #include <sys/file.h>
46 #include <sys/stat.h>
47 #include <sys/buf.h>
48 #include <sys/conf.h>
49 #include <sys/mount.h>
50 #include <sys/vnode.h>
51 #include <sys/lock.h>
52 #include <sys/malloc.h>
53 #include <sys/pool.h>
54 #include <sys/dirent.h>
55 #include <sys/ioctl.h>
56 #include <sys/ioccom.h>
57 #include <sys/poll.h>
58 #include <sys/specdev.h>
59 #include <sys/unistd.h>
60 
61 #include <miscfs/fifofs/fifo.h>
62 
63 #include <isofs/cd9660/iso.h>
64 #include <isofs/cd9660/cd9660_extern.h>
65 #include <isofs/cd9660/cd9660_node.h>
66 #include <isofs/cd9660/iso_rrip.h>
67 
68 int cd9660_kqfilter(void *v);
69 
70 
71 /*
72  * Structure for reading directories
73  */
74 struct isoreaddir {
75 	struct dirent saveent;
76 	struct dirent assocent;
77 	struct dirent current;
78 	off_t saveoff;
79 	off_t assocoff;
80 	off_t curroff;
81 	struct uio *uio;
82 	off_t uio_off;
83 	int eofflag;
84 };
85 
86 int	iso_uiodir(struct isoreaddir *, struct dirent *, off_t);
87 int	iso_shipdir(struct isoreaddir *);
88 
89 /*
90  * Setattr call. Only allowed for block and character special devices.
91  */
92 int
93 cd9660_setattr(void *v)
94 {
95 	struct vop_setattr_args *ap = v;
96 	struct vnode *vp = ap->a_vp;
97 	struct vattr *vap = ap->a_vap;
98 
99 	if (vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL ||
100 	    vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_nsec != VNOVAL ||
101 	    vap->va_mtime.tv_nsec != VNOVAL || vap->va_mode != (mode_t)VNOVAL ||
102 	    (vap->va_vaflags & VA_UTIMES_CHANGE))
103 		return (EROFS);
104 	if (vap->va_size != VNOVAL) {
105 		switch (vp->v_type) {
106 		case VDIR:
107 			return (EISDIR);
108 		case VLNK:
109 		case VREG:
110 			return (EROFS);
111 		case VCHR:
112 		case VBLK:
113 		case VSOCK:
114 		case VFIFO:
115 			return (0);
116 		default:
117 			return (EINVAL);
118 		}
119 	}
120 
121 	return (EINVAL);
122 }
123 
124 /*
125  * Open called.
126  *
127  * Nothing to do.
128  */
129 /* ARGSUSED */
130 int
131 cd9660_open(void *v)
132 {
133 	return (0);
134 }
135 
136 /*
137  * Close called
138  *
139  * Update the times on the inode on writeable file systems.
140  */
141 /* ARGSUSED */
142 int
143 cd9660_close(void *v)
144 {
145 	return (0);
146 }
147 
148 /*
149  * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC.
150  * The mode is shifted to select the owner/group/other fields. The
151  * super user is granted all permissions.
152  */
153 int
154 cd9660_access(void *v)
155 {
156 	struct vop_access_args *ap = v;
157 	struct iso_node *ip = VTOI(ap->a_vp);
158 
159 	return (vaccess(ap->a_vp->v_type, ip->inode.iso_mode & ALLPERMS,
160 	    ip->inode.iso_uid, ip->inode.iso_gid, ap->a_mode, ap->a_cred));
161 }
162 
163 int
164 cd9660_getattr(void *v)
165 {
166 	struct vop_getattr_args *ap = v;
167 	struct vnode *vp = ap->a_vp;
168 	register struct vattr *vap = ap->a_vap;
169 	register struct iso_node *ip = VTOI(vp);
170 
171 	vap->va_fsid	= ip->i_dev;
172 	vap->va_fileid	= ip->i_number;
173 
174 	vap->va_mode	= ip->inode.iso_mode & ALLPERMS;
175 	vap->va_nlink	= ip->inode.iso_links;
176 	vap->va_uid	= ip->inode.iso_uid;
177 	vap->va_gid	= ip->inode.iso_gid;
178 	vap->va_atime	= ip->inode.iso_atime;
179 	vap->va_mtime	= ip->inode.iso_mtime;
180 	vap->va_ctime	= ip->inode.iso_ctime;
181 	vap->va_rdev	= ip->inode.iso_rdev;
182 
183 	vap->va_size	= (u_quad_t) ip->i_size;
184 	if (ip->i_size == 0 && vp->v_type  == VLNK) {
185 		struct vop_readlink_args rdlnk;
186 		struct iovec aiov;
187 		struct uio auio;
188 		char *cp;
189 
190 		cp = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
191 		aiov.iov_base = cp;
192 		aiov.iov_len = MAXPATHLEN;
193 		auio.uio_iov = &aiov;
194 		auio.uio_iovcnt = 1;
195 		auio.uio_offset = 0;
196 		auio.uio_rw = UIO_READ;
197 		auio.uio_segflg = UIO_SYSSPACE;
198 		auio.uio_procp = ap->a_p;
199 		auio.uio_resid = MAXPATHLEN;
200 		rdlnk.a_uio = &auio;
201 		rdlnk.a_vp = ap->a_vp;
202 		rdlnk.a_cred = ap->a_cred;
203 		if (cd9660_readlink(&rdlnk) == 0)
204 			vap->va_size = MAXPATHLEN - auio.uio_resid;
205 		free(cp, M_TEMP, 0);
206 	}
207 	vap->va_flags	= 0;
208 	vap->va_gen = 1;
209 	vap->va_blocksize = ip->i_mnt->logical_block_size;
210 	vap->va_bytes	= (u_quad_t) ip->i_size;
211 	vap->va_type	= vp->v_type;
212 	return (0);
213 }
214 
215 /*
216  * Vnode op for reading.
217  */
218 int
219 cd9660_read(void *v)
220 {
221 	struct vop_read_args *ap = v;
222 	struct vnode *vp = ap->a_vp;
223 	register struct uio *uio = ap->a_uio;
224 	register struct iso_node *ip = VTOI(vp);
225 	register struct iso_mnt *imp;
226 	struct buf *bp;
227 	daddr_t lbn, rablock;
228 	off_t diff;
229 	int error = 0;
230 	long size, on;
231 	size_t n;
232 
233 	if (uio->uio_resid == 0)
234 		return (0);
235 	if (uio->uio_offset < 0)
236 		return (EINVAL);
237 	ip->i_flag |= IN_ACCESS;
238 	imp = ip->i_mnt;
239 	do {
240 		struct cluster_info *ci = &ip->i_ci;
241 
242 		lbn = lblkno(imp, uio->uio_offset);
243 		on = blkoff(imp, uio->uio_offset);
244 		n = ulmin(imp->logical_block_size - on, uio->uio_resid);
245 		diff = (off_t)ip->i_size - uio->uio_offset;
246 		if (diff <= 0)
247 			return (0);
248 		if (diff < n)
249 			n = diff;
250 		size = blksize(imp, ip, lbn);
251 		rablock = lbn + 1;
252 #define MAX_RA 32
253 		if (ci->ci_lastr + 1 == lbn) {
254 			struct ra {
255 				daddr_t blks[MAX_RA];
256 				int sizes[MAX_RA];
257 			} *ra;
258 			int i;
259 
260 			ra = malloc(sizeof *ra, M_TEMP, M_WAITOK);
261 			for (i = 0; i < MAX_RA &&
262 			    lblktosize(imp, (rablock + i)) < ip->i_size;
263 			    i++) {
264 				ra->blks[i] = rablock + i;
265 				ra->sizes[i] = blksize(imp, ip, rablock + i);
266 			}
267 			error = breadn(vp, lbn, size, ra->blks,
268 			    ra->sizes, i, &bp);
269 			free(ra, M_TEMP, 0);
270 		} else
271 			error = bread(vp, lbn, size, &bp);
272 		ci->ci_lastr = lbn;
273 		n = ulmin(n, size - bp->b_resid);
274 		if (error) {
275 			brelse(bp);
276 			return (error);
277 		}
278 
279 		error = uiomove(bp->b_data + on, n, uio);
280 
281 		brelse(bp);
282 	} while (error == 0 && uio->uio_resid > 0 && n != 0);
283 	return (error);
284 }
285 
286 /* ARGSUSED */
287 int
288 cd9660_ioctl(void *v)
289 {
290 	return (ENOTTY);
291 }
292 
293 /* ARGSUSED */
294 int
295 cd9660_poll(void *v)
296 {
297 	struct vop_poll_args *ap = v;
298 
299 	/*
300 	 * We should really check to see if I/O is possible.
301 	 */
302 	return (ap->a_events & (POLLIN | POLLOUT | POLLRDNORM | POLLWRNORM));
303 }
304 
305 /*
306  * Mmap a file
307  *
308  * NB Currently unsupported.
309  */
310 /* ARGSUSED */
311 int
312 cd9660_mmap(void *v)
313 {
314 
315 	return (EINVAL);
316 }
317 
318 /*
319  * Seek on a file
320  *
321  * Nothing to do, so just return.
322  */
323 /* ARGSUSED */
324 int
325 cd9660_seek(void *v)
326 {
327 	return (0);
328 }
329 
330 int
331 iso_uiodir(idp,dp,off)
332 	struct isoreaddir *idp;
333 	struct dirent *dp;
334 	off_t off;
335 {
336 	int error;
337 
338 	dp->d_name[dp->d_namlen] = 0;
339 	dp->d_reclen = DIRENT_SIZE(dp);
340 
341 	if (idp->uio->uio_resid < dp->d_reclen) {
342 		idp->eofflag = 0;
343 		return (-1);
344 	}
345 
346 	dp->d_off = off;
347 	if ((error = uiomove(dp, dp->d_reclen, idp->uio)) != 0)
348 		return (error);
349 	idp->uio_off = off;
350 	return (0);
351 }
352 
353 int
354 iso_shipdir(idp)
355 	struct isoreaddir *idp;
356 {
357 	struct dirent *dp;
358 	int cl, sl, assoc;
359 	int error;
360 	char *cname, *sname;
361 
362 	cl = idp->current.d_namlen;
363 	cname = idp->current.d_name;
364 
365 	if ((assoc = cl > 1 && *cname == ASSOCCHAR)) {
366 		cl--;
367 		cname++;
368 	}
369 
370 	dp = &idp->saveent;
371 	sname = dp->d_name;
372 	if (!(sl = dp->d_namlen)) {
373 		dp = &idp->assocent;
374 		sname = dp->d_name + 1;
375 		sl = dp->d_namlen - 1;
376 	}
377 	if (sl > 0) {
378 		if (sl != cl
379 		    || bcmp(sname,cname,sl)) {
380 			if (idp->assocent.d_namlen) {
381 				error = iso_uiodir(idp, &idp->assocent,
382 						   idp->assocoff);
383 				if (error)
384 					return (error);
385 				idp->assocent.d_namlen = 0;
386 			}
387 			if (idp->saveent.d_namlen) {
388 				error = iso_uiodir(idp, &idp->saveent,
389 						   idp->saveoff);
390 				if (error)
391 					return (error);
392 				idp->saveent.d_namlen = 0;
393 			}
394 		}
395 	}
396 	idp->current.d_reclen = DIRENT_SIZE(&idp->current);
397 	if (assoc) {
398 		idp->assocoff = idp->curroff;
399 		bcopy(&idp->current,&idp->assocent,idp->current.d_reclen);
400 	} else {
401 		idp->saveoff = idp->curroff;
402 		bcopy(&idp->current,&idp->saveent,idp->current.d_reclen);
403 	}
404 	return (0);
405 }
406 
407 /*
408  * Vnode op for readdir
409  */
410 int
411 cd9660_readdir(void *v)
412 {
413 	struct vop_readdir_args *ap = v;
414 	register struct uio *uio = ap->a_uio;
415 	struct isoreaddir *idp;
416 	struct vnode *vdp = ap->a_vp;
417 	struct iso_node *dp;
418 	struct iso_mnt *imp;
419 	struct buf *bp = NULL;
420 	struct iso_directory_record *ep;
421 	int entryoffsetinblock;
422 	doff_t endsearch;
423 	u_long bmask;
424 	int error = 0;
425 	int reclen;
426 	u_short namelen;
427 	cdino_t ino;
428 
429 	dp = VTOI(vdp);
430 	imp = dp->i_mnt;
431 	bmask = imp->im_bmask;
432 
433 	idp = malloc(sizeof(*idp), M_TEMP, M_WAITOK);
434 
435 	/*
436 	 * These are passed to copyout(), so make sure there's no garbage
437 	 * being leaked in padding or after short names.
438 	 */
439 	memset(&idp->saveent, 0, sizeof(idp->saveent));
440 	memset(&idp->assocent, 0, sizeof(idp->assocent));
441 	memset(&idp->current, 0, sizeof(idp->current));
442 
443 	/*
444 	 * XXX
445 	 * Is it worth trying to figure out the type?
446 	 */
447 	idp->saveent.d_type = idp->assocent.d_type = idp->current.d_type =
448 	    DT_UNKNOWN;
449 	idp->uio = uio;
450 	idp->eofflag = 1;
451 	idp->curroff = uio->uio_offset;
452 	idp->uio_off = uio->uio_offset;
453 
454 	if ((entryoffsetinblock = idp->curroff & bmask) &&
455 	    (error = cd9660_bufatoff(dp, (off_t)idp->curroff, NULL, &bp))) {
456 		free(idp, M_TEMP, 0);
457 		return (error);
458 	}
459 	endsearch = dp->i_size;
460 
461 	while (idp->curroff < endsearch) {
462 		/*
463 		 * If offset is on a block boundary,
464 		 * read the next directory block.
465 		 * Release previous if it exists.
466 		 */
467 		if ((idp->curroff & bmask) == 0) {
468 			if (bp != NULL)
469 				brelse(bp);
470 			error = cd9660_bufatoff(dp, (off_t)idp->curroff,
471 					     NULL, &bp);
472 			if (error)
473 				break;
474 			entryoffsetinblock = 0;
475 		}
476 		/*
477 		 * Get pointer to next entry.
478 		 */
479 		ep = (struct iso_directory_record *)
480 			((char *)bp->b_data + entryoffsetinblock);
481 
482 		reclen = isonum_711(ep->length);
483 		if (reclen == 0) {
484 			/* skip to next block, if any */
485 			idp->curroff =
486 			    (idp->curroff & ~bmask) + imp->logical_block_size;
487 			continue;
488 		}
489 
490 		if (reclen < ISO_DIRECTORY_RECORD_SIZE) {
491 			error = EINVAL;
492 			/* illegal entry, stop */
493 			break;
494 		}
495 
496 		if (entryoffsetinblock + reclen > imp->logical_block_size) {
497 			error = EINVAL;
498 			/* illegal directory, so stop looking */
499 			break;
500 		}
501 
502 		idp->current.d_namlen = isonum_711(ep->name_len);
503 
504 		if (reclen < ISO_DIRECTORY_RECORD_SIZE + idp->current.d_namlen) {
505 			error = EINVAL;
506 			/* illegal entry, stop */
507 			break;
508 		}
509 
510 		if (isonum_711(ep->flags)&2)
511 			ino = isodirino(ep, imp);
512 		else
513 			ino = dbtob(bp->b_blkno) + entryoffsetinblock;
514 
515 		idp->curroff += reclen;
516 
517 		switch (imp->iso_ftype) {
518 		case ISO_FTYPE_RRIP:
519 			cd9660_rrip_getname(ep,idp->current.d_name, &namelen,
520 					   &ino, imp);
521 			idp->current.d_fileno = ino;
522 			idp->current.d_namlen = (u_char)namelen;
523 			if (idp->current.d_namlen)
524 				error = iso_uiodir(idp,&idp->current,idp->curroff);
525 			break;
526 		default:	/* ISO_FTYPE_DEFAULT || ISO_FTYPE_9660 */
527 			idp->current.d_fileno = ino;
528 			strlcpy(idp->current.d_name,"..",
529 			    sizeof idp->current.d_name);
530 			if (idp->current.d_namlen == 1 && ep->name[0] == 0) {
531 				idp->current.d_namlen = 1;
532 				error = iso_uiodir(idp,&idp->current,idp->curroff);
533 			} else if (idp->current.d_namlen == 1 &&
534 			    ep->name[0] == 1) {
535 				idp->current.d_namlen = 2;
536 				error = iso_uiodir(idp,&idp->current,idp->curroff);
537 			} else {
538 				isofntrans(ep->name,idp->current.d_namlen,
539 					   idp->current.d_name, &namelen,
540 					   imp->iso_ftype == ISO_FTYPE_9660,
541 					   isonum_711(ep->flags) & 4,
542 					   imp->joliet_level);
543 				idp->current.d_namlen = (u_char)namelen;
544 				if (imp->iso_ftype == ISO_FTYPE_DEFAULT)
545 					error = iso_shipdir(idp);
546 				else
547 					error = iso_uiodir(idp,&idp->current,idp->curroff);
548 			}
549 		}
550 		if (error)
551 			break;
552 
553 		entryoffsetinblock += reclen;
554 	}
555 
556 	if (!error && imp->iso_ftype == ISO_FTYPE_DEFAULT) {
557 		idp->current.d_namlen = 0;
558 		error = iso_shipdir(idp);
559 	}
560 	if (error < 0)
561 		error = 0;
562 
563 	if (bp)
564 		brelse (bp);
565 
566 	uio->uio_offset = idp->uio_off;
567 	*ap->a_eofflag = idp->eofflag;
568 
569 	free(idp, M_TEMP, 0);
570 
571 	return (error);
572 }
573 
574 /*
575  * Return target name of a symbolic link
576  * Shouldn't we get the parent vnode and read the data from there?
577  * This could eventually result in deadlocks in cd9660_lookup.
578  * But otherwise the block read here is in the block buffer two times.
579  */
580 typedef struct iso_directory_record ISODIR;
581 typedef struct iso_node             ISONODE;
582 typedef struct iso_mnt              ISOMNT;
583 int
584 cd9660_readlink(void *v)
585 {
586 	struct vop_readlink_args *ap = v;
587 	ISONODE	*ip;
588 	ISODIR	*dirp;
589 	ISOMNT	*imp;
590 	struct	buf *bp;
591 	struct	uio *uio;
592 	u_short	symlen;
593 	int	error;
594 	char	*symname;
595 
596 	ip  = VTOI(ap->a_vp);
597 	imp = ip->i_mnt;
598 	uio = ap->a_uio;
599 
600 	if (imp->iso_ftype != ISO_FTYPE_RRIP)
601 		return (EINVAL);
602 
603 	/*
604 	 * Get parents directory record block that this inode included.
605 	 */
606 	error = bread(imp->im_devvp,
607 		      (ip->i_number >> imp->im_bshift) <<
608 		      (imp->im_bshift - DEV_BSHIFT),
609 		      imp->logical_block_size, &bp);
610 	if (error) {
611 		brelse(bp);
612 		return (EINVAL);
613 	}
614 
615 	/*
616 	 * Setup the directory pointer for this inode
617 	 */
618 	dirp = (ISODIR *)(bp->b_data + (ip->i_number & imp->im_bmask));
619 
620 	/*
621 	 * Just make sure, we have a right one....
622 	 *   1: Check not cross boundary on block
623 	 */
624 	if ((ip->i_number & imp->im_bmask) + isonum_711(dirp->length)
625 	    > imp->logical_block_size) {
626 		brelse(bp);
627 		return (EINVAL);
628 	}
629 
630 	/*
631 	 * Now get a buffer
632 	 * Abuse a namei buffer for now.
633 	 */
634 	if (uio->uio_segflg == UIO_SYSSPACE &&
635 	    uio->uio_iov->iov_len >= MAXPATHLEN)
636 		symname = uio->uio_iov->iov_base;
637 	else
638 		symname = pool_get(&namei_pool, PR_WAITOK);
639 
640 	/*
641 	 * Ok, we just gathering a symbolic name in SL record.
642 	 */
643 	if (cd9660_rrip_getsymname(dirp, symname, &symlen, imp) == 0) {
644 		if (uio->uio_segflg != UIO_SYSSPACE ||
645 		    uio->uio_iov->iov_len < MAXPATHLEN)
646 			pool_put(&namei_pool, symname);
647 		brelse(bp);
648 		return (EINVAL);
649 	}
650 	/*
651 	 * Don't forget before you leave from home ;-)
652 	 */
653 	brelse(bp);
654 
655 	/*
656 	 * return with the symbolic name to caller's.
657 	 */
658 	if (uio->uio_segflg != UIO_SYSSPACE ||
659 	    uio->uio_iov->iov_len < MAXPATHLEN) {
660 		error = uiomove(symname, symlen, uio);
661 		pool_put(&namei_pool, symname);
662 		return (error);
663 	}
664 	uio->uio_resid -= symlen;
665 	uio->uio_iov->iov_base = (char *)uio->uio_iov->iov_base + symlen;
666 	uio->uio_iov->iov_len -= symlen;
667 	return (0);
668 }
669 
670 int
671 cd9660_link(void *v)
672 {
673 	struct vop_link_args *ap = v;
674 
675 	VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
676 	vput(ap->a_dvp);
677 	return (EROFS);
678 }
679 
680 int
681 cd9660_symlink(void *v)
682 {
683 	struct vop_symlink_args *ap = v;
684 
685 	VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
686 	vput(ap->a_dvp);
687 	return (EROFS);
688 }
689 
690 /*
691  * Lock an inode.
692  */
693 int
694 cd9660_lock(void *v)
695 {
696 	struct vop_lock_args *ap = v;
697 	struct vnode *vp = ap->a_vp;
698 
699 	return rrw_enter(&VTOI(vp)->i_lock, ap->a_flags & LK_RWFLAGS);
700 }
701 
702 /*
703  * Unlock an inode.
704  */
705 int
706 cd9660_unlock(void *v)
707 {
708 	struct vop_unlock_args *ap = v;
709 	struct vnode *vp = ap->a_vp;
710 
711 	rrw_exit(&VTOI(vp)->i_lock);
712 	return 0;
713 }
714 
715 /*
716  * Calculate the logical to physical mapping if not done already,
717  * then call the device strategy routine.
718  */
719 int
720 cd9660_strategy(void *v)
721 {
722 	struct vop_strategy_args *ap = v;
723 	struct buf *bp = ap->a_bp;
724 	struct vnode *vp = bp->b_vp;
725 	struct iso_node *ip;
726 	int error;
727 	int s;
728 
729 	ip = VTOI(vp);
730 	if (vp->v_type == VBLK || vp->v_type == VCHR)
731 		panic("cd9660_strategy: spec");
732 	if (bp->b_blkno == bp->b_lblkno) {
733 		error = VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL);
734 		if (error) {
735 			bp->b_error = error;
736 			bp->b_flags |= B_ERROR;
737 			s = splbio();
738 			biodone(bp);
739 			splx(s);
740 			return (error);
741 		}
742 		if ((long)bp->b_blkno == -1)
743 			clrbuf(bp);
744 	}
745 	if ((long)bp->b_blkno == -1) {
746 		s = splbio();
747 		biodone(bp);
748 		splx(s);
749 		return (0);
750 	}
751 	vp = ip->i_devvp;
752 	bp->b_dev = vp->v_rdev;
753 	(vp->v_op->vop_strategy)(ap);
754 	return (0);
755 }
756 
757 /*
758  * Print out the contents of an inode.
759  */
760 /*ARGSUSED*/
761 int
762 cd9660_print(void *v)
763 {
764 	printf("tag VT_ISOFS, isofs vnode\n");
765 	return (0);
766 }
767 
768 /*
769  * Check for a locked inode.
770  */
771 int
772 cd9660_islocked(void *v)
773 {
774 	struct vop_islocked_args *ap = v;
775 
776 	return rrw_status(&VTOI(ap->a_vp)->i_lock);
777 }
778 
779 /*
780  * Return POSIX pathconf information applicable to cd9660 filesystems.
781  */
782 int
783 cd9660_pathconf(void *v)
784 {
785 	struct vop_pathconf_args *ap = v;
786 	int error = 0;
787 
788 	switch (ap->a_name) {
789 	case _PC_LINK_MAX:
790 		*ap->a_retval = 1;
791 		break;
792 	case _PC_NAME_MAX:
793 		if (VTOI(ap->a_vp)->i_mnt->iso_ftype == ISO_FTYPE_RRIP)
794 			*ap->a_retval = NAME_MAX;
795 		else
796 			*ap->a_retval = 37;
797 		break;
798 	case _PC_CHOWN_RESTRICTED:
799 		*ap->a_retval = 1;
800 		break;
801 	case _PC_NO_TRUNC:
802 		*ap->a_retval = 1;
803 		break;
804 	case _PC_TIMESTAMP_RESOLUTION:
805 		*ap->a_retval = 1000000000;	/* one billion nanoseconds */
806 		break;
807 	default:
808 		error = EINVAL;
809 		break;
810 	}
811 
812 	return (error);
813 }
814 
815 /*
816  * Global vfs data structures for isofs
817  */
818 #define	cd9660_create	eopnotsupp
819 #define	cd9660_mknod	eopnotsupp
820 #define	cd9660_write	eopnotsupp
821 #define	cd9660_fsync	nullop
822 #define	cd9660_remove	eopnotsupp
823 #define	cd9660_rename	eopnotsupp
824 #define	cd9660_mkdir	eopnotsupp
825 #define	cd9660_rmdir	eopnotsupp
826 #define	cd9660_advlock	eopnotsupp
827 #define	cd9660_valloc	eopnotsupp
828 #define	cd9660_vfree	eopnotsupp
829 #define	cd9660_truncate	eopnotsupp
830 #define	cd9660_update	eopnotsupp
831 #define	cd9660_bwrite	eopnotsupp
832 #define cd9660_revoke   vop_generic_revoke
833 
834 /* Global vfs data structures for cd9660. */
835 const struct vops cd9660_vops = {
836 	.vop_lookup	= cd9660_lookup,
837 	.vop_create	= cd9660_create,
838 	.vop_mknod	= cd9660_mknod,
839 	.vop_open	= cd9660_open,
840 	.vop_close	= cd9660_close,
841 	.vop_access	= cd9660_access,
842 	.vop_getattr	= cd9660_getattr,
843 	.vop_setattr	= cd9660_setattr,
844 	.vop_read	= cd9660_read,
845 	.vop_write	= cd9660_write,
846 	.vop_ioctl	= cd9660_ioctl,
847 	.vop_poll	= cd9660_poll,
848 	.vop_kqfilter	= cd9660_kqfilter,
849 	.vop_revoke	= cd9660_revoke,
850 	.vop_fsync	= cd9660_fsync,
851 	.vop_remove	= cd9660_remove,
852 	.vop_link	= cd9660_link,
853 	.vop_rename	= cd9660_rename,
854 	.vop_mkdir	= cd9660_mkdir,
855 	.vop_rmdir	= cd9660_rmdir,
856 	.vop_symlink	= cd9660_symlink,
857 	.vop_readdir	= cd9660_readdir,
858 	.vop_readlink	= cd9660_readlink,
859 	.vop_abortop	= vop_generic_abortop,
860 	.vop_inactive	= cd9660_inactive,
861 	.vop_reclaim	= cd9660_reclaim,
862 	.vop_lock	= cd9660_lock,
863 	.vop_unlock	= cd9660_unlock,
864 	.vop_bmap	= cd9660_bmap,
865 	.vop_strategy	= cd9660_strategy,
866 	.vop_print	= cd9660_print,
867 	.vop_islocked	= cd9660_islocked,
868 	.vop_pathconf	= cd9660_pathconf,
869 	.vop_advlock	= cd9660_advlock,
870 	.vop_bwrite	= vop_generic_bwrite
871 };
872 
873 /* Special device vnode ops */
874 const struct vops cd9660_specvops = {
875 	.vop_access	= cd9660_access,
876 	.vop_getattr	= cd9660_getattr,
877 	.vop_setattr	= cd9660_setattr,
878 	.vop_inactive	= cd9660_inactive,
879 	.vop_reclaim	= cd9660_reclaim,
880 	.vop_lock	= cd9660_lock,
881 	.vop_unlock	= cd9660_unlock,
882 	.vop_print	= cd9660_print,
883 	.vop_islocked	= cd9660_islocked,
884 
885 	/* XXX: Keep in sync with spec_vops. */
886 	.vop_lookup	= vop_generic_lookup,
887 	.vop_create	= spec_badop,
888 	.vop_mknod	= spec_badop,
889 	.vop_open	= spec_open,
890 	.vop_close	= spec_close,
891 	.vop_read	= spec_read,
892 	.vop_write	= spec_write,
893 	.vop_ioctl	= spec_ioctl,
894 	.vop_poll	= spec_poll,
895 	.vop_kqfilter	= spec_kqfilter,
896 	.vop_revoke	= vop_generic_revoke,
897 	.vop_fsync	= spec_fsync,
898 	.vop_remove	= spec_badop,
899 	.vop_link	= spec_badop,
900 	.vop_rename	= spec_badop,
901 	.vop_mkdir	= spec_badop,
902 	.vop_rmdir	= spec_badop,
903 	.vop_symlink	= spec_badop,
904 	.vop_readdir	= spec_badop,
905 	.vop_readlink	= spec_badop,
906 	.vop_abortop	= spec_badop,
907 	.vop_bmap	= vop_generic_bmap,
908 	.vop_strategy	= spec_strategy,
909 	.vop_pathconf	= spec_pathconf,
910 	.vop_advlock	= spec_advlock,
911 	.vop_bwrite	= vop_generic_bwrite,
912 };
913 
914 #ifdef FIFO
915 const struct vops cd9660_fifovops = {
916 	.vop_access	= cd9660_access,
917 	.vop_getattr	= cd9660_getattr,
918 	.vop_setattr	= cd9660_setattr,
919 	.vop_inactive	= cd9660_inactive,
920 	.vop_reclaim	= cd9660_reclaim,
921 	.vop_lock	= cd9660_lock,
922 	.vop_unlock	= cd9660_unlock,
923 	.vop_print	= cd9660_print,
924 	.vop_islocked	= cd9660_islocked,
925 	.vop_bwrite	= vop_generic_bwrite,
926 
927 	/* XXX: Keep in sync with fifo_vops. */
928 	.vop_lookup	= vop_generic_lookup,
929 	.vop_create	= fifo_badop,
930 	.vop_mknod	= fifo_badop,
931 	.vop_open	= fifo_open,
932 	.vop_close	= fifo_close,
933 	.vop_read	= fifo_read,
934 	.vop_write	= fifo_write,
935 	.vop_ioctl	= fifo_ioctl,
936 	.vop_poll	= fifo_poll,
937 	.vop_kqfilter	= fifo_kqfilter,
938 	.vop_revoke	= vop_generic_revoke,
939 	.vop_fsync	= nullop,
940 	.vop_remove	= fifo_badop,
941 	.vop_link	= fifo_badop,
942 	.vop_rename	= fifo_badop,
943 	.vop_mkdir	= fifo_badop,
944 	.vop_rmdir	= fifo_badop,
945 	.vop_symlink	= fifo_badop,
946 	.vop_readdir	= fifo_badop,
947 	.vop_readlink	= fifo_badop,
948 	.vop_abortop	= fifo_badop,
949 	.vop_bmap	= vop_generic_bmap,
950 	.vop_strategy	= fifo_badop,
951 	.vop_pathconf	= fifo_pathconf,
952 	.vop_advlock	= fifo_advlock,
953 };
954 #endif /* FIFO */
955 
956 void filt_cd9660detach(struct knote *kn);
957 int filt_cd9660read(struct knote *kn, long hint);
958 int filt_cd9660write(struct knote *kn, long hint);
959 int filt_cd9660vnode(struct knote *kn, long hint);
960 
961 const struct filterops cd9660read_filtops = {
962 	.f_flags	= FILTEROP_ISFD,
963 	.f_attach	= NULL,
964 	.f_detach	= filt_cd9660detach,
965 	.f_event	= filt_cd9660read,
966 };
967 
968 const struct filterops cd9660write_filtops = {
969 	.f_flags	= FILTEROP_ISFD,
970 	.f_attach	= NULL,
971 	.f_detach	= filt_cd9660detach,
972 	.f_event	= filt_cd9660write,
973 };
974 
975 const struct filterops cd9660vnode_filtops = {
976 	.f_flags	= FILTEROP_ISFD,
977 	.f_attach	= NULL,
978 	.f_detach	= filt_cd9660detach,
979 	.f_event	= filt_cd9660vnode,
980 };
981 
982 int
983 cd9660_kqfilter(void *v)
984 {
985 	struct vop_kqfilter_args *ap = v;
986 	struct vnode *vp = ap->a_vp;
987 	struct knote *kn = ap->a_kn;
988 
989 	switch (kn->kn_filter) {
990 	case EVFILT_READ:
991 		kn->kn_fop = &cd9660read_filtops;
992 		break;
993 	case EVFILT_WRITE:
994 		kn->kn_fop = &cd9660write_filtops;
995 		break;
996 	case EVFILT_VNODE:
997 		kn->kn_fop = &cd9660vnode_filtops;
998 		break;
999 	default:
1000 		return (EINVAL);
1001 	}
1002 
1003 	kn->kn_hook = (caddr_t)vp;
1004 
1005 	klist_insert(&vp->v_selectinfo.si_note, kn);
1006 
1007 	return (0);
1008 }
1009 
1010 void
1011 filt_cd9660detach(struct knote *kn)
1012 {
1013 	struct vnode *vp = (struct vnode *)kn->kn_hook;
1014 
1015 	klist_remove(&vp->v_selectinfo.si_note, kn);
1016 }
1017 
1018 int
1019 filt_cd9660read(struct knote *kn, long hint)
1020 {
1021 	struct vnode *vp = (struct vnode *)kn->kn_hook;
1022 	struct iso_node *node = VTOI(vp);
1023 
1024 	/*
1025 	 * filesystem is gone, so set the EOF flag and schedule
1026 	 * the knote for deletion.
1027 	 */
1028 	if (hint == NOTE_REVOKE) {
1029 		kn->kn_flags |= (EV_EOF | EV_ONESHOT);
1030 		return (1);
1031 	}
1032 
1033 	kn->kn_data = node->i_size - foffset(kn->kn_fp);
1034 	if (kn->kn_data == 0 && kn->kn_sfflags & NOTE_EOF) {
1035 		kn->kn_fflags |= NOTE_EOF;
1036 		return (1);
1037 	}
1038 
1039 	if (kn->kn_flags & __EV_POLL)
1040 		return (1);
1041 
1042 	return (kn->kn_data != 0);
1043 }
1044 
1045 int
1046 filt_cd9660write(struct knote *kn, long hint)
1047 {
1048 	/*
1049 	 * filesystem is gone, so set the EOF flag and schedule
1050 	 * the knote for deletion.
1051 	 */
1052 	if (hint == NOTE_REVOKE) {
1053 		kn->kn_flags |= (EV_EOF | EV_ONESHOT);
1054 		return (1);
1055 	}
1056 
1057 	kn->kn_data = 0;
1058 	return (1);
1059 }
1060 
1061 int
1062 filt_cd9660vnode(struct knote *kn, long hint)
1063 {
1064 	if (kn->kn_sfflags & hint)
1065 		kn->kn_fflags |= hint;
1066 	if (hint == NOTE_REVOKE) {
1067 		kn->kn_flags |= EV_EOF;
1068 		return (1);
1069 	}
1070 	return (kn->kn_fflags != 0);
1071 }
1072