xref: /freebsd/sys/fs/cd9660/cd9660_vnops.c (revision 4cf49a43559ed9fdad601bdcccd2c55963008675)
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  * $FreeBSD$
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/buf.h>
48 #include <sys/mount.h>
49 #include <sys/vnode.h>
50 #include <miscfs/fifofs/fifo.h>
51 #include <sys/malloc.h>
52 #include <sys/dirent.h>
53 #include <sys/unistd.h>
54 
55 #include <vm/vm.h>
56 #include <vm/vm_zone.h>
57 #include <vm/vnode_pager.h>
58 
59 #include <isofs/cd9660/iso.h>
60 #include <isofs/cd9660/cd9660_node.h>
61 #include <isofs/cd9660/iso_rrip.h>
62 
63 static int cd9660_setattr __P((struct vop_setattr_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_pathconf __P((struct vop_pathconf_args *));
67 static int cd9660_read __P((struct vop_read_args *));
68 struct isoreaddir;
69 static int iso_uiodir __P((struct isoreaddir *idp, struct dirent *dp,
70 			   off_t off));
71 static int iso_shipdir __P((struct isoreaddir *idp));
72 static int cd9660_readdir __P((struct vop_readdir_args *));
73 static int cd9660_readlink __P((struct vop_readlink_args *ap));
74 static int cd9660_abortop __P((struct vop_abortop_args *));
75 static int cd9660_strategy __P((struct vop_strategy_args *));
76 static int cd9660_print __P((struct vop_print_args *));
77 static int cd9660_getpages __P((struct vop_getpages_args *));
78 static int cd9660_putpages __P((struct vop_putpages_args *));
79 
80 /*
81  * Setattr call. Only allowed for block and character special devices.
82  */
83 int
84 cd9660_setattr(ap)
85 	struct vop_setattr_args /* {
86 		struct vnodeop_desc *a_desc;
87 		struct vnode *a_vp;
88 		struct vattr *a_vap;
89 		struct ucred *a_cred;
90 		struct proc *a_p;
91 	} */ *ap;
92 {
93 	struct vnode *vp = ap->a_vp;
94 	struct vattr *vap = ap->a_vap;
95 
96   	if (vap->va_flags != (u_long)VNOVAL || vap->va_uid != (uid_t)VNOVAL ||
97 	    vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL ||
98 	    vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL)
99 		return (EROFS);
100 	if (vap->va_size != (u_quad_t)VNOVAL) {
101  		switch (vp->v_type) {
102  		case VDIR:
103  			return (EISDIR);
104 		case VLNK:
105 		case VREG:
106 			return (EROFS);
107  		case VCHR:
108  		case VBLK:
109  		case VSOCK:
110  		case VFIFO:
111 		case VNON:
112 		case VBAD:
113 			return (0);
114 		}
115 	}
116 	return (0);
117 }
118 
119 /*
120  * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC.
121  * The mode is shifted to select the owner/group/other fields. The
122  * super user is granted all permissions.
123  */
124 /* ARGSUSED */
125 static int
126 cd9660_access(ap)
127 	struct vop_access_args /* {
128 		struct vnode *a_vp;
129 		int  a_mode;
130 		struct ucred *a_cred;
131 		struct proc *a_p;
132 	} */ *ap;
133 {
134 	struct vnode *vp = ap->a_vp;
135 	struct iso_node *ip = VTOI(vp);
136 	struct ucred *cred = ap->a_cred;
137 	mode_t mask, mode = ap->a_mode;
138 	gid_t *gp;
139 	int i;
140 
141 	/*
142 	 * Disallow write attempts unless the file is a socket,
143 	 * fifo, or a block or character device resident on the
144 	 * file system.
145 	 */
146 	if (mode & VWRITE) {
147 		switch (vp->v_type) {
148 		case VDIR:
149 		case VLNK:
150 		case VREG:
151 			return (EROFS);
152 			/* NOT REACHED */
153 		default:
154 			break;
155 		}
156 	}
157 
158 	/* User id 0 always gets access. */
159 	if (cred->cr_uid == 0)
160 		return (0);
161 
162 	mask = 0;
163 
164 	/* Otherwise, check the owner. */
165 	if (cred->cr_uid == ip->inode.iso_uid) {
166 		if (mode & VEXEC)
167 			mask |= S_IXUSR;
168 		if (mode & VREAD)
169 			mask |= S_IRUSR;
170 		if (mode & VWRITE)
171 			mask |= S_IWUSR;
172 		return ((ip->inode.iso_mode & mask) == mask ? 0 : EACCES);
173 	}
174 
175 	/* Otherwise, check the groups. */
176 	for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++)
177 		if (ip->inode.iso_gid == *gp) {
178 			if (mode & VEXEC)
179 				mask |= S_IXGRP;
180 			if (mode & VREAD)
181 				mask |= S_IRGRP;
182 			if (mode & VWRITE)
183 				mask |= S_IWGRP;
184 			return ((ip->inode.iso_mode & mask) == mask ?
185 			    0 : EACCES);
186 		}
187 
188 	/* Otherwise, check everyone else. */
189 	if (mode & VEXEC)
190 		mask |= S_IXOTH;
191 	if (mode & VREAD)
192 		mask |= S_IROTH;
193 	if (mode & VWRITE)
194 		mask |= S_IWOTH;
195 	return ((ip->inode.iso_mode & mask) == mask ? 0 : EACCES);
196 }
197 
198 static int
199 cd9660_getattr(ap)
200 	struct vop_getattr_args /* {
201 		struct vnode *a_vp;
202 		struct vattr *a_vap;
203 		struct ucred *a_cred;
204 		struct proc *a_p;
205 	} */ *ap;
206 
207 {
208 	struct vnode *vp = ap->a_vp;
209 	register struct vattr *vap = ap->a_vap;
210 	register struct iso_node *ip = VTOI(vp);
211 
212 	vap->va_fsid	= dev2udev(ip->i_dev);
213 	vap->va_fileid	= ip->i_number;
214 
215 	vap->va_mode	= ip->inode.iso_mode;
216 	vap->va_nlink	= ip->inode.iso_links;
217 	vap->va_uid	= ip->inode.iso_uid;
218 	vap->va_gid	= ip->inode.iso_gid;
219 	vap->va_atime	= ip->inode.iso_atime;
220 	vap->va_mtime	= ip->inode.iso_mtime;
221 	vap->va_ctime	= ip->inode.iso_ctime;
222 	vap->va_rdev	= ip->inode.iso_rdev;
223 
224 	vap->va_size	= (u_quad_t) ip->i_size;
225 	if (ip->i_size == 0 && (vap->va_mode & S_IFMT) == S_IFLNK) {
226 		struct vop_readlink_args rdlnk;
227 		struct iovec aiov;
228 		struct uio auio;
229 		char *cp;
230 
231 		MALLOC(cp, char *, MAXPATHLEN, M_TEMP, M_WAITOK);
232 		aiov.iov_base = cp;
233 		aiov.iov_len = MAXPATHLEN;
234 		auio.uio_iov = &aiov;
235 		auio.uio_iovcnt = 1;
236 		auio.uio_offset = 0;
237 		auio.uio_rw = UIO_READ;
238 		auio.uio_segflg = UIO_SYSSPACE;
239 		auio.uio_procp = ap->a_p;
240 		auio.uio_resid = MAXPATHLEN;
241 		rdlnk.a_uio = &auio;
242 		rdlnk.a_vp = ap->a_vp;
243 		rdlnk.a_cred = ap->a_cred;
244 		if (cd9660_readlink(&rdlnk) == 0)
245 			vap->va_size = MAXPATHLEN - auio.uio_resid;
246 		FREE(cp, M_TEMP);
247 	}
248 	vap->va_flags	= 0;
249 	vap->va_gen = 1;
250 	vap->va_blocksize = ip->i_mnt->logical_block_size;
251 	vap->va_bytes	= (u_quad_t) ip->i_size;
252 	vap->va_type	= vp->v_type;
253 	vap->va_filerev	= 0;
254 	return (0);
255 }
256 
257 /*
258  * Vnode op for reading.
259  */
260 static int
261 cd9660_read(ap)
262 	struct vop_read_args /* {
263 		struct vnode *a_vp;
264 		struct uio *a_uio;
265 		int a_ioflag;
266 		struct ucred *a_cred;
267 	} */ *ap;
268 {
269 	struct vnode *vp = ap->a_vp;
270 	register struct uio *uio = ap->a_uio;
271 	register struct iso_node *ip = VTOI(vp);
272 	register struct iso_mnt *imp;
273 	struct buf *bp;
274 	daddr_t lbn, rablock;
275 	off_t diff;
276 	int rasize, error = 0;
277 	int seqcount;
278 	long size, n, on;
279 
280 	seqcount = ap->a_ioflag >> 16;
281 
282 	if (uio->uio_resid == 0)
283 		return (0);
284 	if (uio->uio_offset < 0)
285 		return (EINVAL);
286 	ip->i_flag |= IN_ACCESS;
287 	imp = ip->i_mnt;
288 	do {
289 		lbn = lblkno(imp, uio->uio_offset);
290 		on = blkoff(imp, uio->uio_offset);
291 		n = min((u_int)(imp->logical_block_size - on),
292 			uio->uio_resid);
293 		diff = (off_t)ip->i_size - uio->uio_offset;
294 		if (diff <= 0)
295 			return (0);
296 		if (diff < n)
297 			n = diff;
298 		size = blksize(imp, ip, lbn);
299 		rablock = lbn + 1;
300 		if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) {
301 			if (lblktosize(imp, rablock) < ip->i_size)
302 				error = cluster_read(vp, (off_t)ip->i_size,
303 				         lbn, size, NOCRED, uio->uio_resid,
304 					 (ap->a_ioflag >> 16), &bp);
305 			else
306 				error = bread(vp, lbn, size, NOCRED, &bp);
307 		} else {
308 			if (seqcount > 1 &&
309 			    lblktosize(imp, rablock) < ip->i_size) {
310 				rasize = blksize(imp, ip, rablock);
311 				error = breadn(vp, lbn, size, &rablock,
312 					       &rasize, 1, NOCRED, &bp);
313 			} else
314 				error = bread(vp, lbn, size, NOCRED, &bp);
315 		}
316 		n = min(n, size - bp->b_resid);
317 		if (error) {
318 			brelse(bp);
319 			return (error);
320 		}
321 
322 		error = uiomove(bp->b_data + on, (int)n, uio);
323 		brelse(bp);
324 	} while (error == 0 && uio->uio_resid > 0 && n != 0);
325 	return (error);
326 }
327 
328 /*
329  * Structure for reading directories
330  */
331 struct isoreaddir {
332 	struct dirent saveent;
333 	struct dirent assocent;
334 	struct dirent current;
335 	off_t saveoff;
336 	off_t assocoff;
337 	off_t curroff;
338 	struct uio *uio;
339 	off_t uio_off;
340 	int eofflag;
341 	u_long *cookies;
342 	int ncookies;
343 };
344 
345 int
346 iso_uiodir(idp,dp,off)
347 	struct isoreaddir *idp;
348 	struct dirent *dp;
349 	off_t off;
350 {
351 	int error;
352 
353 	dp->d_name[dp->d_namlen] = 0;
354 	dp->d_reclen = GENERIC_DIRSIZ(dp);
355 
356 	if (idp->uio->uio_resid < dp->d_reclen) {
357 		idp->eofflag = 0;
358 		return (-1);
359 	}
360 
361 	if (idp->cookies) {
362 		if (idp->ncookies <= 0) {
363 			idp->eofflag = 0;
364 			return (-1);
365 		}
366 
367 		*idp->cookies++ = off;
368 		--idp->ncookies;
369 	}
370 
371 	if ((error = uiomove((caddr_t) dp,dp->d_reclen,idp->uio)) != 0)
372 		return (error);
373 	idp->uio_off = off;
374 	return (0);
375 }
376 
377 int
378 iso_shipdir(idp)
379 	struct isoreaddir *idp;
380 {
381 	struct dirent *dp;
382 	int cl, sl, assoc;
383 	int error;
384 	char *cname, *sname;
385 
386 	cl = idp->current.d_namlen;
387 	cname = idp->current.d_name;
388 assoc = (cl > 1) && (*cname == ASSOCCHAR);
389 	if (assoc) {
390 		cl--;
391 		cname++;
392 	}
393 
394 	dp = &idp->saveent;
395 	sname = dp->d_name;
396 	if (!(sl = dp->d_namlen)) {
397 		dp = &idp->assocent;
398 		sname = dp->d_name + 1;
399 		sl = dp->d_namlen - 1;
400 	}
401 	if (sl > 0) {
402 		if (sl != cl
403 		    || bcmp(sname,cname,sl)) {
404 			if (idp->assocent.d_namlen) {
405 				if ((error = iso_uiodir(idp,&idp->assocent,idp->assocoff)) != 0)
406 					return (error);
407 				idp->assocent.d_namlen = 0;
408 			}
409 			if (idp->saveent.d_namlen) {
410 				if ((error = iso_uiodir(idp,&idp->saveent,idp->saveoff)) != 0)
411 					return (error);
412 				idp->saveent.d_namlen = 0;
413 			}
414 		}
415 	}
416 	idp->current.d_reclen = GENERIC_DIRSIZ(&idp->current);
417 	if (assoc) {
418 		idp->assocoff = idp->curroff;
419 		bcopy(&idp->current,&idp->assocent,idp->current.d_reclen);
420 	} else {
421 		idp->saveoff = idp->curroff;
422 		bcopy(&idp->current,&idp->saveent,idp->current.d_reclen);
423 	}
424 	return (0);
425 }
426 
427 /*
428  * Vnode op for readdir
429  */
430 static int
431 cd9660_readdir(ap)
432 	struct vop_readdir_args /* {
433 		struct vnode *a_vp;
434 		struct uio *a_uio;
435 		struct ucred *a_cred;
436 		int *a_eofflag;
437 		int *a_ncookies;
438 		u_long *a_cookies;
439 	} */ *ap;
440 {
441 	register struct uio *uio = ap->a_uio;
442 	struct isoreaddir *idp;
443 	struct vnode *vdp = ap->a_vp;
444 	struct iso_node *dp;
445 	struct iso_mnt *imp;
446 	struct buf *bp = NULL;
447 	struct iso_directory_record *ep;
448 	int entryoffsetinblock;
449 	doff_t endsearch;
450 	u_long bmask;
451 	int error = 0;
452 	int reclen;
453 	u_short namelen;
454 	int ncookies = 0;
455 	u_long *cookies = NULL;
456 
457 	dp = VTOI(vdp);
458 	imp = dp->i_mnt;
459 	bmask = imp->im_bmask;
460 
461 	MALLOC(idp, struct isoreaddir *, sizeof(*idp), M_TEMP, M_WAITOK);
462 	idp->saveent.d_namlen = idp->assocent.d_namlen = 0;
463 	/*
464 	 * XXX
465 	 * Is it worth trying to figure out the type?
466 	 */
467 	idp->saveent.d_type = idp->assocent.d_type = idp->current.d_type =
468 	    DT_UNKNOWN;
469 	idp->uio = uio;
470 	if (ap->a_ncookies == NULL) {
471 		idp->cookies = NULL;
472 	} else {
473 		/*
474 		 * Guess the number of cookies needed.
475 		 */
476 		ncookies = uio->uio_resid / 16;
477 		MALLOC(cookies, u_long *, ncookies * sizeof(u_int), M_TEMP,
478 		    M_WAITOK);
479 		idp->cookies = cookies;
480 		idp->ncookies = ncookies;
481 	}
482 	idp->eofflag = 1;
483 	idp->curroff = uio->uio_offset;
484 
485 	if ((entryoffsetinblock = idp->curroff & bmask) &&
486 	    (error = cd9660_blkatoff(vdp, (off_t)idp->curroff, NULL, &bp))) {
487 		FREE(idp, M_TEMP);
488 		return (error);
489 	}
490 	endsearch = dp->i_size;
491 
492 	while (idp->curroff < endsearch) {
493 		/*
494 		 * If offset is on a block boundary,
495 		 * read the next directory block.
496 		 * Release previous if it exists.
497 		 */
498 		if ((idp->curroff & bmask) == 0) {
499 			if (bp != NULL)
500 				brelse(bp);
501 			if ((error =
502 			    cd9660_blkatoff(vdp, (off_t)idp->curroff, NULL, &bp)) != 0)
503 				break;
504 			entryoffsetinblock = 0;
505 		}
506 		/*
507 		 * Get pointer to next entry.
508 		 */
509 		ep = (struct iso_directory_record *)
510 			((char *)bp->b_data + entryoffsetinblock);
511 
512 		reclen = isonum_711(ep->length);
513 		if (reclen == 0) {
514 			/* skip to next block, if any */
515 			idp->curroff =
516 			    (idp->curroff & ~bmask) + imp->logical_block_size;
517 			continue;
518 		}
519 
520 		if (reclen < ISO_DIRECTORY_RECORD_SIZE) {
521 			error = EINVAL;
522 			/* illegal entry, stop */
523 			break;
524 		}
525 
526 		if (entryoffsetinblock + reclen > imp->logical_block_size) {
527 			error = EINVAL;
528 			/* illegal directory, so stop looking */
529 			break;
530 		}
531 
532 		idp->current.d_namlen = isonum_711(ep->name_len);
533 
534 		if (reclen < ISO_DIRECTORY_RECORD_SIZE + idp->current.d_namlen) {
535 			error = EINVAL;
536 			/* illegal entry, stop */
537 			break;
538 		}
539 
540 		if (isonum_711(ep->flags)&2)
541 			idp->current.d_fileno = isodirino(ep, imp);
542 		else
543 			idp->current.d_fileno = dbtob(bp->b_blkno) +
544 				entryoffsetinblock;
545 
546 		idp->curroff += reclen;
547 
548 		switch (imp->iso_ftype) {
549 		case ISO_FTYPE_RRIP:
550 			cd9660_rrip_getname(ep,idp->current.d_name, &namelen,
551 					   &idp->current.d_fileno,imp);
552 			idp->current.d_namlen = (u_char)namelen;
553 			if (idp->current.d_namlen)
554 				error = iso_uiodir(idp,&idp->current,idp->curroff);
555 			break;
556 		default: /* ISO_FTYPE_DEFAULT || ISO_FTYPE_9660 || ISO_FTYPE_HIGH_SIERRA*/
557 			strcpy(idp->current.d_name,"..");
558 			if (idp->current.d_namlen == 1 && ep->name[0] == 0) {
559 				idp->current.d_namlen = 1;
560 				error = iso_uiodir(idp,&idp->current,idp->curroff);
561 			} else if (idp->current.d_namlen == 1 && ep->name[0] == 1) {
562 				idp->current.d_namlen = 2;
563 				error = iso_uiodir(idp,&idp->current,idp->curroff);
564 			} else {
565 				isofntrans(ep->name,idp->current.d_namlen,
566 					   idp->current.d_name, &namelen,
567 					   imp->iso_ftype == ISO_FTYPE_9660,
568 					   isonum_711(ep->flags)&4,
569 					   imp->joliet_level);
570 				idp->current.d_namlen = (u_char)namelen;
571 				if (imp->iso_ftype == ISO_FTYPE_DEFAULT)
572 					error = iso_shipdir(idp);
573 				else
574 					error = iso_uiodir(idp,&idp->current,idp->curroff);
575 			}
576 		}
577 		if (error)
578 			break;
579 
580 		entryoffsetinblock += reclen;
581 	}
582 
583 	if (!error && imp->iso_ftype == ISO_FTYPE_DEFAULT) {
584 		idp->current.d_namlen = 0;
585 		error = iso_shipdir(idp);
586 	}
587 	if (error < 0)
588 		error = 0;
589 
590 	if (ap->a_ncookies != NULL) {
591 		if (error)
592 			free(cookies, M_TEMP);
593 		else {
594 			/*
595 			 * Work out the number of cookies actually used.
596 			 */
597 			*ap->a_ncookies = ncookies - idp->ncookies;
598 			*ap->a_cookies = cookies;
599 		}
600 	}
601 
602 	if (bp)
603 		brelse (bp);
604 
605 	uio->uio_offset = idp->uio_off;
606 	*ap->a_eofflag = idp->eofflag;
607 
608 	FREE(idp, M_TEMP);
609 
610 	return (error);
611 }
612 
613 /*
614  * Return target name of a symbolic link
615  * Shouldn't we get the parent vnode and read the data from there?
616  * This could eventually result in deadlocks in cd9660_lookup.
617  * But otherwise the block read here is in the block buffer two times.
618  */
619 typedef struct iso_directory_record ISODIR;
620 typedef struct iso_node		    ISONODE;
621 typedef struct iso_mnt		    ISOMNT;
622 static int
623 cd9660_readlink(ap)
624 	struct vop_readlink_args /* {
625 		struct vnode *a_vp;
626 		struct uio *a_uio;
627 		struct ucred *a_cred;
628 	} */ *ap;
629 {
630 	ISONODE	*ip;
631 	ISODIR	*dirp;
632 	ISOMNT	*imp;
633 	struct	buf *bp;
634 	struct	uio *uio;
635 	u_short	symlen;
636 	int	error;
637 	char	*symname;
638 
639 	ip  = VTOI(ap->a_vp);
640 	imp = ip->i_mnt;
641 	uio = ap->a_uio;
642 
643 	if (imp->iso_ftype != ISO_FTYPE_RRIP)
644 		return (EINVAL);
645 
646 	/*
647 	 * Get parents directory record block that this inode included.
648 	 */
649 	error = bread(imp->im_devvp,
650 		      (ip->i_number >> imp->im_bshift) <<
651 		      (imp->im_bshift - DEV_BSHIFT),
652 		      imp->logical_block_size, NOCRED, &bp);
653 	if (error) {
654 		brelse(bp);
655 		return (EINVAL);
656 	}
657 
658 	/*
659 	 * Setup the directory pointer for this inode
660 	 */
661 	dirp = (ISODIR *)(bp->b_data + (ip->i_number & imp->im_bmask));
662 
663 	/*
664 	 * Just make sure, we have a right one....
665 	 *   1: Check not cross boundary on block
666 	 */
667 	if ((ip->i_number & imp->im_bmask) + isonum_711(dirp->length)
668 	    > (unsigned)imp->logical_block_size) {
669 		brelse(bp);
670 		return (EINVAL);
671 	}
672 
673 	/*
674 	 * Now get a buffer
675 	 * Abuse a namei buffer for now.
676 	 */
677 	if (uio->uio_segflg == UIO_SYSSPACE)
678 		symname = uio->uio_iov->iov_base;
679 	else
680 		symname = zalloc(namei_zone);
681 
682 	/*
683 	 * Ok, we just gathering a symbolic name in SL record.
684 	 */
685 	if (cd9660_rrip_getsymname(dirp, symname, &symlen, imp) == 0) {
686 		if (uio->uio_segflg != UIO_SYSSPACE)
687 			zfree(namei_zone, symname);
688 		brelse(bp);
689 		return (EINVAL);
690 	}
691 	/*
692 	 * Don't forget before you leave from home ;-)
693 	 */
694 	brelse(bp);
695 
696 	/*
697 	 * return with the symbolic name to caller's.
698 	 */
699 	if (uio->uio_segflg != UIO_SYSSPACE) {
700 		error = uiomove(symname, symlen, uio);
701 		zfree(namei_zone, symname);
702 		return (error);
703 	}
704 	uio->uio_resid -= symlen;
705 	uio->uio_iov->iov_base += symlen;
706 	uio->uio_iov->iov_len -= symlen;
707 	return (0);
708 }
709 
710 /*
711  * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually
712  * done. If a buffer has been saved in anticipation of a CREATE, delete it.
713  */
714 static int
715 cd9660_abortop(ap)
716 	struct vop_abortop_args /* {
717 		struct vnode *a_dvp;
718 		struct componentname *a_cnp;
719 	} */ *ap;
720 {
721 	if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF)
722 		zfree(namei_zone, ap->a_cnp->cn_pnbuf);
723 	return (0);
724 }
725 
726 /*
727  * Calculate the logical to physical mapping if not done already,
728  * then call the device strategy routine.
729  */
730 static int
731 cd9660_strategy(ap)
732 	struct vop_strategy_args /* {
733 		struct buf *a_vp;
734 		struct buf *a_bp;
735 	} */ *ap;
736 {
737 	register struct buf *bp = ap->a_bp;
738 	register struct vnode *vp = bp->b_vp;
739 	register struct iso_node *ip;
740 	int error;
741 
742 	ip = VTOI(vp);
743 	if (vp->v_type == VBLK || vp->v_type == VCHR)
744 		panic("cd9660_strategy: spec");
745 	if (bp->b_blkno == bp->b_lblkno) {
746 		if ((error =
747 		    VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL, NULL))) {
748 			bp->b_error = error;
749 			bp->b_flags |= B_ERROR;
750 			biodone(bp);
751 			return (error);
752 		}
753 		if ((long)bp->b_blkno == -1)
754 			clrbuf(bp);
755 	}
756 	if ((long)bp->b_blkno == -1) {
757 		biodone(bp);
758 		return (0);
759 	}
760 	vp = ip->i_devvp;
761 	bp->b_dev = vp->v_rdev;
762 	VOP_STRATEGY(vp, bp);
763 	return (0);
764 }
765 
766 /*
767  * Print out the contents of an inode.
768  */
769 static int
770 cd9660_print(ap)
771 	struct vop_print_args /* {
772 		struct vnode *a_vp;
773 	} */ *ap;
774 {
775 
776 	printf("tag VT_ISOFS, isofs vnode\n");
777 	return (0);
778 }
779 
780 /*
781  * Return POSIX pathconf information applicable to cd9660 filesystems.
782  */
783 static int
784 cd9660_pathconf(ap)
785 	struct vop_pathconf_args /* {
786 		struct vnode *a_vp;
787 		int a_name;
788 		register_t *a_retval;
789 	} */ *ap;
790 {
791 
792 	switch (ap->a_name) {
793 	case _PC_LINK_MAX:
794 		*ap->a_retval = 1;
795 		return (0);
796 	case _PC_NAME_MAX:
797 		if (VTOI(ap->a_vp)->i_mnt->iso_ftype == ISO_FTYPE_RRIP)
798 			*ap->a_retval = NAME_MAX;
799 		else
800 			*ap->a_retval = 37;
801 		return (0);
802 	case _PC_PATH_MAX:
803 		*ap->a_retval = PATH_MAX;
804 		return (0);
805 	case _PC_PIPE_BUF:
806 		*ap->a_retval = PIPE_BUF;
807 		return (0);
808 	case _PC_CHOWN_RESTRICTED:
809 		*ap->a_retval = 1;
810 		return (0);
811 	case _PC_NO_TRUNC:
812 		*ap->a_retval = 1;
813 		return (0);
814 	default:
815 		return (EINVAL);
816 	}
817 	/* NOTREACHED */
818 }
819 
820 /*
821  * get page routine
822  *
823  * XXX By default, wimp out... note that a_offset is ignored (and always
824  * XXX has been).
825  */
826 int
827 cd9660_getpages(ap)
828 	struct vop_getpages_args *ap;
829 {
830 	return vnode_pager_generic_getpages(ap->a_vp, ap->a_m, ap->a_count,
831 		ap->a_reqpage);
832 }
833 
834 /*
835  * put page routine
836  *
837  * XXX By default, wimp out... note that a_offset is ignored (and always
838  * XXX has been).
839  */
840 int
841 cd9660_putpages(ap)
842 	struct vop_putpages_args *ap;
843 {
844 	return vnode_pager_generic_putpages(ap->a_vp, ap->a_m, ap->a_count,
845 		ap->a_sync, ap->a_rtvals);
846 }
847 
848 /*
849  * Global vfs data structures for cd9660
850  */
851 vop_t **cd9660_vnodeop_p;
852 static struct vnodeopv_entry_desc cd9660_vnodeop_entries[] = {
853 	{ &vop_default_desc,		(vop_t *) vop_defaultop },
854 	{ &vop_abortop_desc,		(vop_t *) cd9660_abortop },
855 	{ &vop_access_desc,		(vop_t *) cd9660_access },
856 	{ &vop_bmap_desc,		(vop_t *) cd9660_bmap },
857 	{ &vop_cachedlookup_desc,	(vop_t *) cd9660_lookup },
858 	{ &vop_getattr_desc,		(vop_t *) cd9660_getattr },
859 	{ &vop_inactive_desc,		(vop_t *) cd9660_inactive },
860 	{ &vop_islocked_desc,		(vop_t *) vop_stdislocked },
861 	{ &vop_lock_desc,		(vop_t *) vop_stdlock },
862 	{ &vop_lookup_desc,		(vop_t *) vfs_cache_lookup },
863 	{ &vop_pathconf_desc,		(vop_t *) cd9660_pathconf },
864 	{ &vop_print_desc,		(vop_t *) cd9660_print },
865 	{ &vop_read_desc,		(vop_t *) cd9660_read },
866 	{ &vop_readdir_desc,		(vop_t *) cd9660_readdir },
867 	{ &vop_readlink_desc,		(vop_t *) cd9660_readlink },
868 	{ &vop_reclaim_desc,		(vop_t *) cd9660_reclaim },
869 	{ &vop_setattr_desc,		(vop_t *) cd9660_setattr },
870 	{ &vop_strategy_desc,		(vop_t *) cd9660_strategy },
871 	{ &vop_unlock_desc,		(vop_t *) vop_stdunlock },
872 	{ &vop_getpages_desc,		(vop_t *) cd9660_getpages },
873 	{ &vop_putpages_desc,		(vop_t *) cd9660_putpages },
874 	{ NULL, NULL }
875 };
876 static struct vnodeopv_desc cd9660_vnodeop_opv_desc =
877 	{ &cd9660_vnodeop_p, cd9660_vnodeop_entries };
878 VNODEOP_SET(cd9660_vnodeop_opv_desc);
879 
880 /*
881  * Special device vnode ops
882  */
883 vop_t **cd9660_specop_p;
884 static struct vnodeopv_entry_desc cd9660_specop_entries[] = {
885 	{ &vop_default_desc,		(vop_t *) spec_vnoperate },
886 	{ &vop_access_desc,		(vop_t *) cd9660_access },
887 	{ &vop_getattr_desc,		(vop_t *) cd9660_getattr },
888 	{ &vop_inactive_desc,		(vop_t *) cd9660_inactive },
889 	{ &vop_islocked_desc,		(vop_t *) vop_stdislocked },
890 	{ &vop_lock_desc,		(vop_t *) vop_stdlock },
891 	{ &vop_print_desc,		(vop_t *) cd9660_print },
892 	{ &vop_reclaim_desc,		(vop_t *) cd9660_reclaim },
893 	{ &vop_setattr_desc,		(vop_t *) cd9660_setattr },
894 	{ &vop_unlock_desc,		(vop_t *) vop_stdunlock },
895 	{ NULL, NULL }
896 };
897 static struct vnodeopv_desc cd9660_specop_opv_desc =
898 	{ &cd9660_specop_p, cd9660_specop_entries };
899 VNODEOP_SET(cd9660_specop_opv_desc);
900 
901 vop_t **cd9660_fifoop_p;
902 static struct vnodeopv_entry_desc cd9660_fifoop_entries[] = {
903 	{ &vop_default_desc,		(vop_t *) fifo_vnoperate },
904 	{ &vop_access_desc,		(vop_t *) cd9660_access },
905 	{ &vop_getattr_desc,		(vop_t *) cd9660_getattr },
906 	{ &vop_inactive_desc,		(vop_t *) cd9660_inactive },
907 	{ &vop_islocked_desc,		(vop_t *) vop_stdislocked },
908 	{ &vop_lock_desc,		(vop_t *) vop_stdlock },
909 	{ &vop_print_desc,		(vop_t *) cd9660_print },
910 	{ &vop_reclaim_desc,		(vop_t *) cd9660_reclaim },
911 	{ &vop_setattr_desc,		(vop_t *) cd9660_setattr },
912 	{ &vop_unlock_desc,		(vop_t *) vop_stdunlock },
913 	{ NULL, NULL }
914 };
915 static struct vnodeopv_desc cd9660_fifoop_opv_desc =
916 	{ &cd9660_fifoop_p, cd9660_fifoop_entries };
917 
918 VNODEOP_SET(cd9660_fifoop_opv_desc);
919