xref: /freebsd/sys/fs/cd9660/cd9660_vnops.c (revision 0de89efe5c443f213c7ea28773ef2dc6cf3af2ed)
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  * $Id: cd9660_vnops.c,v 1.39 1997/09/21 04:22:40 dyson Exp $
40  */
41 
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/namei.h>
45 #include <sys/kernel.h>
46 #include <sys/stat.h>
47 #include <sys/sysctl.h>
48 #include <sys/buf.h>
49 #include <sys/mount.h>
50 #include <sys/vnode.h>
51 #include <miscfs/specfs/specdev.h>
52 #include <miscfs/fifofs/fifo.h>
53 #include <sys/malloc.h>
54 #include <sys/dirent.h>
55 #include <sys/unistd.h>
56 
57 #include <isofs/cd9660/iso.h>
58 #include <isofs/cd9660/cd9660_node.h>
59 #include <isofs/cd9660/iso_rrip.h>
60 
61 static int cd9660_setattr __P((struct vop_setattr_args *));
62 static int cd9660_open __P((struct vop_open_args *));
63 static int cd9660_close __P((struct vop_close_args *));
64 static int cd9660_access __P((struct vop_access_args *));
65 static int cd9660_getattr __P((struct vop_getattr_args *));
66 static int cd9660_read __P((struct vop_read_args *));
67 static int cd9660_ioctl __P((struct vop_ioctl_args *));
68 static int cd9660_mmap __P((struct vop_mmap_args *));
69 static int cd9660_seek __P((struct vop_seek_args *));
70 struct isoreaddir;
71 static int iso_uiodir __P((struct isoreaddir *idp, struct dirent *dp,
72 			   off_t off));
73 static int iso_shipdir __P((struct isoreaddir *idp));
74 static int cd9660_readdir __P((struct vop_readdir_args *));
75 static int cd9660_readlink __P((struct vop_readlink_args *ap));
76 static int cd9660_abortop __P((struct vop_abortop_args *));
77 static int cd9660_lock __P((struct vop_lock_args *));
78 static int cd9660_unlock __P((struct vop_unlock_args *));
79 static int cd9660_strategy __P((struct vop_strategy_args *));
80 static int cd9660_print __P((struct vop_print_args *));
81 static int cd9660_islocked __P((struct vop_islocked_args *));
82 
83 /*
84  * Setattr call. Only allowed for block and character special devices.
85  */
86 int
87 cd9660_setattr(ap)
88 	struct vop_setattr_args /* {
89 		struct vnodeop_desc *a_desc;
90 		struct vnode *a_vp;
91 		struct vattr *a_vap;
92 		struct ucred *a_cred;
93 		struct proc *a_p;
94 	} */ *ap;
95 {
96 	struct vnode *vp = ap->a_vp;
97 	struct vattr *vap = ap->a_vap;
98 
99   	if (vap->va_flags != (u_long)VNOVAL || vap->va_uid != (uid_t)VNOVAL ||
100 	    vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL ||
101 	    vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL)
102 		return (EROFS);
103 	if (vap->va_size != (u_quad_t)VNOVAL) {
104  		switch (vp->v_type) {
105  		case VDIR:
106  			return (EISDIR);
107 		case VLNK:
108 		case VREG:
109 			return (EROFS);
110  		case VCHR:
111  		case VBLK:
112  		case VSOCK:
113  		case VFIFO:
114 			return (0);
115 		}
116 	}
117 	return (0);
118 }
119 
120 /*
121  * Open called.
122  *
123  * Nothing to do.
124  */
125 /* ARGSUSED */
126 static int
127 cd9660_open(ap)
128 	struct vop_open_args /* {
129 		struct vnode *a_vp;
130 		int  a_mode;
131 		struct ucred *a_cred;
132 		struct proc *a_p;
133 	} */ *ap;
134 {
135 	return (0);
136 }
137 
138 /*
139  * Close called
140  *
141  * Update the times on the inode on writeable file systems.
142  */
143 /* ARGSUSED */
144 static int
145 cd9660_close(ap)
146 	struct vop_close_args /* {
147 		struct vnode *a_vp;
148 		int  a_fflag;
149 		struct ucred *a_cred;
150 		struct proc *a_p;
151 	} */ *ap;
152 {
153 	return (0);
154 }
155 
156 /*
157  * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC.
158  * The mode is shifted to select the owner/group/other fields. The
159  * super user is granted all permissions.
160  */
161 /* ARGSUSED */
162 static int
163 cd9660_access(ap)
164 	struct vop_access_args /* {
165 		struct vnode *a_vp;
166 		int  a_mode;
167 		struct ucred *a_cred;
168 		struct proc *a_p;
169 	} */ *ap;
170 {
171 	struct vnode *vp = ap->a_vp;
172 	struct iso_node *ip = VTOI(vp);
173 	struct ucred *cred = ap->a_cred;
174 	mode_t mask, mode = ap->a_mode;
175 	gid_t *gp;
176 	int i;
177 
178 	/*
179 	 * Disallow write attempts unless the file is a socket,
180 	 * fifo, or a block or character device resident on the
181 	 * file system.
182 	 */
183 	if (mode & VWRITE) {
184 		switch (vp->v_type) {
185 		case VDIR:
186 		case VLNK:
187 		case VREG:
188 			return (EROFS);
189 		}
190 	}
191 
192 	/* User id 0 always gets access. */
193 	if (cred->cr_uid == 0)
194 		return (0);
195 
196 	mask = 0;
197 
198 	/* Otherwise, check the owner. */
199 	if (cred->cr_uid == ip->inode.iso_uid) {
200 		if (mode & VEXEC)
201 			mask |= S_IXUSR;
202 		if (mode & VREAD)
203 			mask |= S_IRUSR;
204 		if (mode & VWRITE)
205 			mask |= S_IWUSR;
206 		return ((ip->inode.iso_mode & mask) == mask ? 0 : EACCES);
207 	}
208 
209 	/* Otherwise, check the groups. */
210 	for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++)
211 		if (ip->inode.iso_gid == *gp) {
212 			if (mode & VEXEC)
213 				mask |= S_IXGRP;
214 			if (mode & VREAD)
215 				mask |= S_IRGRP;
216 			if (mode & VWRITE)
217 				mask |= S_IWGRP;
218 			return ((ip->inode.iso_mode & mask) == mask ?
219 			    0 : EACCES);
220 		}
221 
222 	/* Otherwise, check everyone else. */
223 	if (mode & VEXEC)
224 		mask |= S_IXOTH;
225 	if (mode & VREAD)
226 		mask |= S_IROTH;
227 	if (mode & VWRITE)
228 		mask |= S_IWOTH;
229 	return ((ip->inode.iso_mode & mask) == mask ? 0 : EACCES);
230 }
231 
232 static int
233 cd9660_getattr(ap)
234 	struct vop_getattr_args /* {
235 		struct vnode *a_vp;
236 		struct vattr *a_vap;
237 		struct ucred *a_cred;
238 		struct proc *a_p;
239 	} */ *ap;
240 
241 {
242 	struct vnode *vp = ap->a_vp;
243 	register struct vattr *vap = ap->a_vap;
244 	register struct iso_node *ip = VTOI(vp);
245 
246 	vap->va_fsid	= ip->i_dev;
247 	vap->va_fileid	= ip->i_number;
248 
249 	vap->va_mode	= ip->inode.iso_mode;
250 	vap->va_nlink	= ip->inode.iso_links;
251 	vap->va_uid	= ip->inode.iso_uid;
252 	vap->va_gid	= ip->inode.iso_gid;
253 	vap->va_atime	= ip->inode.iso_atime;
254 	vap->va_mtime	= ip->inode.iso_mtime;
255 	vap->va_ctime	= ip->inode.iso_ctime;
256 	vap->va_rdev	= ip->inode.iso_rdev;
257 
258 	vap->va_size	= (u_quad_t) ip->i_size;
259 	if (ip->i_size == 0 && (vap->va_mode & S_IFMT) == S_IFLNK) {
260 		struct vop_readlink_args rdlnk;
261 		struct iovec aiov;
262 		struct uio auio;
263 		char *cp;
264 
265 		MALLOC(cp, char *, MAXPATHLEN, M_TEMP, M_WAITOK);
266 		aiov.iov_base = cp;
267 		aiov.iov_len = MAXPATHLEN;
268 		auio.uio_iov = &aiov;
269 		auio.uio_iovcnt = 1;
270 		auio.uio_offset = 0;
271 		auio.uio_rw = UIO_READ;
272 		auio.uio_segflg = UIO_SYSSPACE;
273 		auio.uio_procp = ap->a_p;
274 		auio.uio_resid = MAXPATHLEN;
275 		rdlnk.a_uio = &auio;
276 		rdlnk.a_vp = ap->a_vp;
277 		rdlnk.a_cred = ap->a_cred;
278 		if (cd9660_readlink(&rdlnk) == 0)
279 			vap->va_size = MAXPATHLEN - auio.uio_resid;
280 		FREE(cp, M_TEMP);
281 	}
282 	vap->va_flags	= 0;
283 	vap->va_gen = 1;
284 	vap->va_blocksize = ip->i_mnt->logical_block_size;
285 	vap->va_bytes	= (u_quad_t) ip->i_size;
286 	vap->va_type	= vp->v_type;
287 	vap->va_filerev	= 0;
288 	return (0);
289 }
290 
291 /*
292  * Vnode op for reading.
293  */
294 static int
295 cd9660_read(ap)
296 	struct vop_read_args /* {
297 		struct vnode *a_vp;
298 		struct uio *a_uio;
299 		int a_ioflag;
300 		struct ucred *a_cred;
301 	} */ *ap;
302 {
303 	struct vnode *vp = ap->a_vp;
304 	register struct uio *uio = ap->a_uio;
305 	register struct iso_node *ip = VTOI(vp);
306 	register struct iso_mnt *imp;
307 	struct buf *bp;
308 	daddr_t lbn, rablock;
309 	off_t diff;
310 	int rasize, error = 0;
311 	long size, n, on;
312 
313 	if (uio->uio_resid == 0)
314 		return (0);
315 	if (uio->uio_offset < 0)
316 		return (EINVAL);
317 	ip->i_flag |= IN_ACCESS;
318 	imp = ip->i_mnt;
319 	do {
320 		lbn = lblkno(imp, uio->uio_offset);
321 		on = blkoff(imp, uio->uio_offset);
322 		n = min((u_int)(imp->logical_block_size - on),
323 			uio->uio_resid);
324 		diff = (off_t)ip->i_size - uio->uio_offset;
325 		if (diff <= 0)
326 			return (0);
327 		if (diff < n)
328 			n = diff;
329 		size = blksize(imp, ip, lbn);
330 		rablock = lbn + 1;
331 		if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) {
332 			if (lblktosize(imp, rablock) <= ip->i_size)
333 				error = cluster_read(vp, (off_t)ip->i_size,
334 				         lbn, size, NOCRED, uio->uio_resid,
335 					 (ap->a_ioflag >> 16), &bp);
336 			else
337 				error = bread(vp, lbn, size, NOCRED, &bp);
338 		} else {
339 			if (vp->v_lastr + 1 == lbn &&
340 			    lblktosize(imp, rablock) < ip->i_size) {
341 				rasize = blksize(imp, ip, rablock);
342 				error = breadn(vp, lbn, size, &rablock,
343 					       &rasize, 1, NOCRED, &bp);
344 			} else
345 				error = bread(vp, lbn, size, NOCRED, &bp);
346 		}
347 		vp->v_lastr = lbn;
348 		n = min(n, size - bp->b_resid);
349 		if (error) {
350 			brelse(bp);
351 			return (error);
352 		}
353 
354 		error = uiomove(bp->b_data + on, (int)n, uio);
355 		brelse(bp);
356 	} while (error == 0 && uio->uio_resid > 0 && n != 0);
357 	return (error);
358 }
359 
360 /* ARGSUSED */
361 static int
362 cd9660_ioctl(ap)
363 	struct vop_ioctl_args /* {
364 		struct vnode *a_vp;
365 		u_long a_command;
366 		caddr_t  a_data;
367 		int  a_fflag;
368 		struct ucred *a_cred;
369 		struct proc *a_p;
370 	} */ *ap;
371 {
372 	printf("You did ioctl for isofs !!\n");
373 	return (ENOTTY);
374 }
375 
376 /*
377  * Mmap a file
378  *
379  * NB Currently unsupported.
380  */
381 /* ARGSUSED */
382 static int
383 cd9660_mmap(ap)
384 	struct vop_mmap_args /* {
385 		struct vnode *a_vp;
386 		int  a_fflags;
387 		struct ucred *a_cred;
388 		struct proc *a_p;
389 	} */ *ap;
390 {
391 
392 	return (EINVAL);
393 }
394 
395 /*
396  * Seek on a file
397  *
398  * Nothing to do, so just return.
399  */
400 /* ARGSUSED */
401 static int
402 cd9660_seek(ap)
403 	struct vop_seek_args /* {
404 		struct vnode *a_vp;
405 		off_t  a_oldoff;
406 		off_t  a_newoff;
407 		struct ucred *a_cred;
408 	} */ *ap;
409 {
410 
411 	return (0);
412 }
413 
414 /*
415  * Structure for reading directories
416  */
417 struct isoreaddir {
418 	struct dirent saveent;
419 	struct dirent assocent;
420 	struct dirent current;
421 	off_t saveoff;
422 	off_t assocoff;
423 	off_t curroff;
424 	struct uio *uio;
425 	off_t uio_off;
426 	int eofflag;
427 	u_long *cookies;
428 	int ncookies;
429 };
430 
431 int
432 iso_uiodir(idp,dp,off)
433 	struct isoreaddir *idp;
434 	struct dirent *dp;
435 	off_t off;
436 {
437 	int error;
438 
439 	dp->d_name[dp->d_namlen] = 0;
440 	dp->d_reclen = GENERIC_DIRSIZ(dp);
441 
442 	if (idp->uio->uio_resid < dp->d_reclen) {
443 		idp->eofflag = 0;
444 		return (-1);
445 	}
446 
447 	if (idp->cookies) {
448 		if (idp->ncookies <= 0) {
449 			idp->eofflag = 0;
450 			return (-1);
451 		}
452 
453 		*idp->cookies++ = off;
454 		--idp->ncookies;
455 	}
456 
457 	if (error = uiomove((caddr_t) dp,dp->d_reclen,idp->uio))
458 		return (error);
459 	idp->uio_off = off;
460 	return (0);
461 }
462 
463 int
464 iso_shipdir(idp)
465 	struct isoreaddir *idp;
466 {
467 	struct dirent *dp;
468 	int cl, sl, assoc;
469 	int error;
470 	char *cname, *sname;
471 
472 	cl = idp->current.d_namlen;
473 	cname = idp->current.d_name;
474 assoc = (cl > 1) && (*cname == ASSOCCHAR);
475 	if (assoc) {
476 		cl--;
477 		cname++;
478 	}
479 
480 	dp = &idp->saveent;
481 	sname = dp->d_name;
482 	if (!(sl = dp->d_namlen)) {
483 		dp = &idp->assocent;
484 		sname = dp->d_name + 1;
485 		sl = dp->d_namlen - 1;
486 	}
487 	if (sl > 0) {
488 		if (sl != cl
489 		    || bcmp(sname,cname,sl)) {
490 			if (idp->assocent.d_namlen) {
491 				if (error = iso_uiodir(idp,&idp->assocent,idp->assocoff))
492 					return (error);
493 				idp->assocent.d_namlen = 0;
494 			}
495 			if (idp->saveent.d_namlen) {
496 				if (error = iso_uiodir(idp,&idp->saveent,idp->saveoff))
497 					return (error);
498 				idp->saveent.d_namlen = 0;
499 			}
500 		}
501 	}
502 	idp->current.d_reclen = GENERIC_DIRSIZ(&idp->current);
503 	if (assoc) {
504 		idp->assocoff = idp->curroff;
505 		bcopy(&idp->current,&idp->assocent,idp->current.d_reclen);
506 	} else {
507 		idp->saveoff = idp->curroff;
508 		bcopy(&idp->current,&idp->saveent,idp->current.d_reclen);
509 	}
510 	return (0);
511 }
512 
513 /*
514  * Vnode op for readdir
515  */
516 static int
517 cd9660_readdir(ap)
518 	struct vop_readdir_args /* {
519 		struct vnode *a_vp;
520 		struct uio *a_uio;
521 		struct ucred *a_cred;
522 		int *a_eofflag;
523 		int *a_ncookies;
524 		u_long *a_cookies;
525 	} */ *ap;
526 {
527 	register struct uio *uio = ap->a_uio;
528 	struct isoreaddir *idp;
529 	struct vnode *vdp = ap->a_vp;
530 	struct iso_node *dp;
531 	struct iso_mnt *imp;
532 	struct buf *bp = NULL;
533 	struct iso_directory_record *ep;
534 	int entryoffsetinblock;
535 	doff_t endsearch;
536 	u_long bmask;
537 	int error = 0;
538 	int reclen;
539 	u_short namelen;
540 	int ncookies = 0;
541 	u_long *cookies = NULL;
542 
543 	dp = VTOI(vdp);
544 	imp = dp->i_mnt;
545 	bmask = imp->im_bmask;
546 
547 	MALLOC(idp, struct isoreaddir *, sizeof(*idp), M_TEMP, M_WAITOK);
548 	idp->saveent.d_namlen = idp->assocent.d_namlen = 0;
549 	/*
550 	 * XXX
551 	 * Is it worth trying to figure out the type?
552 	 */
553 	idp->saveent.d_type = idp->assocent.d_type = idp->current.d_type =
554 	    DT_UNKNOWN;
555 	idp->uio = uio;
556 	if (ap->a_ncookies == NULL) {
557 		idp->cookies = NULL;
558 	} else {
559 		/*
560 		 * Guess the number of cookies needed.
561 		 */
562 		ncookies = uio->uio_resid / 16;
563 		MALLOC(cookies, u_long *, ncookies * sizeof(u_int), M_TEMP,
564 		    M_WAITOK);
565 		idp->cookies = cookies;
566 		idp->ncookies = ncookies;
567 	}
568 	idp->eofflag = 1;
569 	idp->curroff = uio->uio_offset;
570 
571 	if ((entryoffsetinblock = idp->curroff & bmask) &&
572 	    (error = VOP_BLKATOFF(vdp, (off_t)idp->curroff, NULL, &bp))) {
573 		FREE(idp, M_TEMP);
574 		return (error);
575 	}
576 	endsearch = dp->i_size;
577 
578 	while (idp->curroff < endsearch) {
579 		/*
580 		 * If offset is on a block boundary,
581 		 * read the next directory block.
582 		 * Release previous if it exists.
583 		 */
584 		if ((idp->curroff & bmask) == 0) {
585 			if (bp != NULL)
586 				brelse(bp);
587 			if (error =
588 			    VOP_BLKATOFF(vdp, (off_t)idp->curroff, NULL, &bp))
589 				break;
590 			entryoffsetinblock = 0;
591 		}
592 		/*
593 		 * Get pointer to next entry.
594 		 */
595 		ep = (struct iso_directory_record *)
596 			((char *)bp->b_data + entryoffsetinblock);
597 
598 		reclen = isonum_711(ep->length);
599 		if (reclen == 0) {
600 			/* skip to next block, if any */
601 			idp->curroff =
602 			    (idp->curroff & ~bmask) + imp->logical_block_size;
603 			continue;
604 		}
605 
606 		if (reclen < ISO_DIRECTORY_RECORD_SIZE) {
607 			error = EINVAL;
608 			/* illegal entry, stop */
609 			break;
610 		}
611 
612 		if (entryoffsetinblock + reclen > imp->logical_block_size) {
613 			error = EINVAL;
614 			/* illegal directory, so stop looking */
615 			break;
616 		}
617 
618 		idp->current.d_namlen = isonum_711(ep->name_len);
619 
620 		if (reclen < ISO_DIRECTORY_RECORD_SIZE + idp->current.d_namlen) {
621 			error = EINVAL;
622 			/* illegal entry, stop */
623 			break;
624 		}
625 
626 		if (isonum_711(ep->flags)&2)
627 			idp->current.d_fileno = isodirino(ep, imp);
628 		else
629 			idp->current.d_fileno = dbtob(bp->b_blkno) +
630 				entryoffsetinblock;
631 
632 		idp->curroff += reclen;
633 
634 		switch (imp->iso_ftype) {
635 		case ISO_FTYPE_RRIP:
636 			cd9660_rrip_getname(ep,idp->current.d_name, &namelen,
637 					   &idp->current.d_fileno,imp);
638 			idp->current.d_namlen = (u_char)namelen;
639 			if (idp->current.d_namlen)
640 				error = iso_uiodir(idp,&idp->current,idp->curroff);
641 			break;
642 		default: /* ISO_FTYPE_DEFAULT || ISO_FTYPE_9660 || ISO_FTYPE_HIGH_SIERRA*/
643 			strcpy(idp->current.d_name,"..");
644 			switch (ep->name[0]) {
645 			case 0:
646 				idp->current.d_namlen = 1;
647 				error = iso_uiodir(idp,&idp->current,idp->curroff);
648 				break;
649 			case 1:
650 				idp->current.d_namlen = 2;
651 				error = iso_uiodir(idp,&idp->current,idp->curroff);
652 				break;
653 			default:
654 				isofntrans(ep->name,idp->current.d_namlen,
655 					   idp->current.d_name, &namelen,
656 					   imp->iso_ftype == ISO_FTYPE_9660,
657 					   isonum_711(ep->flags)&4);
658 				idp->current.d_namlen = (u_char)namelen;
659 				if (imp->iso_ftype == ISO_FTYPE_DEFAULT)
660 					error = iso_shipdir(idp);
661 				else
662 					error = iso_uiodir(idp,&idp->current,idp->curroff);
663 				break;
664 			}
665 		}
666 		if (error)
667 			break;
668 
669 		entryoffsetinblock += reclen;
670 	}
671 
672 	if (!error && imp->iso_ftype == ISO_FTYPE_DEFAULT) {
673 		idp->current.d_namlen = 0;
674 		error = iso_shipdir(idp);
675 	}
676 	if (error < 0)
677 		error = 0;
678 
679 	if (ap->a_ncookies != NULL) {
680 		if (error)
681 			free(cookies, M_TEMP);
682 		else {
683 			/*
684 			 * Work out the number of cookies actually used.
685 			 */
686 			*ap->a_ncookies = ncookies - idp->ncookies;
687 			*ap->a_cookies = cookies;
688 		}
689 	}
690 
691 	if (bp)
692 		brelse (bp);
693 
694 	uio->uio_offset = idp->uio_off;
695 	*ap->a_eofflag = idp->eofflag;
696 
697 	FREE(idp, M_TEMP);
698 
699 	return (error);
700 }
701 
702 /*
703  * Return target name of a symbolic link
704  * Shouldn't we get the parent vnode and read the data from there?
705  * This could eventually result in deadlocks in cd9660_lookup.
706  * But otherwise the block read here is in the block buffer two times.
707  */
708 typedef struct iso_directory_record ISODIR;
709 typedef struct iso_node		    ISONODE;
710 typedef struct iso_mnt		    ISOMNT;
711 static int
712 cd9660_readlink(ap)
713 	struct vop_readlink_args /* {
714 		struct vnode *a_vp;
715 		struct uio *a_uio;
716 		struct ucred *a_cred;
717 	} */ *ap;
718 {
719 	ISONODE	*ip;
720 	ISODIR	*dirp;
721 	ISOMNT	*imp;
722 	struct	buf *bp;
723 	struct	uio *uio;
724 	u_short	symlen;
725 	int	error;
726 	char	*symname;
727 
728 	ip  = VTOI(ap->a_vp);
729 	imp = ip->i_mnt;
730 	uio = ap->a_uio;
731 
732 	if (imp->iso_ftype != ISO_FTYPE_RRIP)
733 		return (EINVAL);
734 
735 	/*
736 	 * Get parents directory record block that this inode included.
737 	 */
738 	error = bread(imp->im_devvp,
739 		      (ip->i_number >> imp->im_bshift) <<
740 		      (imp->im_bshift - DEV_BSHIFT),
741 		      imp->logical_block_size, NOCRED, &bp);
742 	if (error) {
743 		brelse(bp);
744 		return (EINVAL);
745 	}
746 
747 	/*
748 	 * Setup the directory pointer for this inode
749 	 */
750 	dirp = (ISODIR *)(bp->b_data + (ip->i_number & imp->im_bmask));
751 
752 	/*
753 	 * Just make sure, we have a right one....
754 	 *   1: Check not cross boundary on block
755 	 */
756 	if ((ip->i_number & imp->im_bmask) + isonum_711(dirp->length)
757 	    > (unsigned)imp->logical_block_size) {
758 		brelse(bp);
759 		return (EINVAL);
760 	}
761 
762 	/*
763 	 * Now get a buffer
764 	 * Abuse a namei buffer for now.
765 	 */
766 	if (uio->uio_segflg == UIO_SYSSPACE)
767 		symname = uio->uio_iov->iov_base;
768 	else
769 		symname = zalloc(namei_zone);
770 
771 	/*
772 	 * Ok, we just gathering a symbolic name in SL record.
773 	 */
774 	if (cd9660_rrip_getsymname(dirp, symname, &symlen, imp) == 0) {
775 		if (uio->uio_segflg != UIO_SYSSPACE)
776 			zfree(namei_zone, symname);
777 		brelse(bp);
778 		return (EINVAL);
779 	}
780 	/*
781 	 * Don't forget before you leave from home ;-)
782 	 */
783 	brelse(bp);
784 
785 	/*
786 	 * return with the symbolic name to caller's.
787 	 */
788 	if (uio->uio_segflg != UIO_SYSSPACE) {
789 		error = uiomove(symname, symlen, uio);
790 		zfree(namei_zone, symname);
791 		return (error);
792 	}
793 	uio->uio_resid -= symlen;
794 	uio->uio_iov->iov_base += symlen;
795 	uio->uio_iov->iov_len -= symlen;
796 	return (0);
797 }
798 
799 /*
800  * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually
801  * done. If a buffer has been saved in anticipation of a CREATE, delete it.
802  */
803 static int
804 cd9660_abortop(ap)
805 	struct vop_abortop_args /* {
806 		struct vnode *a_dvp;
807 		struct componentname *a_cnp;
808 	} */ *ap;
809 {
810 	if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF)
811 		zfree(namei_zone, ap->a_cnp->cn_pnbuf);
812 	return (0);
813 }
814 
815 /*
816  * Lock an inode.
817  */
818 static int
819 cd9660_lock(ap)
820 	struct vop_lock_args /* {
821 		struct vnode *a_vp;
822 		int a_flags;
823 		struct proc *a_p;
824 	} */ *ap;
825 {
826 	struct vnode *vp = ap->a_vp;
827 
828 	return (lockmgr(&VTOI(vp)->i_lock, ap->a_flags, &vp->v_interlock,
829 		ap->a_p));
830 }
831 
832 /*
833  * Unlock an inode.
834  */
835 static int
836 cd9660_unlock(ap)
837 	struct vop_unlock_args /* {
838 		struct vnode *a_vp;
839 		int a_flags;
840 		struct proc *a_p;
841 	} */ *ap;
842 {
843 	struct vnode *vp = ap->a_vp;
844 
845 	return (lockmgr(&VTOI(vp)->i_lock, ap->a_flags | LK_RELEASE,
846 		&vp->v_interlock, ap->a_p));
847 }
848 
849 /*
850  * Calculate the logical to physical mapping if not done already,
851  * then call the device strategy routine.
852  */
853 static int
854 cd9660_strategy(ap)
855 	struct vop_strategy_args /* {
856 		struct buf *a_bp;
857 	} */ *ap;
858 {
859 	register struct buf *bp = ap->a_bp;
860 	register struct vnode *vp = bp->b_vp;
861 	register struct iso_node *ip;
862 	int error;
863 
864 	ip = VTOI(vp);
865 	if (vp->v_type == VBLK || vp->v_type == VCHR)
866 		panic("cd9660_strategy: spec");
867 	if (bp->b_blkno == bp->b_lblkno) {
868 		if ((error =
869 		    VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL, NULL))) {
870 			bp->b_error = error;
871 			bp->b_flags |= B_ERROR;
872 			biodone(bp);
873 			return (error);
874 		}
875 		if ((long)bp->b_blkno == -1)
876 			clrbuf(bp);
877 	}
878 	if ((long)bp->b_blkno == -1) {
879 		biodone(bp);
880 		return (0);
881 	}
882 	vp = ip->i_devvp;
883 	bp->b_dev = vp->v_rdev;
884 	VOCALL (vp->v_op, VOFFSET(vop_strategy), ap);
885 	return (0);
886 }
887 
888 /*
889  * Print out the contents of an inode.
890  */
891 static int
892 cd9660_print(ap)
893 	struct vop_print_args /* {
894 		struct vnode *a_vp;
895 	} */ *ap;
896 {
897 
898 	printf("tag VT_ISOFS, isofs vnode\n");
899 	return (0);
900 }
901 
902 /*
903  * Check for a locked inode.
904  */
905 int
906 cd9660_islocked(ap)
907 	struct vop_islocked_args /* {
908 		struct vnode *a_vp;
909 	} */ *ap;
910 {
911 
912 	return (lockstatus(&VTOI(ap->a_vp)->i_lock));
913 }
914 
915 /*
916  * Return POSIX pathconf information applicable to cd9660 filesystems.
917  */
918 int
919 cd9660_pathconf(ap)
920 	struct vop_pathconf_args /* {
921 		struct vnode *a_vp;
922 		int a_name;
923 		register_t *a_retval;
924 	} */ *ap;
925 {
926 
927 	switch (ap->a_name) {
928 	case _PC_LINK_MAX:
929 		*ap->a_retval = 1;
930 		return (0);
931 	case _PC_NAME_MAX:
932 		if (VTOI(ap->a_vp)->i_mnt->iso_ftype == ISO_FTYPE_RRIP)
933 			*ap->a_retval = NAME_MAX;
934 		else
935 			*ap->a_retval = 37;
936 		return (0);
937 	case _PC_PATH_MAX:
938 		*ap->a_retval = PATH_MAX;
939 		return (0);
940 	case _PC_PIPE_BUF:
941 		*ap->a_retval = PIPE_BUF;
942 		return (0);
943 	case _PC_CHOWN_RESTRICTED:
944 		*ap->a_retval = 1;
945 		return (0);
946 	case _PC_NO_TRUNC:
947 		*ap->a_retval = 1;
948 		return (0);
949 	default:
950 		return (EINVAL);
951 	}
952 	/* NOTREACHED */
953 }
954 
955 /*
956  * Global vfs data structures for isofs
957  */
958 #define cd9660_create \
959 	((int (*) __P((struct  vop_create_args *)))eopnotsupp)
960 #define cd9660_mknod ((int (*) __P((struct  vop_mknod_args *)))eopnotsupp)
961 #define cd9660_write ((int (*) __P((struct  vop_write_args *)))eopnotsupp)
962 #ifdef NFS
963 #define	 cd9660_lease_check lease_check
964 #else
965 #define	 cd9660_lease_check ((int (*) __P((struct vop_lease_args *)))nullop)
966 #endif
967 #define cd9660_poll vop_nopoll
968 #define cd9660_fsync ((int (*) __P((struct  vop_fsync_args *)))nullop)
969 #define cd9660_remove \
970 	((int (*) __P((struct  vop_remove_args *)))eopnotsupp)
971 #define cd9660_link ((int (*) __P((struct  vop_link_args *)))eopnotsupp)
972 #define cd9660_rename \
973 	((int (*) __P((struct  vop_rename_args *)))eopnotsupp)
974 #define cd9660_mkdir ((int (*) __P((struct  vop_mkdir_args *)))eopnotsupp)
975 #define cd9660_rmdir ((int (*) __P((struct  vop_rmdir_args *)))eopnotsupp)
976 #define cd9660_symlink \
977 	((int (*) __P((struct vop_symlink_args *)))eopnotsupp)
978 #define cd9660_advlock \
979 	((int (*) __P((struct vop_advlock_args *)))eopnotsupp)
980 #define cd9660_valloc ((int(*) __P(( \
981 		struct vnode *pvp, \
982 		int mode, \
983 		struct ucred *cred, \
984 		struct vnode **vpp))) eopnotsupp)
985 #define cd9660_vfree ((int (*) __P((struct  vop_vfree_args *)))eopnotsupp)
986 #define cd9660_truncate \
987 	((int (*) __P((struct  vop_truncate_args *)))eopnotsupp)
988 #define cd9660_update \
989 	((int (*) __P((struct  vop_update_args *)))eopnotsupp)
990 #define cd9660_bwrite \
991 	((int (*) __P((struct  vop_bwrite_args *)))eopnotsupp)
992 
993 /*
994  * Global vfs data structures for cd9660
995  */
996 vop_t **cd9660_vnodeop_p;
997 struct vnodeopv_entry_desc cd9660_vnodeop_entries[] = {
998 
999 	{ &vop_default_desc, (vop_t *)vn_default_error },
1000 	{ &vop_lookup_desc, (vop_t *)vfs_cache_lookup },	/* lookup */
1001 	{ &vop_cachedlookup_desc, (vop_t *)cd9660_lookup },	/* lookup */
1002 	{ &vop_create_desc, (vop_t *)cd9660_create },	/* create */
1003 /* XXX: vop_whiteout */
1004 	{ &vop_mknod_desc, (vop_t *)cd9660_mknod },	/* mknod */
1005 	{ &vop_open_desc, (vop_t *)cd9660_open },	/* open */
1006 	{ &vop_close_desc, (vop_t *)cd9660_close },	/* close */
1007 	{ &vop_access_desc, (vop_t *)cd9660_access },	/* access */
1008 	{ &vop_getattr_desc, (vop_t *)cd9660_getattr },	/* getattr */
1009 	{ &vop_setattr_desc, (vop_t *)cd9660_setattr },	/* setattr */
1010 	{ &vop_read_desc, (vop_t *)cd9660_read },	/* read */
1011 	{ &vop_write_desc, (vop_t *)cd9660_write },	/* write */
1012 	{ &vop_lease_desc, (vop_t *)cd9660_lease_check },/* lease */
1013 	{ &vop_ioctl_desc, (vop_t *)cd9660_ioctl },	/* ioctl */
1014 	{ &vop_poll_desc, (vop_t *)cd9660_poll },	/* poll */
1015 	{ &vop_revoke_desc, (vop_t *)cd9660_revoke },	/* revoke */
1016 	{ &vop_mmap_desc, (vop_t *)cd9660_mmap },	/* mmap */
1017 	{ &vop_fsync_desc, (vop_t *)cd9660_fsync },	/* fsync */
1018 	{ &vop_seek_desc, (vop_t *)cd9660_seek },	/* seek */
1019 	{ &vop_remove_desc, (vop_t *)cd9660_remove },	/* remove */
1020 	{ &vop_link_desc, (vop_t *)cd9660_link },	/* link */
1021 	{ &vop_rename_desc, (vop_t *)cd9660_rename },	/* rename */
1022 	{ &vop_mkdir_desc, (vop_t *)cd9660_mkdir },	/* mkdir */
1023 	{ &vop_rmdir_desc, (vop_t *)cd9660_rmdir },	/* rmdir */
1024 	{ &vop_symlink_desc, (vop_t *)cd9660_symlink },	/* symlink */
1025 	{ &vop_readdir_desc, (vop_t *)cd9660_readdir },	/* readdir */
1026 	{ &vop_readlink_desc, (vop_t *)cd9660_readlink },/* readlink */
1027 	{ &vop_abortop_desc, (vop_t *)cd9660_abortop },	/* abortop */
1028 	{ &vop_inactive_desc, (vop_t *)cd9660_inactive },/* inactive */
1029 	{ &vop_reclaim_desc, (vop_t *)cd9660_reclaim },	/* reclaim */
1030 	{ &vop_lock_desc, (vop_t *)cd9660_lock },	/* lock */
1031 	{ &vop_unlock_desc, (vop_t *)cd9660_unlock },	/* unlock */
1032 	{ &vop_bmap_desc, (vop_t *)cd9660_bmap },	/* bmap */
1033 	{ &vop_strategy_desc, (vop_t *)cd9660_strategy },/* strategy */
1034 	{ &vop_print_desc, (vop_t *)cd9660_print },	/* print */
1035 	{ &vop_islocked_desc, (vop_t *)cd9660_islocked },/* islocked */
1036 	{ &vop_pathconf_desc, (vop_t *)cd9660_pathconf },/* pathconf */
1037 	{ &vop_advlock_desc, (vop_t *)cd9660_advlock },	/* advlock */
1038 	{ &vop_blkatoff_desc, (vop_t *)cd9660_blkatoff },/* blkatoff */
1039 	{ &vop_valloc_desc, (vop_t *)cd9660_valloc },	/* valloc */
1040 /* XXX: vop_reallocblks */
1041 	{ &vop_vfree_desc, (vop_t *)cd9660_vfree },	/* vfree */
1042 	{ &vop_truncate_desc, (vop_t *)cd9660_truncate },/* truncate */
1043 	{ &vop_update_desc, (vop_t *)cd9660_update },	/* update */
1044 /* XXX: vop_getpages */
1045 /* XXX: vop_putpages */
1046 	{ &vop_bwrite_desc, (vop_t *)vn_bwrite },
1047 	{ NULL, NULL }
1048 };
1049 static struct vnodeopv_desc cd9660_vnodeop_opv_desc =
1050 	{ &cd9660_vnodeop_p, cd9660_vnodeop_entries };
1051 VNODEOP_SET(cd9660_vnodeop_opv_desc);
1052 
1053 /*
1054  * Special device vnode ops
1055  */
1056 vop_t **cd9660_specop_p;
1057 struct vnodeopv_entry_desc cd9660_specop_entries[] = {
1058 	{ &vop_default_desc, (vop_t *)vn_default_error },
1059 	{ &vop_lookup_desc, (vop_t *)spec_lookup },	/* lookup */
1060 /* XXX: vop_cachedlookup */
1061 	{ &vop_create_desc, (vop_t *)spec_create },	/* create */
1062 /* XXX: vop_whiteout */
1063 	{ &vop_mknod_desc, (vop_t *)spec_mknod },	/* mknod */
1064 	{ &vop_open_desc, (vop_t *)spec_open },		/* open */
1065 	{ &vop_close_desc, (vop_t *)spec_close },	/* close */
1066 	{ &vop_access_desc, (vop_t *)cd9660_access },	/* access */
1067 	{ &vop_getattr_desc, (vop_t *)cd9660_getattr },	/* getattr */
1068 	{ &vop_setattr_desc, (vop_t *)cd9660_setattr },	/* setattr */
1069 	{ &vop_read_desc, (vop_t *)spec_read },		/* read */
1070 	{ &vop_write_desc, (vop_t *)spec_write },	/* write */
1071 	{ &vop_lease_desc, (vop_t *)spec_lease_check },	/* lease */
1072 	{ &vop_ioctl_desc, (vop_t *)spec_ioctl },	/* ioctl */
1073 	{ &vop_poll_desc, (vop_t *)spec_poll },		/* poll */
1074 	{ &vop_revoke_desc, (vop_t *)spec_revoke },	/* revoke */
1075 	{ &vop_mmap_desc, (vop_t *)spec_mmap },		/* mmap */
1076 	{ &vop_fsync_desc, (vop_t *)spec_fsync },	/* fsync */
1077 	{ &vop_seek_desc, (vop_t *)spec_seek },		/* seek */
1078 	{ &vop_remove_desc, (vop_t *)spec_remove },	/* remove */
1079 	{ &vop_link_desc, (vop_t *)spec_link },		/* link */
1080 	{ &vop_rename_desc, (vop_t *)spec_rename },	/* rename */
1081 	{ &vop_mkdir_desc, (vop_t *)spec_mkdir },	/* mkdir */
1082 	{ &vop_rmdir_desc, (vop_t *)spec_rmdir },	/* rmdir */
1083 	{ &vop_symlink_desc, (vop_t *)spec_symlink },	/* symlink */
1084 	{ &vop_readdir_desc, (vop_t *)spec_readdir },	/* readdir */
1085 	{ &vop_readlink_desc, (vop_t *)spec_readlink },	/* readlink */
1086 	{ &vop_abortop_desc, (vop_t *)spec_abortop },	/* abortop */
1087 	{ &vop_inactive_desc, (vop_t *)cd9660_inactive },/* inactive */
1088 	{ &vop_reclaim_desc, (vop_t *)cd9660_reclaim },	/* reclaim */
1089 	{ &vop_lock_desc, (vop_t *)cd9660_lock },	/* lock */
1090 	{ &vop_unlock_desc, (vop_t *)cd9660_unlock },	/* unlock */
1091 	{ &vop_bmap_desc, (vop_t *)spec_bmap },		/* bmap */
1092 	{ &vop_strategy_desc, (vop_t *)spec_strategy },	/* strategy */
1093 	{ &vop_print_desc, (vop_t *)cd9660_print },	/* print */
1094 	{ &vop_islocked_desc, (vop_t *)cd9660_islocked },/* islocked */
1095 	{ &vop_pathconf_desc, (vop_t *)spec_pathconf },	/* pathconf */
1096 	{ &vop_advlock_desc, (vop_t *)spec_advlock },	/* advlock */
1097 	{ &vop_blkatoff_desc, (vop_t *)spec_blkatoff },	/* blkatoff */
1098 	{ &vop_valloc_desc, (vop_t *)spec_valloc },	/* valloc */
1099 /* XXX: vop_reallocblks */
1100 	{ &vop_vfree_desc, (vop_t *)spec_vfree },	/* vfree */
1101 	{ &vop_truncate_desc, (vop_t *)spec_truncate },	/* truncate */
1102 	{ &vop_update_desc, (vop_t *)cd9660_update },	/* update */
1103 /* XXX: vop_getpages */
1104 /* XXX: vop_putpages */
1105 	{ &vop_bwrite_desc, (vop_t *)vn_bwrite },
1106 	{ NULL, NULL }
1107 };
1108 static struct vnodeopv_desc cd9660_specop_opv_desc =
1109 	{ &cd9660_specop_p, cd9660_specop_entries };
1110 VNODEOP_SET(cd9660_specop_opv_desc);
1111 
1112 vop_t **cd9660_fifoop_p;
1113 struct vnodeopv_entry_desc cd9660_fifoop_entries[] = {
1114 	{ &vop_default_desc, (vop_t *)vn_default_error },
1115 	{ &vop_lookup_desc, (vop_t *)fifo_lookup },	/* lookup */
1116 /* XXX: vop_cachedlookup */
1117 	{ &vop_create_desc, (vop_t *)fifo_create },	/* create */
1118 /* XXX: vop_whiteout */
1119 	{ &vop_mknod_desc, (vop_t *)fifo_mknod },	/* mknod */
1120 	{ &vop_open_desc, (vop_t *)fifo_open },		/* open */
1121 	{ &vop_close_desc, (vop_t *)fifo_close },	/* close */
1122 	{ &vop_access_desc, (vop_t *)cd9660_access },	/* access */
1123 	{ &vop_getattr_desc, (vop_t *)cd9660_getattr },	/* getattr */
1124 	{ &vop_setattr_desc, (vop_t *)cd9660_setattr },	/* setattr */
1125 	{ &vop_read_desc, (vop_t *)fifo_read },		/* read */
1126 	{ &vop_write_desc, (vop_t *)fifo_write },	/* write */
1127 	{ &vop_lease_desc, (vop_t *)fifo_lease_check },	/* lease */
1128 	{ &vop_ioctl_desc, (vop_t *)fifo_ioctl },	/* ioctl */
1129 	{ &vop_poll_desc, (vop_t *)fifo_poll },		/* poll */
1130 	{ &vop_revoke_desc, (vop_t *)fifo_revoke },	/* revoke */
1131 	{ &vop_mmap_desc, (vop_t *)fifo_mmap },		/* mmap */
1132 	{ &vop_fsync_desc, (vop_t *)fifo_fsync },	/* fsync */
1133 	{ &vop_seek_desc, (vop_t *)fifo_seek },		/* seek */
1134 	{ &vop_remove_desc, (vop_t *)fifo_remove },	/* remove */
1135 	{ &vop_link_desc, (vop_t *)fifo_link }	,	/* link */
1136 	{ &vop_rename_desc, (vop_t *)fifo_rename },	/* rename */
1137 	{ &vop_mkdir_desc, (vop_t *)fifo_mkdir },	/* mkdir */
1138 	{ &vop_rmdir_desc, (vop_t *)fifo_rmdir },	/* rmdir */
1139 	{ &vop_symlink_desc, (vop_t *)fifo_symlink },	/* symlink */
1140 	{ &vop_readdir_desc, (vop_t *)fifo_readdir },	/* readdir */
1141 	{ &vop_readlink_desc, (vop_t *)fifo_readlink },	/* readlink */
1142 	{ &vop_abortop_desc, (vop_t *)fifo_abortop },	/* abortop */
1143 	{ &vop_inactive_desc, (vop_t *)cd9660_inactive },/* inactive */
1144 	{ &vop_reclaim_desc, (vop_t *)cd9660_reclaim },	/* reclaim */
1145 	{ &vop_lock_desc, (vop_t *)cd9660_lock },	/* lock */
1146 	{ &vop_unlock_desc, (vop_t *)cd9660_unlock },	/* unlock */
1147 	{ &vop_bmap_desc, (vop_t *)fifo_bmap },		/* bmap */
1148 	{ &vop_strategy_desc, (vop_t *)fifo_strategy },	/* strategy */
1149 	{ &vop_print_desc, (vop_t *)cd9660_print },	/* print */
1150 	{ &vop_islocked_desc, (vop_t *)cd9660_islocked },/* islocked */
1151 	{ &vop_pathconf_desc, (vop_t *)fifo_pathconf },	/* pathconf */
1152 	{ &vop_advlock_desc, (vop_t *)fifo_advlock },	/* advlock */
1153 	{ &vop_blkatoff_desc, (vop_t *)fifo_blkatoff },	/* blkatoff */
1154 	{ &vop_valloc_desc, (vop_t *)fifo_valloc },	/* valloc */
1155 /* XXX: vop_reallocpages */
1156 	{ &vop_vfree_desc, (vop_t *)fifo_vfree },	/* vfree */
1157 	{ &vop_truncate_desc, (vop_t *)fifo_truncate },	/* truncate */
1158 	{ &vop_update_desc, (vop_t *)cd9660_update },	/* update */
1159 /* XXX: vop_getpages */
1160 /* XXX: vop_putpages */
1161 	{ &vop_bwrite_desc, (vop_t *)vn_bwrite },
1162 	{ NULL, NULL }
1163 };
1164 static struct vnodeopv_desc cd9660_fifoop_opv_desc =
1165 	{ &cd9660_fifoop_p, cd9660_fifoop_entries };
1166 
1167 VNODEOP_SET(cd9660_fifoop_opv_desc);
1168