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  * %sccs.include.redist.c%
11  *
12  *	@(#)cd9660_vnops.c	8.2 (Berkeley) 01/22/94
13  */
14 
15 #include <sys/param.h>
16 #include <sys/systm.h>
17 #include <sys/namei.h>
18 #include <sys/resourcevar.h>
19 #include <sys/kernel.h>
20 #include <sys/file.h>
21 #include <sys/stat.h>
22 #include <sys/buf.h>
23 #include <sys/proc.h>
24 #include <sys/conf.h>
25 #include <sys/mount.h>
26 #include <sys/vnode.h>
27 #include <miscfs/specfs/specdev.h>
28 #include <miscfs/fifofs/fifo.h>
29 #include <sys/malloc.h>
30 #include <sys/dir.h>
31 
32 #include <isofs/cd9660/iso.h>
33 #include <isofs/cd9660/isofs_node.h>
34 #include <isofs/cd9660/iso_rrip.h>
35 
36 #if 0
37 /*
38  * Mknod vnode call
39  *  Actually remap the device number
40  */
41 isofs_mknod(ndp, vap, cred, p)
42 	struct nameidata *ndp;
43 	struct ucred *cred;
44 	struct vattr *vap;
45 	struct proc *p;
46 {
47 #ifndef	ISODEVMAP
48 	free(ndp->ni_pnbuf, M_NAMEI);
49 	vput(ndp->ni_dvp);
50 	vput(ndp->ni_vp);
51 	return EINVAL;
52 #else
53 	register struct vnode *vp;
54 	struct iso_node *ip;
55 	struct iso_dnode *dp;
56 	int error;
57 
58 	vp = ndp->ni_vp;
59 	ip = VTOI(vp);
60 
61 	if (ip->i_mnt->iso_ftype != ISO_FTYPE_RRIP
62 	    || vap->va_type != vp->v_type
63 	    || (vap->va_type != VCHR && vap->va_type != VBLK)) {
64 		free(ndp->ni_pnbuf, M_NAMEI);
65 		vput(ndp->ni_dvp);
66 		vput(ndp->ni_vp);
67 		return EINVAL;
68 	}
69 
70 	dp = iso_dmap(ip->i_dev,ip->i_number,1);
71 	if (ip->inode.iso_rdev == vap->va_rdev || vap->va_rdev == VNOVAL) {
72 		/* same as the unmapped one, delete the mapping */
73 		remque(dp);
74 		FREE(dp,M_CACHE);
75 	} else
76 		/* enter new mapping */
77 		dp->d_dev = vap->va_rdev;
78 
79 	/*
80 	 * Remove inode so that it will be reloaded by iget and
81 	 * checked to see if it is an alias of an existing entry
82 	 * in the inode cache.
83 	 */
84 	vput(vp);
85 	vp->v_type = VNON;
86 	vgone(vp);
87 	return (0);
88 #endif
89 }
90 #endif
91 
92 /*
93  * Open called.
94  *
95  * Nothing to do.
96  */
97 /* ARGSUSED */
98 int
99 isofs_open(ap)
100 	struct vop_open_args /* {
101 		struct vnode *a_vp;
102 		int  a_mode;
103 		struct ucred *a_cred;
104 		struct proc *a_p;
105 	} */ *ap;
106 {
107 	return (0);
108 }
109 
110 /*
111  * Close called
112  *
113  * Update the times on the inode on writeable file systems.
114  */
115 /* ARGSUSED */
116 int
117 isofs_close(ap)
118 	struct vop_close_args /* {
119 		struct vnode *a_vp;
120 		int  a_fflag;
121 		struct ucred *a_cred;
122 		struct proc *a_p;
123 	} */ *ap;
124 {
125 	return (0);
126 }
127 
128 /*
129  * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC.
130  * The mode is shifted to select the owner/group/other fields. The
131  * super user is granted all permissions.
132  */
133 /* ARGSUSED */
134 isofs_access(ap)
135 	struct vop_access_args /* {
136 		struct vnode *a_vp;
137 		int  a_mode;
138 		struct ucred *a_cred;
139 		struct proc *a_p;
140 	} */ *ap;
141 {
142 	return (0);
143 }
144 
145 isofs_getattr(ap)
146 	struct vop_getattr_args /* {
147 		struct vnode *a_vp;
148 		struct vattr *a_vap;
149 		struct ucred *a_cred;
150 		struct proc *a_p;
151 	} */ *ap;
152 
153 {
154 	struct vnode *vp = ap->a_vp;
155 	register struct vattr *vap = ap->a_vap;
156 	register struct iso_node *ip = VTOI(vp);
157 	int i;
158 
159 	vap->va_fsid	= ip->i_dev;
160 	vap->va_fileid	= ip->i_number;
161 
162 	vap->va_mode	= ip->inode.iso_mode;
163 	vap->va_nlink	= ip->inode.iso_links;
164 	vap->va_uid	= ip->inode.iso_uid;
165 	vap->va_gid	= ip->inode.iso_gid;
166 	vap->va_atime	= ip->inode.iso_atime;
167 	vap->va_mtime	= ip->inode.iso_mtime;
168 	vap->va_ctime	= ip->inode.iso_ctime;
169 	vap->va_rdev	= ip->inode.iso_rdev;
170 
171 	vap->va_size	= (u_quad_t) ip->i_size;
172 	vap->va_flags	= 0;
173 	vap->va_gen = 1;
174 	vap->va_blocksize = ip->i_mnt->logical_block_size;
175 	vap->va_bytes	= (u_quad_t) ip->i_size;
176 	vap->va_type	= vp->v_type;
177 	return (0);
178 }
179 
180 #if ISO_DEFAULT_BLOCK_SIZE >= NBPG
181 #ifdef DEBUG
182 extern int doclusterread;
183 #else
184 #define doclusterread 1
185 #endif
186 #else
187 /* XXX until cluster routines can handle block sizes less than one page */
188 #define doclusterread 0
189 #endif
190 
191 /*
192  * Vnode op for reading.
193  */
194 isofs_read(ap)
195 	struct vop_read_args /* {
196 		struct vnode *a_vp;
197 		struct uio *a_uio;
198 		int a_ioflag;
199 		struct ucred *a_cred;
200 	} */ *ap;
201 {
202 	struct vnode *vp = ap->a_vp;
203 	register struct uio *uio = ap->a_uio;
204 	register struct iso_node *ip = VTOI(vp);
205 	register struct iso_mnt *imp;
206 	struct buf *bp;
207 	daddr_t lbn, bn, rablock;
208 	off_t diff;
209 	int rasize, error = 0;
210 	long size, n, on;
211 
212 	if (uio->uio_resid == 0)
213 		return (0);
214 	if (uio->uio_offset < 0)
215 		return (EINVAL);
216 	ip->i_flag |= IACC;
217 	imp = ip->i_mnt;
218 	do {
219 		lbn = iso_lblkno(imp, uio->uio_offset);
220 		on = iso_blkoff(imp, uio->uio_offset);
221 		n = min((unsigned)(imp->logical_block_size - on),
222 			uio->uio_resid);
223 		diff = (off_t)ip->i_size - uio->uio_offset;
224 		if (diff <= 0)
225 			return (0);
226 		if (diff < n)
227 			n = diff;
228 		size = iso_blksize(imp, ip, lbn);
229 		rablock = lbn + 1;
230 		if (doclusterread) {
231 			if (iso_lblktosize(imp, rablock) <= ip->i_size)
232 				error = cluster_read(vp, (off_t)ip->i_size,
233 						     lbn, size, NOCRED, &bp);
234 			else
235 				error = bread(vp, lbn, size, NOCRED, &bp);
236 		} else {
237 			if (vp->v_lastr + 1 == lbn &&
238 			    iso_lblktosize(imp, rablock) < ip->i_size) {
239 				rasize = iso_blksize(imp, ip, rablock);
240 				error = breadn(vp, lbn, size, &rablock,
241 					       &rasize, 1, NOCRED, &bp);
242 			} else
243 				error = bread(vp, lbn, size, NOCRED, &bp);
244 		}
245 		vp->v_lastr = lbn;
246 		n = min(n, size - bp->b_resid);
247 		if (error) {
248 			brelse(bp);
249 			return (error);
250 		}
251 
252 		error = uiomove(bp->b_un.b_addr + on, (int)n, uio);
253 		if (n + on == imp->logical_block_size ||
254 		    uio->uio_offset == (off_t)ip->i_size)
255 			bp->b_flags |= B_AGE;
256 		brelse(bp);
257 	} while (error == 0 && uio->uio_resid > 0 && n != 0);
258 	return (error);
259 }
260 
261 /* ARGSUSED */
262 int
263 isofs_ioctl(ap)
264 	struct vop_ioctl_args /* {
265 		struct vnode *a_vp;
266 		int  a_command;
267 		caddr_t  a_data;
268 		int  a_fflag;
269 		struct ucred *a_cred;
270 		struct proc *a_p;
271 	} */ *ap;
272 {
273 	printf("You did ioctl for isofs !!\n");
274 	return (ENOTTY);
275 }
276 
277 /* ARGSUSED */
278 int
279 isofs_select(ap)
280 	struct vop_select_args /* {
281 		struct vnode *a_vp;
282 		int  a_which;
283 		int  a_fflags;
284 		struct ucred *a_cred;
285 		struct proc *a_p;
286 	} */ *ap;
287 {
288 
289 	/*
290 	 * We should really check to see if I/O is possible.
291 	 */
292 	return (1);
293 }
294 
295 /*
296  * Mmap a file
297  *
298  * NB Currently unsupported.
299  */
300 /* ARGSUSED */
301 int
302 isofs_mmap(ap)
303 	struct vop_mmap_args /* {
304 		struct vnode *a_vp;
305 		int  a_fflags;
306 		struct ucred *a_cred;
307 		struct proc *a_p;
308 	} */ *ap;
309 {
310 
311 	return (EINVAL);
312 }
313 
314 /*
315  * Seek on a file
316  *
317  * Nothing to do, so just return.
318  */
319 /* ARGSUSED */
320 int
321 isofs_seek(ap)
322 	struct vop_seek_args /* {
323 		struct vnode *a_vp;
324 		off_t  a_oldoff;
325 		off_t  a_newoff;
326 		struct ucred *a_cred;
327 	} */ *ap;
328 {
329 
330 	return (0);
331 }
332 
333 /*
334  * Structure for reading directories
335  */
336 struct isoreaddir {
337 	struct dirent saveent;
338 	struct dirent assocent;
339 	struct dirent current;
340 	off_t saveoff;
341 	off_t assocoff;
342 	off_t curroff;
343 	struct uio *uio;
344 	off_t uio_off;
345 	u_int *cookiep;
346 	int ncookies;
347 	int eof;
348 };
349 
350 static int
351 iso_uiodir(idp,dp,off)
352 	struct isoreaddir *idp;
353 	struct dirent *dp;
354 	off_t off;
355 {
356 	int error;
357 
358 	dp->d_name[dp->d_namlen] = 0;
359 	dp->d_reclen = DIRSIZ(dp);
360 
361 	if (idp->uio->uio_resid < dp->d_reclen) {
362 		idp->eof = 0;
363 		return -1;
364 	}
365 
366 	if (idp->cookiep) {
367 		if (idp->ncookies <= 0) {
368 			idp->eof = 0;
369 			return -1;
370 		}
371 
372 		*idp->cookiep++ = off;
373 		--idp->ncookies;
374 	}
375 
376 	if (error = uiomove(dp,dp->d_reclen,idp->uio))
377 		return error;
378 	idp->uio_off = off;
379 	return 0;
380 }
381 
382 static int
383 iso_shipdir(idp)
384 	struct isoreaddir *idp;
385 {
386 	struct dirent *dp;
387 	int cl, sl, assoc;
388 	int error;
389 	char *cname, *sname;
390 
391 	cl = idp->current.d_namlen;
392 	cname = idp->current.d_name;
393 	if (assoc = cl > 1 && *cname == ASSOCCHAR) {
394 		cl--;
395 		cname++;
396 	}
397 
398 	dp = &idp->saveent;
399 	sname = dp->d_name;
400 	if (!(sl = dp->d_namlen)) {
401 		dp = &idp->assocent;
402 		sname = dp->d_name + 1;
403 		sl = dp->d_namlen - 1;
404 	}
405 	if (sl > 0) {
406 		if (sl != cl
407 		    || bcmp(sname,cname,sl)) {
408 			if (idp->assocent.d_namlen) {
409 				if (error = iso_uiodir(idp,&idp->assocent,idp->assocoff))
410 					return error;
411 				idp->assocent.d_namlen = 0;
412 			}
413 			if (idp->saveent.d_namlen) {
414 				if (error = iso_uiodir(idp,&idp->saveent,idp->saveoff))
415 					return error;
416 				idp->saveent.d_namlen = 0;
417 			}
418 		}
419 	}
420 	idp->current.d_reclen = DIRSIZ(&idp->current);
421 	if (assoc) {
422 		idp->assocoff = idp->curroff;
423 		bcopy(&idp->current,&idp->assocent,idp->current.d_reclen);
424 	} else {
425 		idp->saveoff = idp->curroff;
426 		bcopy(&idp->current,&idp->saveent,idp->current.d_reclen);
427 	}
428 	return 0;
429 }
430 
431 /*
432  * Vnode op for readdir
433  * XXX make sure everything still works now that eofflagp and cookiep
434  * are no longer args.
435  */
436 int
437 isofs_readdir(ap)
438 	struct vop_readdir_args /* {
439 		struct vnode *a_vp;
440 		struct uio *a_uio;
441 		struct ucred *a_cred;
442 	} */ *ap;
443 {
444 	register struct uio *uio = ap->a_uio;
445 	struct isoreaddir *idp;
446 	int entryoffsetinblock;
447 	int error = 0;
448 	int endsearch;
449 	struct iso_directory_record *ep;
450 	u_short elen;
451 	int reclen;
452 	struct iso_mnt *imp;
453 	struct iso_node *ip;
454 	struct buf *bp = NULL;
455 
456 	ip = VTOI(ap->a_vp);
457 	imp = ip->i_mnt;
458 
459 	MALLOC(idp,struct isoreaddir *,sizeof(*idp),M_TEMP,M_WAITOK);
460 	idp->saveent.d_namlen = 0;
461 	idp->assocent.d_namlen = 0;
462 	idp->uio = uio;
463 #if 0
464 	idp->cookiep = cookies;
465 	idp->ncookies = ncookies;
466 	idp->eof = 1;
467 #else
468 	idp->cookiep = 0;
469 #endif
470 	idp->curroff = uio->uio_offset;
471 
472 	entryoffsetinblock = iso_blkoff(imp, idp->curroff);
473 	if (entryoffsetinblock != 0) {
474 		if (error = iso_blkatoff(ip, idp->curroff, &bp)) {
475 			FREE(idp,M_TEMP);
476 			return (error);
477 		}
478 	}
479 
480 	endsearch = ip->i_size;
481 
482 	while (idp->curroff < endsearch) {
483 		/*
484 		 * If offset is on a block boundary,
485 		 * read the next directory block.
486 		 * Release previous if it exists.
487 		 */
488 
489 		if (iso_blkoff(imp, idp->curroff) == 0) {
490 			if (bp != NULL)
491 				brelse(bp);
492 			if (error = iso_blkatoff(ip, idp->curroff, &bp))
493 				break;
494 			entryoffsetinblock = 0;
495 		}
496 		/*
497 		 * Get pointer to next entry.
498 		 */
499 
500 		ep = (struct iso_directory_record *)
501 			(bp->b_un.b_addr + entryoffsetinblock);
502 
503 		reclen = isonum_711 (ep->length);
504 		if (reclen == 0) {
505 			/* skip to next block, if any */
506 			idp->curroff = roundup (idp->curroff,
507 						imp->logical_block_size);
508 			continue;
509 		}
510 
511 		if (reclen < ISO_DIRECTORY_RECORD_SIZE) {
512 			error = EINVAL;
513 			/* illegal entry, stop */
514 			break;
515 		}
516 
517 		if (entryoffsetinblock + reclen > imp->logical_block_size) {
518 			error = EINVAL;
519 			/* illegal directory, so stop looking */
520 			break;
521 		}
522 
523 		idp->current.d_namlen = isonum_711 (ep->name_len);
524 		if (isonum_711(ep->flags)&2)
525 			isodirino(&idp->current.d_fileno,ep,imp);
526 		else
527 			idp->current.d_fileno = dbtob(bp->b_blkno) +
528 				idp->curroff;
529 
530 		if (reclen < ISO_DIRECTORY_RECORD_SIZE + idp->current.d_namlen) {
531 			error = EINVAL;
532 			/* illegal entry, stop */
533 			break;
534 		}
535 
536 		idp->curroff += reclen;
537 		/*
538 		 *
539 		 */
540 		switch (imp->iso_ftype) {
541 		case ISO_FTYPE_RRIP:
542 			isofs_rrip_getname(ep,idp->current.d_name,
543 					   (u_short *)&idp->current.d_namlen,
544 					   &idp->current.d_fileno,imp);
545 			if (idp->current.d_namlen)
546 				error = iso_uiodir(idp,&idp->current,idp->curroff);
547 			break;
548 		default:	/* ISO_FTYPE_DEFAULT || ISO_FTYPE_9660 */
549 			strcpy(idp->current.d_name,"..");
550 			switch (ep->name[0]) {
551 			case 0:
552 				idp->current.d_namlen = 1;
553 				error = iso_uiodir(idp,&idp->current,idp->curroff);
554 				break;
555 			case 1:
556 				idp->current.d_namlen = 2;
557 				error = iso_uiodir(idp,&idp->current,idp->curroff);
558 				break;
559 			default:
560 				isofntrans(ep->name,idp->current.d_namlen,
561 					   idp->current.d_name, &elen,
562 					   imp->iso_ftype == ISO_FTYPE_9660,
563 					   isonum_711(ep->flags)&4);
564 				idp->current.d_namlen = (u_char)elen;
565 				if (imp->iso_ftype == ISO_FTYPE_DEFAULT)
566 					error = iso_shipdir(idp);
567 				else
568 					error = iso_uiodir(idp,&idp->current,idp->curroff);
569 				break;
570 			}
571 		}
572 		if (error)
573 			break;
574 
575 		entryoffsetinblock += reclen;
576 	}
577 
578 	if (!error && imp->iso_ftype == ISO_FTYPE_DEFAULT) {
579 		idp->current.d_namlen = 0;
580 		error = iso_shipdir(idp);
581 	}
582 	if (error < 0)
583 		error = 0;
584 
585 	if (bp)
586 		brelse (bp);
587 
588 	uio->uio_offset = idp->uio_off;
589 #if 0
590 	*eofflagp = idp->eof;
591 #endif
592 
593 	FREE(idp,M_TEMP);
594 
595 	return (error);
596 }
597 
598 /*
599  * Return target name of a symbolic link
600  * Shouldn't we get the parent vnode and read the data from there?
601  * This could eventually result in deadlocks in isofs_lookup.
602  * But otherwise the block read here is in the block buffer two times.
603  */
604 typedef struct iso_directory_record ISODIR;
605 typedef struct iso_node             ISONODE;
606 typedef struct iso_mnt              ISOMNT;
607 int
608 isofs_readlink(ap)
609 	struct vop_readlink_args /* {
610 		struct vnode *a_vp;
611 		struct uio *a_uio;
612 		struct ucred *a_cred;
613 	} */ *ap;
614 {
615 	ISONODE	*ip;
616 	ISODIR	*dirp;
617 	ISOMNT	*imp;
618 	struct	buf *bp;
619 	u_short	symlen;
620 	int	error;
621 	char	*symname;
622 	ino_t	ino;
623 
624 	ip  = VTOI(ap->a_vp);
625 	imp = ip->i_mnt;
626 
627 	if (imp->iso_ftype != ISO_FTYPE_RRIP)
628 		return EINVAL;
629 
630 	/*
631 	 * Get parents directory record block that this inode included.
632 	 */
633 	error = bread(imp->im_devvp,
634 		      (daddr_t)(ip->i_number / DEV_BSIZE),
635 		      imp->logical_block_size,
636 		      NOCRED,
637 		      &bp);
638 	if (error) {
639 		brelse(bp);
640 		return EINVAL;
641 	}
642 
643 	/*
644 	 * Setup the directory pointer for this inode
645 	 */
646 	dirp = (ISODIR *)(bp->b_un.b_addr + (ip->i_number & imp->im_bmask));
647 #ifdef DEBUG
648 	printf("lbn=%d,off=%d,bsize=%d,DEV_BSIZE=%d, dirp= %08x, b_addr=%08x, offset=%08x(%08x)\n",
649 	       (daddr_t)(ip->i_number >> imp->im_bshift),
650 	       ip->i_number & imp->im_bmask,
651 	       imp->logical_block_size,
652 	       DEV_BSIZE,
653 	       dirp,
654 	       bp->b_un.b_addr,
655 	       ip->i_number,
656 	       ip->i_number & imp->im_bmask );
657 #endif
658 
659 	/*
660 	 * Just make sure, we have a right one....
661 	 *   1: Check not cross boundary on block
662 	 */
663 	if ((ip->i_number & imp->im_bmask) + isonum_711(dirp->length)
664 	    > imp->logical_block_size) {
665 		brelse(bp);
666 		return EINVAL;
667 	}
668 
669 	/*
670 	 * Now get a buffer
671 	 * Abuse a namei buffer for now.
672 	 */
673 	MALLOC(symname,char *,MAXPATHLEN,M_NAMEI,M_WAITOK);
674 
675 	/*
676 	 * Ok, we just gathering a symbolic name in SL record.
677 	 */
678 	if (isofs_rrip_getsymname(dirp,symname,&symlen,imp) == 0) {
679 		FREE(symname,M_NAMEI);
680 		brelse(bp);
681 		return EINVAL;
682 	}
683 	/*
684 	 * Don't forget before you leave from home ;-)
685 	 */
686 	brelse(bp);
687 
688 	/*
689 	 * return with the symbolic name to caller's.
690 	 */
691 	error = uiomove(symname,symlen,ap->a_uio);
692 
693 	FREE(symname,M_NAMEI);
694 
695 	return error;
696 }
697 
698 /*
699  * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually
700  * done. If a buffer has been saved in anticipation of a CREATE, delete it.
701  */
702 int
703 isofs_abortop(ap)
704 	struct vop_abortop_args /* {
705 		struct vnode *a_dvp;
706 		struct componentname *a_cnp;
707 	} */ *ap;
708 {
709 	if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF)
710 		FREE(ap->a_cnp->cn_pnbuf, M_NAMEI);
711 	return 0;
712 }
713 
714 /*
715  * Lock an inode.
716  */
717 int
718 isofs_lock(ap)
719 	struct vop_lock_args /* {
720 		struct vnode *a_vp;
721 	} */ *ap;
722 {
723 	register struct iso_node *ip = VTOI(ap->a_vp);
724 
725 	ISO_ILOCK(ip);
726 	return 0;
727 }
728 
729 /*
730  * Unlock an inode.
731  */
732 int
733 isofs_unlock(ap)
734 	struct vop_unlock_args /* {
735 		struct vnode *a_vp;
736 	} */ *ap;
737 {
738 	register struct iso_node *ip = VTOI(ap->a_vp);
739 
740 	if (!(ip->i_flag & ILOCKED))
741 		panic("isofs_unlock NOT LOCKED");
742 	ISO_IUNLOCK(ip);
743 	return 0;
744 }
745 
746 /*
747  * Check for a locked inode.
748  */
749 int
750 isofs_islocked(ap)
751 	struct vop_islocked_args /* {
752 		struct vnode *a_vp;
753 	} */ *ap;
754 {
755 
756 	if (VTOI(ap->a_vp)->i_flag & ILOCKED)
757 		return 1;
758 	return 0;
759 }
760 
761 /*
762  * Calculate the logical to physical mapping if not done already,
763  * then call the device strategy routine.
764  */
765 int
766 isofs_strategy(ap)
767 	struct vop_strategy_args /* {
768 		struct buf *a_bp;
769 	} */ *ap;
770 {
771 	register struct buf *bp = ap->a_bp;
772 	register struct vnode *vp = bp->b_vp;
773 	register struct iso_node *ip;
774 	int error;
775 
776 	ip = VTOI(vp);
777 	if (vp->v_type == VBLK || vp->v_type == VCHR)
778 		panic("isofs_strategy: spec");
779 	if (bp->b_blkno == bp->b_lblkno) {
780 		if (error =
781 		    VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL)) {
782 			bp->b_error = error;
783 			bp->b_flags |= B_ERROR;
784 			biodone(bp);
785 			return (error);
786 		}
787 		if ((long)bp->b_blkno == -1)
788 			clrbuf(bp);
789 	}
790 	if ((long)bp->b_blkno == -1) {
791 		biodone(bp);
792 		return (0);
793 	}
794 	vp = ip->i_devvp;
795 	bp->b_dev = vp->v_rdev;
796 	VOCALL (vp->v_op, VOFFSET(vop_strategy), ap);
797 	return (0);
798 }
799 
800 /*
801  * Print out the contents of an inode.
802  */
803 int
804 isofs_print(ap)
805 	struct vop_print_args /* {
806 		struct vnode *a_vp;
807 	} */ *ap;
808 {
809 	printf("tag VT_ISOFS, isofs vnode\n");
810 	return 0;
811 }
812 
813 /*
814  * Unsupported operation
815  */
816 int
817 isofs_enotsupp()
818 {
819 
820 	return (EOPNOTSUPP);
821 }
822 
823 /*
824  * Global vfs data structures for isofs
825  */
826 #define isofs_create ((int (*) __P((struct  vop_create_args *)))isofs_enotsupp)
827 #define isofs_mknod ((int (*) __P((struct  vop_mknod_args *)))isofs_enotsupp)
828 #define isofs_setattr \
829 	((int (*) __P((struct  vop_setattr_args *)))isofs_enotsupp)
830 #define isofs_write ((int (*) __P((struct  vop_write_args *)))isofs_enotsupp)
831 #define isofs_fsync ((int (*) __P((struct  vop_fsync_args *)))nullop)
832 #define isofs_remove ((int (*) __P((struct  vop_remove_args *)))isofs_enotsupp)
833 #define isofs_link ((int (*) __P((struct  vop_link_args *)))isofs_enotsupp)
834 #define isofs_rename ((int (*) __P((struct  vop_rename_args *)))isofs_enotsupp)
835 #define isofs_mkdir ((int (*) __P((struct  vop_mkdir_args *)))isofs_enotsupp)
836 #define isofs_rmdir ((int (*) __P((struct  vop_rmdir_args *)))isofs_enotsupp)
837 #define isofs_symlink \
838 	((int (*) __P((struct vop_symlink_args *)))isofs_enotsupp)
839 #define isofs_pathconf \
840 	((int (*) __P((struct vop_pathconf_args *)))isofs_enotsupp)
841 #define isofs_advlock \
842 	((int (*) __P((struct vop_advlock_args *)))isofs_enotsupp)
843 #define isofs_blkatoff \
844 	((int (*) __P((struct  vop_blkatoff_args *)))isofs_enotsupp)
845 #define isofs_valloc ((int(*) __P(( \
846 		struct vnode *pvp, \
847 		int mode, \
848 		struct ucred *cred, \
849 		struct vnode **vpp))) isofs_enotsupp)
850 #define isofs_vfree ((int (*) __P((struct  vop_vfree_args *)))isofs_enotsupp)
851 #define isofs_truncate \
852 	((int (*) __P((struct  vop_truncate_args *)))isofs_enotsupp)
853 #define isofs_update ((int (*) __P((struct  vop_update_args *)))isofs_enotsupp)
854 #define isofs_bwrite ((int (*) __P((struct  vop_bwrite_args *)))isofs_enotsupp)
855 
856 /*
857  * Global vfs data structures for nfs
858  */
859 int (**isofs_vnodeop_p)();
860 struct vnodeopv_entry_desc isofs_vnodeop_entries[] = {
861 	{ &vop_default_desc, vn_default_error },
862 	{ &vop_lookup_desc, isofs_lookup },	/* lookup */
863 	{ &vop_create_desc, isofs_create },	/* create */
864 	{ &vop_mknod_desc, isofs_mknod },	/* mknod */
865 	{ &vop_open_desc, isofs_open },		/* open */
866 	{ &vop_close_desc, isofs_close },	/* close */
867 	{ &vop_access_desc, isofs_access },	/* access */
868 	{ &vop_getattr_desc, isofs_getattr },	/* getattr */
869 	{ &vop_setattr_desc, isofs_setattr },	/* setattr */
870 	{ &vop_read_desc, isofs_read },		/* read */
871 	{ &vop_write_desc, isofs_write },	/* write */
872 	{ &vop_ioctl_desc, isofs_ioctl },	/* ioctl */
873 	{ &vop_select_desc, isofs_select },	/* select */
874 	{ &vop_mmap_desc, isofs_mmap },		/* mmap */
875 	{ &vop_fsync_desc, isofs_fsync },	/* fsync */
876 	{ &vop_seek_desc, isofs_seek },		/* seek */
877 	{ &vop_remove_desc, isofs_remove },	/* remove */
878 	{ &vop_link_desc, isofs_link },		/* link */
879 	{ &vop_rename_desc, isofs_rename },	/* rename */
880 	{ &vop_mkdir_desc, isofs_mkdir },	/* mkdir */
881 	{ &vop_rmdir_desc, isofs_rmdir },	/* rmdir */
882 	{ &vop_symlink_desc, isofs_symlink },	/* symlink */
883 	{ &vop_readdir_desc, isofs_readdir },	/* readdir */
884 	{ &vop_readlink_desc, isofs_readlink },	/* readlink */
885 	{ &vop_abortop_desc, isofs_abortop },	/* abortop */
886 	{ &vop_inactive_desc, isofs_inactive },	/* inactive */
887 	{ &vop_reclaim_desc, isofs_reclaim },	/* reclaim */
888 	{ &vop_lock_desc, isofs_lock },		/* lock */
889 	{ &vop_unlock_desc, isofs_unlock },	/* unlock */
890 	{ &vop_bmap_desc, isofs_bmap },		/* bmap */
891 	{ &vop_strategy_desc, isofs_strategy },	/* strategy */
892 	{ &vop_print_desc, isofs_print },	/* print */
893 	{ &vop_islocked_desc, isofs_islocked },	/* islocked */
894 	{ &vop_pathconf_desc, isofs_pathconf },	/* pathconf */
895 	{ &vop_advlock_desc, isofs_advlock },	/* advlock */
896 	{ &vop_blkatoff_desc, isofs_blkatoff },	/* blkatoff */
897 	{ &vop_valloc_desc, isofs_valloc },	/* valloc */
898 	{ &vop_vfree_desc, isofs_vfree },	/* vfree */
899 	{ &vop_truncate_desc, isofs_truncate },	/* truncate */
900 	{ &vop_update_desc, isofs_update },	/* update */
901 	{ &vop_bwrite_desc, vn_bwrite },
902 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
903 };
904 struct vnodeopv_desc isofs_vnodeop_opv_desc =
905 	{ &isofs_vnodeop_p, isofs_vnodeop_entries };
906 
907 /*
908  * Special device vnode ops
909  */
910 int (**isofs_specop_p)();
911 struct vnodeopv_entry_desc isofs_specop_entries[] = {
912 	{ &vop_default_desc, vn_default_error },
913 	{ &vop_lookup_desc, spec_lookup },	/* lookup */
914 	{ &vop_create_desc, isofs_create },	/* create */
915 	{ &vop_mknod_desc, isofs_mknod },	/* mknod */
916 	{ &vop_open_desc, spec_open },		/* open */
917 	{ &vop_close_desc, spec_close },	/* close */
918 	{ &vop_access_desc, isofs_access },	/* access */
919 	{ &vop_getattr_desc, isofs_getattr },	/* getattr */
920 	{ &vop_setattr_desc, isofs_setattr },	/* setattr */
921 	{ &vop_read_desc, spec_read },		/* read */
922 	{ &vop_write_desc, spec_write },	/* write */
923 	{ &vop_ioctl_desc, spec_ioctl },	/* ioctl */
924 	{ &vop_select_desc, spec_select },	/* select */
925 	{ &vop_mmap_desc, spec_mmap },		/* mmap */
926 	{ &vop_fsync_desc, spec_fsync },	/* fsync */
927 	{ &vop_seek_desc, spec_seek },		/* seek */
928 	{ &vop_remove_desc, isofs_remove },	/* remove */
929 	{ &vop_link_desc, isofs_link },		/* link */
930 	{ &vop_rename_desc, isofs_rename },	/* rename */
931 	{ &vop_mkdir_desc, isofs_mkdir },	/* mkdir */
932 	{ &vop_rmdir_desc, isofs_rmdir },	/* rmdir */
933 	{ &vop_symlink_desc, isofs_symlink },	/* symlink */
934 	{ &vop_readdir_desc, spec_readdir },	/* readdir */
935 	{ &vop_readlink_desc, spec_readlink },	/* readlink */
936 	{ &vop_abortop_desc, spec_abortop },	/* abortop */
937 	{ &vop_inactive_desc, isofs_inactive },	/* inactive */
938 	{ &vop_reclaim_desc, isofs_reclaim },	/* reclaim */
939 	{ &vop_lock_desc, isofs_lock },		/* lock */
940 	{ &vop_unlock_desc, isofs_unlock },	/* unlock */
941 	{ &vop_bmap_desc, spec_bmap },		/* bmap */
942 		/* XXX strategy: panics, should be notsupp instead? */
943 	{ &vop_strategy_desc, isofs_strategy },	/* strategy */
944 	{ &vop_print_desc, isofs_print },	/* print */
945 	{ &vop_islocked_desc, isofs_islocked },	/* islocked */
946 	{ &vop_pathconf_desc, spec_pathconf },	/* pathconf */
947 	{ &vop_advlock_desc, spec_advlock },	/* advlock */
948 	{ &vop_blkatoff_desc, spec_blkatoff },	/* blkatoff */
949 	{ &vop_valloc_desc, spec_valloc },	/* valloc */
950 	{ &vop_vfree_desc, spec_vfree },	/* vfree */
951 	{ &vop_truncate_desc, spec_truncate },	/* truncate */
952 	{ &vop_update_desc, isofs_update },	/* update */
953 	{ &vop_bwrite_desc, vn_bwrite },
954 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
955 };
956 struct vnodeopv_desc isofs_specop_opv_desc =
957 	{ &isofs_specop_p, isofs_specop_entries };
958 
959 #ifdef FIFO
960 int (**isofs_fifoop_p)();
961 struct vnodeopv_entry_desc isofs_fifoop_entries[] = {
962 	{ &vop_default_desc, vn_default_error },
963 	{ &vop_lookup_desc, fifo_lookup },	/* lookup */
964 	{ &vop_create_desc, isofs_create },	/* create */
965 	{ &vop_mknod_desc, isofs_mknod },	/* mknod */
966 	{ &vop_open_desc, fifo_open },		/* open */
967 	{ &vop_close_desc, fifo_close },	/* close */
968 	{ &vop_access_desc, isofs_access },	/* access */
969 	{ &vop_getattr_desc, isofs_getattr },	/* getattr */
970 	{ &vop_setattr_desc, isofs_setattr },	/* setattr */
971 	{ &vop_read_desc, fifo_read },		/* read */
972 	{ &vop_write_desc, fifo_write },	/* write */
973 	{ &vop_ioctl_desc, fifo_ioctl },	/* ioctl */
974 	{ &vop_select_desc, fifo_select },	/* select */
975 	{ &vop_mmap_desc, fifo_mmap },		/* mmap */
976 	{ &vop_fsync_desc, fifo_fsync },	/* fsync */
977 	{ &vop_seek_desc, fifo_seek },		/* seek */
978 	{ &vop_remove_desc, isofs_remove },	/* remove */
979 	{ &vop_link_desc, isofs_link },		/* link */
980 	{ &vop_rename_desc, isofs_rename },	/* rename */
981 	{ &vop_mkdir_desc, isofs_mkdir },	/* mkdir */
982 	{ &vop_rmdir_desc, isofs_rmdir },	/* rmdir */
983 	{ &vop_symlink_desc, isofs_symlink },	/* symlink */
984 	{ &vop_readdir_desc, fifo_readdir },	/* readdir */
985 	{ &vop_readlink_desc, fifo_readlink },	/* readlink */
986 	{ &vop_abortop_desc, fifo_abortop },	/* abortop */
987 	{ &vop_inactive_desc, isofs_inactive },	/* inactive */
988 	{ &vop_reclaim_desc, isofs_reclaim },	/* reclaim */
989 	{ &vop_lock_desc, isofs_lock },		/* lock */
990 	{ &vop_unlock_desc, isofs_unlock },	/* unlock */
991 	{ &vop_bmap_desc, fifo_bmap },		/* bmap */
992 	{ &vop_strategy_desc, fifo_badop },	/* strategy */
993 	{ &vop_print_desc, isofs_print },	/* print */
994 	{ &vop_islocked_desc, isofs_islocked },	/* islocked */
995 	{ &vop_pathconf_desc, fifo_pathconf },	/* pathconf */
996 	{ &vop_advlock_desc, fifo_advlock },	/* advlock */
997 	{ &vop_blkatoff_desc, fifo_blkatoff },	/* blkatoff */
998 	{ &vop_valloc_desc, fifo_valloc },	/* valloc */
999 	{ &vop_vfree_desc, fifo_vfree },	/* vfree */
1000 	{ &vop_truncate_desc, fifo_truncate },	/* truncate */
1001 	{ &vop_update_desc, isofs_update },	/* update */
1002 	{ &vop_bwrite_desc, vn_bwrite },
1003 	{ (struct vnodeop_desc*)NULL, (int(*)())NULL }
1004 };
1005 struct vnodeopv_desc isofs_fifoop_opv_desc =
1006 	{ &isofs_fifoop_p, isofs_fifoop_entries };
1007 #endif /* FIFO */
1008