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