xref: /openbsd-src/sys/isofs/cd9660/cd9660_vnops.c (revision 5a0ec8146b3a8f74af8f596985d293fb896d1dcb)
1*5a0ec814Smiod /*	$OpenBSD: cd9660_vnops.c,v 1.97 2024/10/18 05:52:32 miod Exp $	*/
2053e05a2Sniklas /*	$NetBSD: cd9660_vnops.c,v 1.42 1997/10/16 23:56:57 christos Exp $	*/
3df930be7Sderaadt 
4df930be7Sderaadt /*-
5df930be7Sderaadt  * Copyright (c) 1994
6df930be7Sderaadt  *	The Regents of the University of California.  All rights reserved.
7df930be7Sderaadt  *
8df930be7Sderaadt  * This code is derived from software contributed to Berkeley
9df930be7Sderaadt  * by Pace Willisson (pace@blitz.com).  The Rock Ridge Extension
10df930be7Sderaadt  * Support code is derived from software contributed to Berkeley
11df930be7Sderaadt  * by Atsushi Murai (amurai@spec.co.jp).
12df930be7Sderaadt  *
13df930be7Sderaadt  * Redistribution and use in source and binary forms, with or without
14df930be7Sderaadt  * modification, are permitted provided that the following conditions
15df930be7Sderaadt  * are met:
16df930be7Sderaadt  * 1. Redistributions of source code must retain the above copyright
17df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer.
18df930be7Sderaadt  * 2. Redistributions in binary form must reproduce the above copyright
19df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer in the
20df930be7Sderaadt  *    documentation and/or other materials provided with the distribution.
2129295d1cSmillert  * 3. Neither the name of the University nor the names of its contributors
22df930be7Sderaadt  *    may be used to endorse or promote products derived from this software
23df930be7Sderaadt  *    without specific prior written permission.
24df930be7Sderaadt  *
25df930be7Sderaadt  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26df930be7Sderaadt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27df930be7Sderaadt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28df930be7Sderaadt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29df930be7Sderaadt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30df930be7Sderaadt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31df930be7Sderaadt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32df930be7Sderaadt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33df930be7Sderaadt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34df930be7Sderaadt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35df930be7Sderaadt  * SUCH DAMAGE.
36df930be7Sderaadt  *
37df930be7Sderaadt  *	@(#)cd9660_vnops.c	8.15 (Berkeley) 12/5/94
38df930be7Sderaadt  */
39df930be7Sderaadt 
40df930be7Sderaadt #include <sys/param.h>
41df930be7Sderaadt #include <sys/systm.h>
42df930be7Sderaadt #include <sys/namei.h>
43df930be7Sderaadt #include <sys/resourcevar.h>
44df930be7Sderaadt #include <sys/kernel.h>
45df930be7Sderaadt #include <sys/file.h>
46df930be7Sderaadt #include <sys/stat.h>
47df930be7Sderaadt #include <sys/buf.h>
48df930be7Sderaadt #include <sys/conf.h>
49df930be7Sderaadt #include <sys/mount.h>
50df930be7Sderaadt #include <sys/vnode.h>
51fde894e5Stedu #include <sys/lock.h>
52df930be7Sderaadt #include <sys/malloc.h>
53dbe27ba0Stedu #include <sys/pool.h>
540c0430f8Sniklas #include <sys/dirent.h>
55e6ab5f15Sangelos #include <sys/ioctl.h>
56e6ab5f15Sangelos #include <sys/ioccom.h>
57544451c3Sderaadt #include <sys/specdev.h>
58782ebdf8Stedu #include <sys/unistd.h>
59df930be7Sderaadt 
60053e05a2Sniklas #include <miscfs/fifofs/fifo.h>
61053e05a2Sniklas 
62df930be7Sderaadt #include <isofs/cd9660/iso.h>
63053e05a2Sniklas #include <isofs/cd9660/cd9660_extern.h>
64df930be7Sderaadt #include <isofs/cd9660/cd9660_node.h>
65df930be7Sderaadt #include <isofs/cd9660/iso_rrip.h>
66df930be7Sderaadt 
67e04616ffStedu int cd9660_kqfilter(void *v);
68e04616ffStedu 
69e04616ffStedu 
709d71829cSniklas /*
719d71829cSniklas  * Structure for reading directories
729d71829cSniklas  */
739d71829cSniklas struct isoreaddir {
749d71829cSniklas 	struct dirent saveent;
759d71829cSniklas 	struct dirent assocent;
769d71829cSniklas 	struct dirent current;
779d71829cSniklas 	off_t saveoff;
789d71829cSniklas 	off_t assocoff;
799d71829cSniklas 	off_t curroff;
809d71829cSniklas 	struct uio *uio;
819d71829cSniklas 	off_t uio_off;
829d71829cSniklas 	int eofflag;
839d71829cSniklas };
849d71829cSniklas 
85c4071fd1Smillert int	iso_uiodir(struct isoreaddir *, struct dirent *, off_t);
86c4071fd1Smillert int	iso_shipdir(struct isoreaddir *);
879d71829cSniklas 
88df930be7Sderaadt /*
8907feb63cScsapuntz  * Setattr call. Only allowed for block and character special devices.
9007feb63cScsapuntz  */
9107feb63cScsapuntz int
92edf63aa4Smatthew cd9660_setattr(void *v)
9307feb63cScsapuntz {
9499bc9d31Sderaadt 	struct vop_setattr_args *ap = v;
9507feb63cScsapuntz 	struct vnode *vp = ap->a_vp;
9607feb63cScsapuntz 	struct vattr *vap = ap->a_vap;
9707feb63cScsapuntz 
9807feb63cScsapuntz 	if (vap->va_flags != VNOVAL || vap->va_uid != (uid_t)VNOVAL ||
994707cbe3Sguenther 	    vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_nsec != VNOVAL ||
1004707cbe3Sguenther 	    vap->va_mtime.tv_nsec != VNOVAL || vap->va_mode != (mode_t)VNOVAL ||
1014707cbe3Sguenther 	    (vap->va_vaflags & VA_UTIMES_CHANGE))
10207feb63cScsapuntz 		return (EROFS);
10307feb63cScsapuntz 	if (vap->va_size != VNOVAL) {
10407feb63cScsapuntz 		switch (vp->v_type) {
10507feb63cScsapuntz 		case VDIR:
10607feb63cScsapuntz 			return (EISDIR);
10707feb63cScsapuntz 		case VLNK:
10807feb63cScsapuntz 		case VREG:
10907feb63cScsapuntz 			return (EROFS);
11007feb63cScsapuntz 		case VCHR:
11107feb63cScsapuntz 		case VBLK:
11207feb63cScsapuntz 		case VSOCK:
11307feb63cScsapuntz 		case VFIFO:
11407feb63cScsapuntz 			return (0);
11507feb63cScsapuntz 		default:
11607feb63cScsapuntz 			return (EINVAL);
11707feb63cScsapuntz 		}
11807feb63cScsapuntz 	}
11907feb63cScsapuntz 
12007feb63cScsapuntz 	return (EINVAL);
12107feb63cScsapuntz }
12207feb63cScsapuntz 
12307feb63cScsapuntz /*
124df930be7Sderaadt  * Open called.
125df930be7Sderaadt  *
126df930be7Sderaadt  * Nothing to do.
127df930be7Sderaadt  */
128df930be7Sderaadt int
129edf63aa4Smatthew cd9660_open(void *v)
130df930be7Sderaadt {
131df930be7Sderaadt 	return (0);
132df930be7Sderaadt }
133df930be7Sderaadt 
134df930be7Sderaadt /*
135df930be7Sderaadt  * Close called
136df930be7Sderaadt  *
137df930be7Sderaadt  * Update the times on the inode on writeable file systems.
138df930be7Sderaadt  */
139df930be7Sderaadt int
140edf63aa4Smatthew cd9660_close(void *v)
141df930be7Sderaadt {
142df930be7Sderaadt 	return (0);
143df930be7Sderaadt }
144df930be7Sderaadt 
145df930be7Sderaadt /*
146df930be7Sderaadt  * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC.
147df930be7Sderaadt  * The mode is shifted to select the owner/group/other fields. The
148df930be7Sderaadt  * super user is granted all permissions.
149df930be7Sderaadt  */
150df930be7Sderaadt int
151edf63aa4Smatthew cd9660_access(void *v)
1529d71829cSniklas {
15399bc9d31Sderaadt 	struct vop_access_args *ap = v;
154df930be7Sderaadt 	struct iso_node *ip = VTOI(ap->a_vp);
155df930be7Sderaadt 
156141c07a8Smillert 	return (vaccess(ap->a_vp->v_type, ip->inode.iso_mode & ALLPERMS,
157141c07a8Smillert 	    ip->inode.iso_uid, ip->inode.iso_gid, ap->a_mode, ap->a_cred));
158df930be7Sderaadt }
159df930be7Sderaadt 
160df930be7Sderaadt int
161edf63aa4Smatthew cd9660_getattr(void *v)
1629d71829cSniklas {
16399bc9d31Sderaadt 	struct vop_getattr_args *ap = v;
164df930be7Sderaadt 	struct vnode *vp = ap->a_vp;
165b2acc587Sjsg 	struct vattr *vap = ap->a_vap;
166b2acc587Sjsg 	struct iso_node *ip = VTOI(vp);
167df930be7Sderaadt 
168df930be7Sderaadt 	vap->va_fsid	= ip->i_dev;
169df930be7Sderaadt 	vap->va_fileid	= ip->i_number;
170df930be7Sderaadt 
171053e05a2Sniklas 	vap->va_mode	= ip->inode.iso_mode & ALLPERMS;
172df930be7Sderaadt 	vap->va_nlink	= ip->inode.iso_links;
173df930be7Sderaadt 	vap->va_uid	= ip->inode.iso_uid;
174df930be7Sderaadt 	vap->va_gid	= ip->inode.iso_gid;
175df930be7Sderaadt 	vap->va_atime	= ip->inode.iso_atime;
176df930be7Sderaadt 	vap->va_mtime	= ip->inode.iso_mtime;
177df930be7Sderaadt 	vap->va_ctime	= ip->inode.iso_ctime;
178df930be7Sderaadt 	vap->va_rdev	= ip->inode.iso_rdev;
179df930be7Sderaadt 
180df930be7Sderaadt 	vap->va_size	= (u_quad_t) ip->i_size;
181053e05a2Sniklas 	if (ip->i_size == 0 && vp->v_type  == VLNK) {
182df930be7Sderaadt 		struct vop_readlink_args rdlnk;
183df930be7Sderaadt 		struct iovec aiov;
184df930be7Sderaadt 		struct uio auio;
185df930be7Sderaadt 		char *cp;
186df930be7Sderaadt 
187808d1e2bSchl 		cp = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
188df930be7Sderaadt 		aiov.iov_base = cp;
189df930be7Sderaadt 		aiov.iov_len = MAXPATHLEN;
190df930be7Sderaadt 		auio.uio_iov = &aiov;
191df930be7Sderaadt 		auio.uio_iovcnt = 1;
192df930be7Sderaadt 		auio.uio_offset = 0;
193df930be7Sderaadt 		auio.uio_rw = UIO_READ;
194df930be7Sderaadt 		auio.uio_segflg = UIO_SYSSPACE;
195df930be7Sderaadt 		auio.uio_procp = ap->a_p;
196df930be7Sderaadt 		auio.uio_resid = MAXPATHLEN;
197df930be7Sderaadt 		rdlnk.a_uio = &auio;
198df930be7Sderaadt 		rdlnk.a_vp = ap->a_vp;
199df930be7Sderaadt 		rdlnk.a_cred = ap->a_cred;
200df930be7Sderaadt 		if (cd9660_readlink(&rdlnk) == 0)
201df930be7Sderaadt 			vap->va_size = MAXPATHLEN - auio.uio_resid;
2020e5ae731Stedu 		free(cp, M_TEMP, 0);
203df930be7Sderaadt 	}
204df930be7Sderaadt 	vap->va_flags	= 0;
205df930be7Sderaadt 	vap->va_gen = 1;
206df930be7Sderaadt 	vap->va_blocksize = ip->i_mnt->logical_block_size;
207df930be7Sderaadt 	vap->va_bytes	= (u_quad_t) ip->i_size;
208df930be7Sderaadt 	vap->va_type	= vp->v_type;
209df930be7Sderaadt 	return (0);
210df930be7Sderaadt }
211df930be7Sderaadt 
212df930be7Sderaadt /*
213df930be7Sderaadt  * Vnode op for reading.
214df930be7Sderaadt  */
215df930be7Sderaadt int
216edf63aa4Smatthew cd9660_read(void *v)
2179d71829cSniklas {
21899bc9d31Sderaadt 	struct vop_read_args *ap = v;
219df930be7Sderaadt 	struct vnode *vp = ap->a_vp;
220b2acc587Sjsg 	struct uio *uio = ap->a_uio;
221b2acc587Sjsg 	struct iso_node *ip = VTOI(vp);
222b2acc587Sjsg 	struct iso_mnt *imp;
2231414b0faSart 	struct buf *bp;
2241abdbfdeSderaadt 	daddr_t lbn, rablock;
2251414b0faSart 	off_t diff;
2268de3a2c5Sart 	int error = 0;
227b52c98b0Sstefan 	long size, on;
228b52c98b0Sstefan 	size_t n;
229df930be7Sderaadt 
230df930be7Sderaadt 	if (uio->uio_resid == 0)
231df930be7Sderaadt 		return (0);
232df930be7Sderaadt 	if (uio->uio_offset < 0)
233df930be7Sderaadt 		return (EINVAL);
234dd910b73Sart 	ip->i_flag |= IN_ACCESS;
2351414b0faSart 	imp = ip->i_mnt;
2361414b0faSart 	do {
2378de3a2c5Sart 		struct cluster_info *ci = &ip->i_ci;
2388de3a2c5Sart 
2391414b0faSart 		lbn = lblkno(imp, uio->uio_offset);
2401414b0faSart 		on = blkoff(imp, uio->uio_offset);
241b52c98b0Sstefan 		n = ulmin(imp->logical_block_size - on, uio->uio_resid);
2421414b0faSart 		diff = (off_t)ip->i_size - uio->uio_offset;
2431414b0faSart 		if (diff <= 0)
2441414b0faSart 			return (0);
2451414b0faSart 		if (diff < n)
2461414b0faSart 			n = diff;
2471414b0faSart 		size = blksize(imp, ip, lbn);
2481414b0faSart 		rablock = lbn + 1;
2498de3a2c5Sart #define MAX_RA 32
2508de3a2c5Sart 		if (ci->ci_lastr + 1 == lbn) {
2518f6e076eSmickey 			struct ra {
2521abdbfdeSderaadt 				daddr_t blks[MAX_RA];
2538f6e076eSmickey 				int sizes[MAX_RA];
2548f6e076eSmickey 			} *ra;
2558de3a2c5Sart 			int i;
2568de3a2c5Sart 
257808d1e2bSchl 			ra = malloc(sizeof *ra, M_TEMP, M_WAITOK);
2588de3a2c5Sart 			for (i = 0; i < MAX_RA &&
2598de3a2c5Sart 			    lblktosize(imp, (rablock + i)) < ip->i_size;
2608de3a2c5Sart 			    i++) {
2618f6e076eSmickey 				ra->blks[i] = rablock + i;
2628f6e076eSmickey 				ra->sizes[i] = blksize(imp, ip, rablock + i);
2638de3a2c5Sart 			}
2648f6e076eSmickey 			error = breadn(vp, lbn, size, ra->blks,
26593f62a9eStedu 			    ra->sizes, i, &bp);
2660e5ae731Stedu 			free(ra, M_TEMP, 0);
2671414b0faSart 		} else
26893f62a9eStedu 			error = bread(vp, lbn, size, &bp);
2698de3a2c5Sart 		ci->ci_lastr = lbn;
270b52c98b0Sstefan 		n = ulmin(n, size - bp->b_resid);
2711414b0faSart 		if (error) {
2721414b0faSart 			brelse(bp);
273dd910b73Sart 			return (error);
2745af79db2Sart 		}
2755af79db2Sart 
276b52c98b0Sstefan 		error = uiomove(bp->b_data + on, n, uio);
2771414b0faSart 
2781414b0faSart 		brelse(bp);
2791414b0faSart 	} while (error == 0 && uio->uio_resid > 0 && n != 0);
2801414b0faSart 	return (error);
281df930be7Sderaadt }
282df930be7Sderaadt 
283df930be7Sderaadt int
284edf63aa4Smatthew cd9660_ioctl(void *v)
285df930be7Sderaadt {
286df930be7Sderaadt 	return (ENOTTY);
287df930be7Sderaadt }
288df930be7Sderaadt 
289df930be7Sderaadt /*
290df930be7Sderaadt  * Mmap a file
291df930be7Sderaadt  *
292df930be7Sderaadt  * NB Currently unsupported.
293df930be7Sderaadt  */
294df930be7Sderaadt int
295edf63aa4Smatthew cd9660_mmap(void *v)
296df930be7Sderaadt {
297df930be7Sderaadt 
298df930be7Sderaadt 	return (EINVAL);
299df930be7Sderaadt }
300df930be7Sderaadt 
301df930be7Sderaadt /*
302df930be7Sderaadt  * Seek on a file
303df930be7Sderaadt  *
304df930be7Sderaadt  * Nothing to do, so just return.
305df930be7Sderaadt  */
306df930be7Sderaadt int
307edf63aa4Smatthew cd9660_seek(void *v)
308df930be7Sderaadt {
309df930be7Sderaadt 	return (0);
310df930be7Sderaadt }
311df930be7Sderaadt 
312df930be7Sderaadt int
3131bf87d88Sjsg iso_uiodir(struct isoreaddir *idp, struct dirent *dp, off_t off)
314df930be7Sderaadt {
315df930be7Sderaadt 	int error;
316df930be7Sderaadt 
317df930be7Sderaadt 	dp->d_name[dp->d_namlen] = 0;
3180c0430f8Sniklas 	dp->d_reclen = DIRENT_SIZE(dp);
319df930be7Sderaadt 
32046f7109aSclaudio 	if (memchr(dp->d_name, '/', dp->d_namlen) != NULL) {
32146f7109aSclaudio 		/* illegal file name */
32246f7109aSclaudio 		return (EINVAL);
32346f7109aSclaudio 	}
32446f7109aSclaudio 
325df930be7Sderaadt 	if (idp->uio->uio_resid < dp->d_reclen) {
326df930be7Sderaadt 		idp->eofflag = 0;
327df930be7Sderaadt 		return (-1);
328df930be7Sderaadt 	}
329df930be7Sderaadt 
33091a535ffSguenther 	dp->d_off = off;
331b52c98b0Sstefan 	if ((error = uiomove(dp, dp->d_reclen, idp->uio)) != 0)
332df930be7Sderaadt 		return (error);
333df930be7Sderaadt 	idp->uio_off = off;
334df930be7Sderaadt 	return (0);
335df930be7Sderaadt }
336df930be7Sderaadt 
337df930be7Sderaadt int
3381bf87d88Sjsg iso_shipdir(struct isoreaddir *idp)
339df930be7Sderaadt {
340df930be7Sderaadt 	struct dirent *dp;
341df930be7Sderaadt 	int cl, sl, assoc;
342df930be7Sderaadt 	int error;
343df930be7Sderaadt 	char *cname, *sname;
344df930be7Sderaadt 
345df930be7Sderaadt 	cl = idp->current.d_namlen;
346df930be7Sderaadt 	cname = idp->current.d_name;
3479d71829cSniklas 
348d724e01aSderaadt 	if ((assoc = cl > 1 && *cname == ASSOCCHAR)) {
349df930be7Sderaadt 		cl--;
350df930be7Sderaadt 		cname++;
351df930be7Sderaadt 	}
352df930be7Sderaadt 
353df930be7Sderaadt 	dp = &idp->saveent;
354df930be7Sderaadt 	sname = dp->d_name;
355df930be7Sderaadt 	if (!(sl = dp->d_namlen)) {
356df930be7Sderaadt 		dp = &idp->assocent;
357df930be7Sderaadt 		sname = dp->d_name + 1;
358df930be7Sderaadt 		sl = dp->d_namlen - 1;
359df930be7Sderaadt 	}
360df930be7Sderaadt 	if (sl > 0) {
361df930be7Sderaadt 		if (sl != cl
362df930be7Sderaadt 		    || bcmp(sname,cname,sl)) {
363df930be7Sderaadt 			if (idp->assocent.d_namlen) {
3649d71829cSniklas 				error = iso_uiodir(idp, &idp->assocent,
3659d71829cSniklas 						   idp->assocoff);
3669d71829cSniklas 				if (error)
367df930be7Sderaadt 					return (error);
368df930be7Sderaadt 				idp->assocent.d_namlen = 0;
369df930be7Sderaadt 			}
370df930be7Sderaadt 			if (idp->saveent.d_namlen) {
3719d71829cSniklas 				error = iso_uiodir(idp, &idp->saveent,
3729d71829cSniklas 						   idp->saveoff);
3739d71829cSniklas 				if (error)
374df930be7Sderaadt 					return (error);
375df930be7Sderaadt 				idp->saveent.d_namlen = 0;
376df930be7Sderaadt 			}
377df930be7Sderaadt 		}
378df930be7Sderaadt 	}
3790c0430f8Sniklas 	idp->current.d_reclen = DIRENT_SIZE(&idp->current);
380df930be7Sderaadt 	if (assoc) {
381df930be7Sderaadt 		idp->assocoff = idp->curroff;
382df930be7Sderaadt 		bcopy(&idp->current,&idp->assocent,idp->current.d_reclen);
383df930be7Sderaadt 	} else {
384df930be7Sderaadt 		idp->saveoff = idp->curroff;
385df930be7Sderaadt 		bcopy(&idp->current,&idp->saveent,idp->current.d_reclen);
386df930be7Sderaadt 	}
387df930be7Sderaadt 	return (0);
388df930be7Sderaadt }
389df930be7Sderaadt 
390df930be7Sderaadt /*
391df930be7Sderaadt  * Vnode op for readdir
392df930be7Sderaadt  */
393df930be7Sderaadt int
394edf63aa4Smatthew cd9660_readdir(void *v)
3959d71829cSniklas {
39699bc9d31Sderaadt 	struct vop_readdir_args *ap = v;
397b2acc587Sjsg 	struct uio *uio = ap->a_uio;
398df930be7Sderaadt 	struct isoreaddir *idp;
399df930be7Sderaadt 	struct vnode *vdp = ap->a_vp;
400df930be7Sderaadt 	struct iso_node *dp;
401df930be7Sderaadt 	struct iso_mnt *imp;
402df930be7Sderaadt 	struct buf *bp = NULL;
403df930be7Sderaadt 	struct iso_directory_record *ep;
404df930be7Sderaadt 	int entryoffsetinblock;
405df930be7Sderaadt 	doff_t endsearch;
406df930be7Sderaadt 	u_long bmask;
407df930be7Sderaadt 	int error = 0;
408df930be7Sderaadt 	int reclen;
409df930be7Sderaadt 	u_short namelen;
4100cad8b22Sguenther 	cdino_t ino;
411df930be7Sderaadt 
412df930be7Sderaadt 	dp = VTOI(vdp);
413df930be7Sderaadt 	imp = dp->i_mnt;
414df930be7Sderaadt 	bmask = imp->im_bmask;
415df930be7Sderaadt 
416808d1e2bSchl 	idp = malloc(sizeof(*idp), M_TEMP, M_WAITOK);
417ebee68f3Sguenther 
418ebee68f3Sguenther 	/*
419ebee68f3Sguenther 	 * These are passed to copyout(), so make sure there's no garbage
420ebee68f3Sguenther 	 * being leaked in padding or after short names.
421ebee68f3Sguenther 	 */
422ebee68f3Sguenther 	memset(&idp->saveent, 0, sizeof(idp->saveent));
423ebee68f3Sguenther 	memset(&idp->assocent, 0, sizeof(idp->assocent));
424ebee68f3Sguenther 	memset(&idp->current, 0, sizeof(idp->current));
425ebee68f3Sguenther 
426df930be7Sderaadt 	/*
427df930be7Sderaadt 	 * XXX
428df930be7Sderaadt 	 * Is it worth trying to figure out the type?
429df930be7Sderaadt 	 */
430df930be7Sderaadt 	idp->saveent.d_type = idp->assocent.d_type = idp->current.d_type =
431df930be7Sderaadt 	    DT_UNKNOWN;
432df930be7Sderaadt 	idp->uio = uio;
433df930be7Sderaadt 	idp->eofflag = 1;
434df930be7Sderaadt 	idp->curroff = uio->uio_offset;
435c8609118Skrw 	idp->uio_off = uio->uio_offset;
436df930be7Sderaadt 
437df930be7Sderaadt 	if ((entryoffsetinblock = idp->curroff & bmask) &&
438574066a2Scsapuntz 	    (error = cd9660_bufatoff(dp, (off_t)idp->curroff, NULL, &bp))) {
4390e5ae731Stedu 		free(idp, M_TEMP, 0);
440df930be7Sderaadt 		return (error);
441df930be7Sderaadt 	}
442df930be7Sderaadt 	endsearch = dp->i_size;
443df930be7Sderaadt 
444df930be7Sderaadt 	while (idp->curroff < endsearch) {
445df930be7Sderaadt 		/*
446df930be7Sderaadt 		 * If offset is on a block boundary,
447df930be7Sderaadt 		 * read the next directory block.
448df930be7Sderaadt 		 * Release previous if it exists.
449df930be7Sderaadt 		 */
450df930be7Sderaadt 		if ((idp->curroff & bmask) == 0) {
451df930be7Sderaadt 			if (bp != NULL)
452df930be7Sderaadt 				brelse(bp);
453574066a2Scsapuntz 			error = cd9660_bufatoff(dp, (off_t)idp->curroff,
4549d71829cSniklas 					     NULL, &bp);
4559d71829cSniklas 			if (error)
456df930be7Sderaadt 				break;
457df930be7Sderaadt 			entryoffsetinblock = 0;
458df930be7Sderaadt 		}
459df930be7Sderaadt 		/*
460df930be7Sderaadt 		 * Get pointer to next entry.
461df930be7Sderaadt 		 */
462df930be7Sderaadt 		ep = (struct iso_directory_record *)
463df930be7Sderaadt 			((char *)bp->b_data + entryoffsetinblock);
464df930be7Sderaadt 
465df930be7Sderaadt 		reclen = isonum_711(ep->length);
466df930be7Sderaadt 		if (reclen == 0) {
467df930be7Sderaadt 			/* skip to next block, if any */
468df930be7Sderaadt 			idp->curroff =
469df930be7Sderaadt 			    (idp->curroff & ~bmask) + imp->logical_block_size;
470df930be7Sderaadt 			continue;
471df930be7Sderaadt 		}
472df930be7Sderaadt 
473df930be7Sderaadt 		if (reclen < ISO_DIRECTORY_RECORD_SIZE) {
474df930be7Sderaadt 			error = EINVAL;
475df930be7Sderaadt 			/* illegal entry, stop */
476df930be7Sderaadt 			break;
477df930be7Sderaadt 		}
478df930be7Sderaadt 
479df930be7Sderaadt 		if (entryoffsetinblock + reclen > imp->logical_block_size) {
480df930be7Sderaadt 			error = EINVAL;
481df930be7Sderaadt 			/* illegal directory, so stop looking */
482df930be7Sderaadt 			break;
483df930be7Sderaadt 		}
484df930be7Sderaadt 
485df930be7Sderaadt 		idp->current.d_namlen = isonum_711(ep->name_len);
486df930be7Sderaadt 
487df930be7Sderaadt 		if (reclen < ISO_DIRECTORY_RECORD_SIZE + idp->current.d_namlen) {
488df930be7Sderaadt 			error = EINVAL;
489df930be7Sderaadt 			/* illegal entry, stop */
490df930be7Sderaadt 			break;
491df930be7Sderaadt 		}
492df930be7Sderaadt 
493df930be7Sderaadt 		if (isonum_711(ep->flags)&2)
4940cad8b22Sguenther 			ino = isodirino(ep, imp);
495df930be7Sderaadt 		else
4960cad8b22Sguenther 			ino = dbtob(bp->b_blkno) + entryoffsetinblock;
497df930be7Sderaadt 
498df930be7Sderaadt 		idp->curroff += reclen;
499df930be7Sderaadt 
500df930be7Sderaadt 		switch (imp->iso_ftype) {
501df930be7Sderaadt 		case ISO_FTYPE_RRIP:
502df930be7Sderaadt 			cd9660_rrip_getname(ep,idp->current.d_name, &namelen,
5030cad8b22Sguenther 					   &ino, imp);
5040cad8b22Sguenther 			idp->current.d_fileno = ino;
505df930be7Sderaadt 			idp->current.d_namlen = (u_char)namelen;
506df930be7Sderaadt 			if (idp->current.d_namlen)
507df930be7Sderaadt 				error = iso_uiodir(idp,&idp->current,idp->curroff);
508df930be7Sderaadt 			break;
509df930be7Sderaadt 		default:	/* ISO_FTYPE_DEFAULT || ISO_FTYPE_9660 */
5100cad8b22Sguenther 			idp->current.d_fileno = ino;
511e615ec19Sderaadt 			strlcpy(idp->current.d_name,"..",
512e615ec19Sderaadt 			    sizeof idp->current.d_name);
51349f343b7Sd 			if (idp->current.d_namlen == 1 && ep->name[0] == 0) {
514df930be7Sderaadt 				idp->current.d_namlen = 1;
515df930be7Sderaadt 				error = iso_uiodir(idp,&idp->current,idp->curroff);
51649f343b7Sd 			} else if (idp->current.d_namlen == 1 &&
51749f343b7Sd 			    ep->name[0] == 1) {
518df930be7Sderaadt 				idp->current.d_namlen = 2;
519df930be7Sderaadt 				error = iso_uiodir(idp,&idp->current,idp->curroff);
52049f343b7Sd 			} else {
521df930be7Sderaadt 				isofntrans(ep->name,idp->current.d_namlen,
522df930be7Sderaadt 					   idp->current.d_name, &namelen,
523df930be7Sderaadt 					   imp->iso_ftype == ISO_FTYPE_9660,
52449f343b7Sd 					   isonum_711(ep->flags) & 4,
52549f343b7Sd 					   imp->joliet_level);
526df930be7Sderaadt 				idp->current.d_namlen = (u_char)namelen;
527df930be7Sderaadt 				if (imp->iso_ftype == ISO_FTYPE_DEFAULT)
528df930be7Sderaadt 					error = iso_shipdir(idp);
529df930be7Sderaadt 				else
530df930be7Sderaadt 					error = iso_uiodir(idp,&idp->current,idp->curroff);
531df930be7Sderaadt 			}
532df930be7Sderaadt 		}
533df930be7Sderaadt 		if (error)
534df930be7Sderaadt 			break;
535df930be7Sderaadt 
536df930be7Sderaadt 		entryoffsetinblock += reclen;
537df930be7Sderaadt 	}
538df930be7Sderaadt 
539df930be7Sderaadt 	if (!error && imp->iso_ftype == ISO_FTYPE_DEFAULT) {
540df930be7Sderaadt 		idp->current.d_namlen = 0;
541df930be7Sderaadt 		error = iso_shipdir(idp);
542df930be7Sderaadt 	}
543df930be7Sderaadt 	if (error < 0)
544df930be7Sderaadt 		error = 0;
545df930be7Sderaadt 
546df930be7Sderaadt 	if (bp)
547df930be7Sderaadt 		brelse (bp);
548df930be7Sderaadt 
549df930be7Sderaadt 	uio->uio_offset = idp->uio_off;
550df930be7Sderaadt 	*ap->a_eofflag = idp->eofflag;
551df930be7Sderaadt 
5520e5ae731Stedu 	free(idp, M_TEMP, 0);
553df930be7Sderaadt 
554df930be7Sderaadt 	return (error);
555df930be7Sderaadt }
556df930be7Sderaadt 
557df930be7Sderaadt /*
558df930be7Sderaadt  * Return target name of a symbolic link
559df930be7Sderaadt  * Shouldn't we get the parent vnode and read the data from there?
560df930be7Sderaadt  * This could eventually result in deadlocks in cd9660_lookup.
561df930be7Sderaadt  * But otherwise the block read here is in the block buffer two times.
562df930be7Sderaadt  */
563df930be7Sderaadt typedef struct iso_directory_record ISODIR;
564df930be7Sderaadt typedef struct iso_node             ISONODE;
565df930be7Sderaadt typedef struct iso_mnt              ISOMNT;
566df930be7Sderaadt int
567edf63aa4Smatthew cd9660_readlink(void *v)
5689d71829cSniklas {
56999bc9d31Sderaadt 	struct vop_readlink_args *ap = v;
570df930be7Sderaadt 	ISONODE	*ip;
571df930be7Sderaadt 	ISODIR	*dirp;
572df930be7Sderaadt 	ISOMNT	*imp;
573df930be7Sderaadt 	struct	buf *bp;
574df930be7Sderaadt 	struct	uio *uio;
575df930be7Sderaadt 	u_short	symlen;
576df930be7Sderaadt 	int	error;
577df930be7Sderaadt 	char	*symname;
578df930be7Sderaadt 
579df930be7Sderaadt 	ip  = VTOI(ap->a_vp);
580df930be7Sderaadt 	imp = ip->i_mnt;
581df930be7Sderaadt 	uio = ap->a_uio;
582df930be7Sderaadt 
583df930be7Sderaadt 	if (imp->iso_ftype != ISO_FTYPE_RRIP)
584df930be7Sderaadt 		return (EINVAL);
585df930be7Sderaadt 
586df930be7Sderaadt 	/*
587df930be7Sderaadt 	 * Get parents directory record block that this inode included.
588df930be7Sderaadt 	 */
589df930be7Sderaadt 	error = bread(imp->im_devvp,
590df930be7Sderaadt 		      (ip->i_number >> imp->im_bshift) <<
591df930be7Sderaadt 		      (imp->im_bshift - DEV_BSHIFT),
59293f62a9eStedu 		      imp->logical_block_size, &bp);
593df930be7Sderaadt 	if (error) {
594df930be7Sderaadt 		brelse(bp);
595df930be7Sderaadt 		return (EINVAL);
596df930be7Sderaadt 	}
597df930be7Sderaadt 
598df930be7Sderaadt 	/*
599df930be7Sderaadt 	 * Setup the directory pointer for this inode
600df930be7Sderaadt 	 */
601df930be7Sderaadt 	dirp = (ISODIR *)(bp->b_data + (ip->i_number & imp->im_bmask));
602df930be7Sderaadt 
603df930be7Sderaadt 	/*
604df930be7Sderaadt 	 * Just make sure, we have a right one....
605df930be7Sderaadt 	 *   1: Check not cross boundary on block
606df930be7Sderaadt 	 */
607df930be7Sderaadt 	if ((ip->i_number & imp->im_bmask) + isonum_711(dirp->length)
608df930be7Sderaadt 	    > imp->logical_block_size) {
609df930be7Sderaadt 		brelse(bp);
610df930be7Sderaadt 		return (EINVAL);
611df930be7Sderaadt 	}
612df930be7Sderaadt 
613df930be7Sderaadt 	/*
614df930be7Sderaadt 	 * Now get a buffer
615df930be7Sderaadt 	 * Abuse a namei buffer for now.
616df930be7Sderaadt 	 */
6178c4185c5Stdeval 	if (uio->uio_segflg == UIO_SYSSPACE &&
6188c4185c5Stdeval 	    uio->uio_iov->iov_len >= MAXPATHLEN)
619df930be7Sderaadt 		symname = uio->uio_iov->iov_base;
620df930be7Sderaadt 	else
621dbe27ba0Stedu 		symname = pool_get(&namei_pool, PR_WAITOK);
622df930be7Sderaadt 
623df930be7Sderaadt 	/*
624df930be7Sderaadt 	 * Ok, we just gathering a symbolic name in SL record.
625df930be7Sderaadt 	 */
626df930be7Sderaadt 	if (cd9660_rrip_getsymname(dirp, symname, &symlen, imp) == 0) {
6278c4185c5Stdeval 		if (uio->uio_segflg != UIO_SYSSPACE ||
628d293fc99Stdeval 		    uio->uio_iov->iov_len < MAXPATHLEN)
629dbe27ba0Stedu 			pool_put(&namei_pool, symname);
630df930be7Sderaadt 		brelse(bp);
631df930be7Sderaadt 		return (EINVAL);
632df930be7Sderaadt 	}
633df930be7Sderaadt 	/*
634df930be7Sderaadt 	 * Don't forget before you leave from home ;-)
635df930be7Sderaadt 	 */
636df930be7Sderaadt 	brelse(bp);
637df930be7Sderaadt 
638df930be7Sderaadt 	/*
639df930be7Sderaadt 	 * return with the symbolic name to caller's.
640df930be7Sderaadt 	 */
6418c4185c5Stdeval 	if (uio->uio_segflg != UIO_SYSSPACE ||
6428c4185c5Stdeval 	    uio->uio_iov->iov_len < MAXPATHLEN) {
643b52c98b0Sstefan 		error = uiomove(symname, symlen, uio);
644dbe27ba0Stedu 		pool_put(&namei_pool, symname);
645df930be7Sderaadt 		return (error);
646df930be7Sderaadt 	}
647df930be7Sderaadt 	uio->uio_resid -= symlen;
648ab8fb65aSgrange 	uio->uio_iov->iov_base = (char *)uio->uio_iov->iov_base + symlen;
649df930be7Sderaadt 	uio->uio_iov->iov_len -= symlen;
650df930be7Sderaadt 	return (0);
651df930be7Sderaadt }
652df930be7Sderaadt 
6539d71829cSniklas int
654edf63aa4Smatthew cd9660_link(void *v)
6559d71829cSniklas {
65699bc9d31Sderaadt 	struct vop_link_args *ap = v;
6579d71829cSniklas 
6589d71829cSniklas 	VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
6599d71829cSniklas 	vput(ap->a_dvp);
6609d71829cSniklas 	return (EROFS);
6619d71829cSniklas }
6629d71829cSniklas 
6639d71829cSniklas int
664edf63aa4Smatthew cd9660_symlink(void *v)
6659d71829cSniklas {
66699bc9d31Sderaadt 	struct vop_symlink_args *ap = v;
6679d71829cSniklas 
6689d71829cSniklas 	VOP_ABORTOP(ap->a_dvp, ap->a_cnp);
6699d71829cSniklas 	vput(ap->a_dvp);
6709d71829cSniklas 	return (EROFS);
6719d71829cSniklas }
6729d71829cSniklas 
673df930be7Sderaadt /*
674df930be7Sderaadt  * Lock an inode.
675df930be7Sderaadt  */
676df930be7Sderaadt int
677edf63aa4Smatthew cd9660_lock(void *v)
6789d71829cSniklas {
67999bc9d31Sderaadt 	struct vop_lock_args *ap = v;
68007feb63cScsapuntz 	struct vnode *vp = ap->a_vp;
681df930be7Sderaadt 
68226b8ec94Snatano 	return rrw_enter(&VTOI(vp)->i_lock, ap->a_flags & LK_RWFLAGS);
683df930be7Sderaadt }
684df930be7Sderaadt 
685df930be7Sderaadt /*
686df930be7Sderaadt  * Unlock an inode.
687df930be7Sderaadt  */
688df930be7Sderaadt int
689edf63aa4Smatthew cd9660_unlock(void *v)
6909d71829cSniklas {
69199bc9d31Sderaadt 	struct vop_unlock_args *ap = v;
69207feb63cScsapuntz 	struct vnode *vp = ap->a_vp;
693df930be7Sderaadt 
69426b8ec94Snatano 	rrw_exit(&VTOI(vp)->i_lock);
69526b8ec94Snatano 	return 0;
696df930be7Sderaadt }
697df930be7Sderaadt 
698df930be7Sderaadt /*
699df930be7Sderaadt  * Calculate the logical to physical mapping if not done already,
700df930be7Sderaadt  * then call the device strategy routine.
701df930be7Sderaadt  */
702df930be7Sderaadt int
703edf63aa4Smatthew cd9660_strategy(void *v)
7049d71829cSniklas {
70599bc9d31Sderaadt 	struct vop_strategy_args *ap = v;
7068235abd6Sart 	struct buf *bp = ap->a_bp;
7078235abd6Sart 	struct vnode *vp = bp->b_vp;
7088235abd6Sart 	struct iso_node *ip;
709df930be7Sderaadt 	int error;
7108235abd6Sart 	int s;
711df930be7Sderaadt 
712df930be7Sderaadt 	ip = VTOI(vp);
713df930be7Sderaadt 	if (vp->v_type == VBLK || vp->v_type == VCHR)
714df930be7Sderaadt 		panic("cd9660_strategy: spec");
715df930be7Sderaadt 	if (bp->b_blkno == bp->b_lblkno) {
7169d71829cSniklas 		error = VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL);
7179d71829cSniklas 		if (error) {
718df930be7Sderaadt 			bp->b_error = error;
719df930be7Sderaadt 			bp->b_flags |= B_ERROR;
7208235abd6Sart 			s = splbio();
721df930be7Sderaadt 			biodone(bp);
7228235abd6Sart 			splx(s);
723df930be7Sderaadt 			return (error);
724df930be7Sderaadt 		}
725df930be7Sderaadt 		if ((long)bp->b_blkno == -1)
726df930be7Sderaadt 			clrbuf(bp);
727df930be7Sderaadt 	}
728df930be7Sderaadt 	if ((long)bp->b_blkno == -1) {
7298235abd6Sart 		s = splbio();
730df930be7Sderaadt 		biodone(bp);
7318235abd6Sart 		splx(s);
732df930be7Sderaadt 		return (0);
733df930be7Sderaadt 	}
734df930be7Sderaadt 	vp = ip->i_devvp;
735df930be7Sderaadt 	bp->b_dev = vp->v_rdev;
736f1993be3Svisa 	VOP_STRATEGY(vp, bp);
737df930be7Sderaadt 	return (0);
738df930be7Sderaadt }
739df930be7Sderaadt 
740df930be7Sderaadt /*
741df930be7Sderaadt  * Print out the contents of an inode.
742df930be7Sderaadt  */
743df930be7Sderaadt int
744edf63aa4Smatthew cd9660_print(void *v)
745df930be7Sderaadt {
746*5a0ec814Smiod #if defined(DEBUG) || defined(DIAGNOSTIC) || defined(VFSLCKDEBUG)
747df930be7Sderaadt 	printf("tag VT_ISOFS, isofs vnode\n");
748*5a0ec814Smiod #endif
749df930be7Sderaadt 	return (0);
750df930be7Sderaadt }
751df930be7Sderaadt 
752df930be7Sderaadt /*
753df930be7Sderaadt  * Check for a locked inode.
754df930be7Sderaadt  */
755df930be7Sderaadt int
756edf63aa4Smatthew cd9660_islocked(void *v)
7579d71829cSniklas {
75899bc9d31Sderaadt 	struct vop_islocked_args *ap = v;
759df930be7Sderaadt 
76026b8ec94Snatano 	return rrw_status(&VTOI(ap->a_vp)->i_lock);
761df930be7Sderaadt }
762df930be7Sderaadt 
763df930be7Sderaadt /*
764df930be7Sderaadt  * Return POSIX pathconf information applicable to cd9660 filesystems.
765df930be7Sderaadt  */
766df930be7Sderaadt int
767edf63aa4Smatthew cd9660_pathconf(void *v)
7689d71829cSniklas {
76999bc9d31Sderaadt 	struct vop_pathconf_args *ap = v;
77017497195Sbrad 	int error = 0;
77117497195Sbrad 
772df930be7Sderaadt 	switch (ap->a_name) {
773df930be7Sderaadt 	case _PC_LINK_MAX:
774df930be7Sderaadt 		*ap->a_retval = 1;
77517497195Sbrad 		break;
776df930be7Sderaadt 	case _PC_NAME_MAX:
777df930be7Sderaadt 		if (VTOI(ap->a_vp)->i_mnt->iso_ftype == ISO_FTYPE_RRIP)
778df930be7Sderaadt 			*ap->a_retval = NAME_MAX;
779df930be7Sderaadt 		else
780df930be7Sderaadt 			*ap->a_retval = 37;
78117497195Sbrad 		break;
782df930be7Sderaadt 	case _PC_CHOWN_RESTRICTED:
783df930be7Sderaadt 		*ap->a_retval = 1;
78417497195Sbrad 		break;
785df930be7Sderaadt 	case _PC_NO_TRUNC:
786df930be7Sderaadt 		*ap->a_retval = 1;
78717497195Sbrad 		break;
788d4648cd6Sguenther 	case _PC_TIMESTAMP_RESOLUTION:
789d4648cd6Sguenther 		*ap->a_retval = 1000000000;	/* one billion nanoseconds */
790d4648cd6Sguenther 		break;
791df930be7Sderaadt 	default:
79217497195Sbrad 		error = EINVAL;
79317497195Sbrad 		break;
794df930be7Sderaadt 	}
79517497195Sbrad 
79617497195Sbrad 	return (error);
797df930be7Sderaadt }
798df930be7Sderaadt 
799df930be7Sderaadt /*
800df930be7Sderaadt  * Global vfs data structures for isofs
801df930be7Sderaadt  */
802df930be7Sderaadt 
803dc81e71aSthib /* Global vfs data structures for cd9660. */
8042d6b9e38Sclaudio const struct vops cd9660_vops = {
805dc81e71aSthib 	.vop_lookup	= cd9660_lookup,
80641019245Ssemarie 	.vop_create	= eopnotsupp,
80741019245Ssemarie 	.vop_mknod	= eopnotsupp,
808dc81e71aSthib 	.vop_open	= cd9660_open,
809dc81e71aSthib 	.vop_close	= cd9660_close,
810dc81e71aSthib 	.vop_access	= cd9660_access,
811dc81e71aSthib 	.vop_getattr	= cd9660_getattr,
812dc81e71aSthib 	.vop_setattr	= cd9660_setattr,
813dc81e71aSthib 	.vop_read	= cd9660_read,
81441019245Ssemarie 	.vop_write	= eopnotsupp,
815dc81e71aSthib 	.vop_ioctl	= cd9660_ioctl,
816e04616ffStedu 	.vop_kqfilter	= cd9660_kqfilter,
81741019245Ssemarie 	.vop_revoke	= vop_generic_revoke,
81841019245Ssemarie 	.vop_fsync	= nullop,
81941019245Ssemarie 	.vop_remove	= eopnotsupp,
820dc81e71aSthib 	.vop_link	= cd9660_link,
82141019245Ssemarie 	.vop_rename	= eopnotsupp,
82241019245Ssemarie 	.vop_mkdir	= eopnotsupp,
82341019245Ssemarie 	.vop_rmdir	= eopnotsupp,
824dc81e71aSthib 	.vop_symlink	= cd9660_symlink,
825dc81e71aSthib 	.vop_readdir	= cd9660_readdir,
826dc81e71aSthib 	.vop_readlink	= cd9660_readlink,
827dc81e71aSthib 	.vop_abortop	= vop_generic_abortop,
828dc81e71aSthib 	.vop_inactive	= cd9660_inactive,
829dc81e71aSthib 	.vop_reclaim	= cd9660_reclaim,
830dc81e71aSthib 	.vop_lock	= cd9660_lock,
831dc81e71aSthib 	.vop_unlock	= cd9660_unlock,
832dc81e71aSthib 	.vop_bmap	= cd9660_bmap,
833dc81e71aSthib 	.vop_strategy	= cd9660_strategy,
834dc81e71aSthib 	.vop_print	= cd9660_print,
835dc81e71aSthib 	.vop_islocked	= cd9660_islocked,
836dc81e71aSthib 	.vop_pathconf	= cd9660_pathconf,
83741019245Ssemarie 	.vop_advlock	= eopnotsupp,
83841019245Ssemarie 	.vop_bwrite	= vop_generic_bwrite,
839df930be7Sderaadt };
840df930be7Sderaadt 
841dc81e71aSthib /* Special device vnode ops */
8422d6b9e38Sclaudio const struct vops cd9660_specvops = {
843dc81e71aSthib 	.vop_access	= cd9660_access,
844dc81e71aSthib 	.vop_getattr	= cd9660_getattr,
845dc81e71aSthib 	.vop_setattr	= cd9660_setattr,
846dc81e71aSthib 	.vop_inactive	= cd9660_inactive,
847dc81e71aSthib 	.vop_reclaim	= cd9660_reclaim,
848dc81e71aSthib 	.vop_lock	= cd9660_lock,
849dc81e71aSthib 	.vop_unlock	= cd9660_unlock,
850dc81e71aSthib 	.vop_print	= cd9660_print,
851dc81e71aSthib 	.vop_islocked	= cd9660_islocked,
852dc81e71aSthib 
853dc81e71aSthib 	/* XXX: Keep in sync with spec_vops. */
854dc81e71aSthib 	.vop_lookup	= vop_generic_lookup,
8559aafff14Ssemarie 	.vop_create	= vop_generic_badop,
8569aafff14Ssemarie 	.vop_mknod	= vop_generic_badop,
857dc81e71aSthib 	.vop_open	= spec_open,
858dc81e71aSthib 	.vop_close	= spec_close,
859dc81e71aSthib 	.vop_read	= spec_read,
860dc81e71aSthib 	.vop_write	= spec_write,
861dc81e71aSthib 	.vop_ioctl	= spec_ioctl,
862dc81e71aSthib 	.vop_kqfilter	= spec_kqfilter,
863dc81e71aSthib 	.vop_revoke	= vop_generic_revoke,
864dc81e71aSthib 	.vop_fsync	= spec_fsync,
8659aafff14Ssemarie 	.vop_remove	= vop_generic_badop,
8669aafff14Ssemarie 	.vop_link	= vop_generic_badop,
8679aafff14Ssemarie 	.vop_rename	= vop_generic_badop,
8689aafff14Ssemarie 	.vop_mkdir	= vop_generic_badop,
8699aafff14Ssemarie 	.vop_rmdir	= vop_generic_badop,
8709aafff14Ssemarie 	.vop_symlink	= vop_generic_badop,
8719aafff14Ssemarie 	.vop_readdir	= vop_generic_badop,
8729aafff14Ssemarie 	.vop_readlink	= vop_generic_badop,
8739aafff14Ssemarie 	.vop_abortop	= vop_generic_badop,
874dc81e71aSthib 	.vop_bmap	= vop_generic_bmap,
875dc81e71aSthib 	.vop_strategy	= spec_strategy,
876dc81e71aSthib 	.vop_pathconf	= spec_pathconf,
877dc81e71aSthib 	.vop_advlock	= spec_advlock,
878dc81e71aSthib 	.vop_bwrite	= vop_generic_bwrite,
879df930be7Sderaadt };
880df930be7Sderaadt 
881df930be7Sderaadt #ifdef FIFO
8822d6b9e38Sclaudio const struct vops cd9660_fifovops = {
883dc81e71aSthib 	.vop_access	= cd9660_access,
884dc81e71aSthib 	.vop_getattr	= cd9660_getattr,
885dc81e71aSthib 	.vop_setattr	= cd9660_setattr,
886dc81e71aSthib 	.vop_inactive	= cd9660_inactive,
887dc81e71aSthib 	.vop_reclaim	= cd9660_reclaim,
888dc81e71aSthib 	.vop_lock	= cd9660_lock,
889dc81e71aSthib 	.vop_unlock	= cd9660_unlock,
890dc81e71aSthib 	.vop_print	= cd9660_print,
891dc81e71aSthib 	.vop_islocked	= cd9660_islocked,
892dc81e71aSthib 	.vop_bwrite	= vop_generic_bwrite,
893dc81e71aSthib 
894dc81e71aSthib 	/* XXX: Keep in sync with fifo_vops. */
895dc81e71aSthib 	.vop_lookup	= vop_generic_lookup,
8969aafff14Ssemarie 	.vop_create	= vop_generic_badop,
8979aafff14Ssemarie 	.vop_mknod	= vop_generic_badop,
898dc81e71aSthib 	.vop_open	= fifo_open,
899dc81e71aSthib 	.vop_close	= fifo_close,
900dc81e71aSthib 	.vop_read	= fifo_read,
901dc81e71aSthib 	.vop_write	= fifo_write,
902dc81e71aSthib 	.vop_ioctl	= fifo_ioctl,
903dc81e71aSthib 	.vop_kqfilter	= fifo_kqfilter,
904dc81e71aSthib 	.vop_revoke	= vop_generic_revoke,
905dc81e71aSthib 	.vop_fsync	= nullop,
9069aafff14Ssemarie 	.vop_remove	= vop_generic_badop,
9079aafff14Ssemarie 	.vop_link	= vop_generic_badop,
9089aafff14Ssemarie 	.vop_rename	= vop_generic_badop,
9099aafff14Ssemarie 	.vop_mkdir	= vop_generic_badop,
9109aafff14Ssemarie 	.vop_rmdir	= vop_generic_badop,
9119aafff14Ssemarie 	.vop_symlink	= vop_generic_badop,
9129aafff14Ssemarie 	.vop_readdir	= vop_generic_badop,
9139aafff14Ssemarie 	.vop_readlink	= vop_generic_badop,
9149aafff14Ssemarie 	.vop_abortop	= vop_generic_badop,
915dc81e71aSthib 	.vop_bmap	= vop_generic_bmap,
9169aafff14Ssemarie 	.vop_strategy	= vop_generic_badop,
917dc81e71aSthib 	.vop_pathconf	= fifo_pathconf,
918dc81e71aSthib 	.vop_advlock	= fifo_advlock,
919df930be7Sderaadt };
920df930be7Sderaadt #endif /* FIFO */
921e04616ffStedu 
922e04616ffStedu void filt_cd9660detach(struct knote *kn);
923e04616ffStedu int filt_cd9660read(struct knote *kn, long hint);
924e04616ffStedu int filt_cd9660write(struct knote *kn, long hint);
925e04616ffStedu int filt_cd9660vnode(struct knote *kn, long hint);
926e04616ffStedu 
92794321eb4Svisa const struct filterops cd9660read_filtops = {
928b8213689Svisa 	.f_flags	= FILTEROP_ISFD,
92994321eb4Svisa 	.f_attach	= NULL,
93094321eb4Svisa 	.f_detach	= filt_cd9660detach,
93194321eb4Svisa 	.f_event	= filt_cd9660read,
93294321eb4Svisa };
93394321eb4Svisa 
93494321eb4Svisa const struct filterops cd9660write_filtops = {
935b8213689Svisa 	.f_flags	= FILTEROP_ISFD,
93694321eb4Svisa 	.f_attach	= NULL,
93794321eb4Svisa 	.f_detach	= filt_cd9660detach,
93894321eb4Svisa 	.f_event	= filt_cd9660write,
93994321eb4Svisa };
94094321eb4Svisa 
94194321eb4Svisa const struct filterops cd9660vnode_filtops = {
942b8213689Svisa 	.f_flags	= FILTEROP_ISFD,
94394321eb4Svisa 	.f_attach	= NULL,
94494321eb4Svisa 	.f_detach	= filt_cd9660detach,
94594321eb4Svisa 	.f_event	= filt_cd9660vnode,
94694321eb4Svisa };
947e04616ffStedu 
948e04616ffStedu int
949e04616ffStedu cd9660_kqfilter(void *v)
950e04616ffStedu {
951e04616ffStedu 	struct vop_kqfilter_args *ap = v;
952e04616ffStedu 	struct vnode *vp = ap->a_vp;
953e04616ffStedu 	struct knote *kn = ap->a_kn;
954e04616ffStedu 
955e04616ffStedu 	switch (kn->kn_filter) {
956e04616ffStedu 	case EVFILT_READ:
957e04616ffStedu 		kn->kn_fop = &cd9660read_filtops;
958e04616ffStedu 		break;
959e04616ffStedu 	case EVFILT_WRITE:
960e04616ffStedu 		kn->kn_fop = &cd9660write_filtops;
961e04616ffStedu 		break;
962e04616ffStedu 	case EVFILT_VNODE:
963e04616ffStedu 		kn->kn_fop = &cd9660vnode_filtops;
964e04616ffStedu 		break;
965e04616ffStedu 	default:
966e04616ffStedu 		return (EINVAL);
967e04616ffStedu 	}
968e04616ffStedu 
969e04616ffStedu 	kn->kn_hook = (caddr_t)vp;
970e04616ffStedu 
971cc53a24cSmvs 	klist_insert_locked(&vp->v_klist, kn);
972e04616ffStedu 
973e04616ffStedu 	return (0);
974e04616ffStedu }
975e04616ffStedu 
976e04616ffStedu void
977e04616ffStedu filt_cd9660detach(struct knote *kn)
978e04616ffStedu {
979e04616ffStedu 	struct vnode *vp = (struct vnode *)kn->kn_hook;
980e04616ffStedu 
981cc53a24cSmvs 	klist_remove_locked(&vp->v_klist, kn);
982e04616ffStedu }
983e04616ffStedu 
984e04616ffStedu int
985e04616ffStedu filt_cd9660read(struct knote *kn, long hint)
986e04616ffStedu {
987e04616ffStedu 	struct vnode *vp = (struct vnode *)kn->kn_hook;
988e04616ffStedu 	struct iso_node *node = VTOI(vp);
989e04616ffStedu 
990e04616ffStedu 	/*
991e04616ffStedu 	 * filesystem is gone, so set the EOF flag and schedule
992e04616ffStedu 	 * the knote for deletion.
993e04616ffStedu 	 */
994e04616ffStedu 	if (hint == NOTE_REVOKE) {
995e04616ffStedu 		kn->kn_flags |= (EV_EOF | EV_ONESHOT);
996e04616ffStedu 		return (1);
997e04616ffStedu 	}
998e04616ffStedu 
999836f297bSanton 	kn->kn_data = node->i_size - foffset(kn->kn_fp);
1000e04616ffStedu 	if (kn->kn_data == 0 && kn->kn_sfflags & NOTE_EOF) {
1001e04616ffStedu 		kn->kn_fflags |= NOTE_EOF;
1002e04616ffStedu 		return (1);
1003e04616ffStedu 	}
1004e04616ffStedu 
10056ecc0d7fSvisa 	if (kn->kn_flags & (__EV_POLL | __EV_SELECT))
10066e29a944Smpi 		return (1);
10076e29a944Smpi 
1008e04616ffStedu 	return (kn->kn_data != 0);
1009e04616ffStedu }
1010e04616ffStedu 
1011e04616ffStedu int
1012e04616ffStedu filt_cd9660write(struct knote *kn, long hint)
1013e04616ffStedu {
1014e04616ffStedu 	/*
1015e04616ffStedu 	 * filesystem is gone, so set the EOF flag and schedule
1016e04616ffStedu 	 * the knote for deletion.
1017e04616ffStedu 	 */
1018e04616ffStedu 	if (hint == NOTE_REVOKE) {
1019e04616ffStedu 		kn->kn_flags |= (EV_EOF | EV_ONESHOT);
1020e04616ffStedu 		return (1);
1021e04616ffStedu 	}
1022e04616ffStedu 
1023e04616ffStedu 	kn->kn_data = 0;
1024e04616ffStedu 	return (1);
1025e04616ffStedu }
1026e04616ffStedu 
1027e04616ffStedu int
1028e04616ffStedu filt_cd9660vnode(struct knote *kn, long hint)
1029e04616ffStedu {
1030e04616ffStedu 	if (kn->kn_sfflags & hint)
1031e04616ffStedu 		kn->kn_fflags |= hint;
1032e04616ffStedu 	if (hint == NOTE_REVOKE) {
1033e04616ffStedu 		kn->kn_flags |= EV_EOF;
1034e04616ffStedu 		return (1);
1035e04616ffStedu 	}
1036e04616ffStedu 	return (kn->kn_fflags != 0);
1037e04616ffStedu }
1038