1/*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1994
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley
8 * by Pace Willisson (pace@blitz.com).  The Rock Ridge Extension
9 * Support code is derived from software contributed to Berkeley
10 * by Atsushi Murai (amurai@spec.co.jp).
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 *    notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 *    notice, this list of conditions and the following disclaimer in the
19 *    documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 *	@(#)cd9660_vnops.c	8.19 (Berkeley) 5/27/95
37 */
38
39#include <sys/cdefs.h>
40__FBSDID("$FreeBSD$");
41
42#include <sys/param.h>
43#include <sys/systm.h>
44#include <sys/namei.h>
45#include <sys/kernel.h>
46#include <sys/conf.h>
47#include <sys/stat.h>
48#include <sys/bio.h>
49#include <sys/buf.h>
50#include <sys/mount.h>
51#include <sys/vnode.h>
52#include <sys/malloc.h>
53#include <sys/dirent.h>
54#include <sys/unistd.h>
55#include <sys/filio.h>
56#include <sys/sysctl.h>
57
58#include <vm/vm.h>
59#include <vm/vnode_pager.h>
60#include <vm/uma.h>
61
62#include <fs/cd9660/iso.h>
63#include <fs/cd9660/cd9660_node.h>
64#include <fs/cd9660/iso_rrip.h>
65
66static vop_setattr_t	cd9660_setattr;
67static vop_open_t	cd9660_open;
68static vop_access_t	cd9660_access;
69static vop_getattr_t	cd9660_getattr;
70static vop_ioctl_t	cd9660_ioctl;
71static vop_pathconf_t	cd9660_pathconf;
72static vop_read_t	cd9660_read;
73struct isoreaddir;
74static int iso_uiodir(struct isoreaddir *idp, struct dirent *dp, off_t off);
75static int iso_shipdir(struct isoreaddir *idp);
76static vop_readdir_t	cd9660_readdir;
77static vop_readlink_t	cd9660_readlink;
78static vop_strategy_t	cd9660_strategy;
79static vop_vptofh_t	cd9660_vptofh;
80static vop_getpages_t	cd9660_getpages;
81
82/*
83 * Setattr call. Only allowed for block and character special devices.
84 */
85static int
86cd9660_setattr(ap)
87	struct vop_setattr_args /* {
88		struct vnodeop_desc *a_desc;
89		struct vnode *a_vp;
90		struct vattr *a_vap;
91		struct ucred *a_cred;
92	} */ *ap;
93{
94	struct vnode *vp = ap->a_vp;
95	struct vattr *vap = ap->a_vap;
96
97	if (vap->va_flags != (u_long)VNOVAL || vap->va_uid != (uid_t)VNOVAL ||
98	    vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL ||
99	    vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL)
100		return (EROFS);
101	if (vap->va_size != (u_quad_t)VNOVAL) {
102		switch (vp->v_type) {
103		case VDIR:
104			return (EISDIR);
105		case VLNK:
106		case VREG:
107			return (EROFS);
108		case VCHR:
109		case VBLK:
110		case VSOCK:
111		case VFIFO:
112		case VNON:
113		case VBAD:
114		case VMARKER:
115			return (0);
116		}
117	}
118	return (0);
119}
120
121/*
122 * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC.
123 * The mode is shifted to select the owner/group/other fields. The
124 * super user is granted all permissions.
125 */
126/* ARGSUSED */
127static int
128cd9660_access(ap)
129	struct vop_access_args /* {
130		struct vnode *a_vp;
131		accmode_t a_accmode;
132		struct ucred *a_cred;
133		struct thread *a_td;
134	} */ *ap;
135{
136	struct vnode *vp = ap->a_vp;
137	struct iso_node *ip = VTOI(vp);
138	accmode_t accmode = ap->a_accmode;
139
140	if (vp->v_type == VCHR || vp->v_type == VBLK)
141		return (EOPNOTSUPP);
142
143	/*
144	 * Disallow write attempts unless the file is a socket,
145	 * fifo, or a block or character device resident on the
146	 * filesystem.
147	 */
148	if (accmode & VWRITE) {
149		switch (vp->v_type) {
150		case VDIR:
151		case VLNK:
152		case VREG:
153			return (EROFS);
154			/* NOT REACHED */
155		default:
156			break;
157		}
158	}
159
160	return (vaccess(vp->v_type, ip->inode.iso_mode, ip->inode.iso_uid,
161	    ip->inode.iso_gid, ap->a_accmode, ap->a_cred, NULL));
162}
163
164static int
165cd9660_open(ap)
166	struct vop_open_args /* {
167		struct vnode *a_vp;
168		int a_mode;
169		struct ucred *a_cred;
170		struct thread *a_td;
171		struct file *a_fp;
172	} */ *ap;
173{
174	struct vnode *vp = ap->a_vp;
175	struct iso_node *ip = VTOI(vp);
176
177	if (vp->v_type == VCHR || vp->v_type == VBLK)
178		return (EOPNOTSUPP);
179
180	vnode_create_vobject(vp, ip->i_size, ap->a_td);
181	return (0);
182}
183
184
185static int
186cd9660_getattr(ap)
187	struct vop_getattr_args /* {
188		struct vnode *a_vp;
189		struct vattr *a_vap;
190		struct ucred *a_cred;
191	} */ *ap;
192
193{
194	struct vnode *vp = ap->a_vp;
195	struct vattr *vap = ap->a_vap;
196	struct iso_node *ip = VTOI(vp);
197
198	vap->va_fsid    = dev2udev(ip->i_mnt->im_dev);
199	vap->va_fileid	= ip->i_number;
200
201	vap->va_mode	= ip->inode.iso_mode;
202	vap->va_nlink	= ip->inode.iso_links;
203	vap->va_uid	= ip->inode.iso_uid;
204	vap->va_gid	= ip->inode.iso_gid;
205	vap->va_atime	= ip->inode.iso_atime;
206	vap->va_mtime	= ip->inode.iso_mtime;
207	vap->va_ctime	= ip->inode.iso_ctime;
208	vap->va_rdev	= ip->inode.iso_rdev;
209
210	vap->va_size	= (u_quad_t) ip->i_size;
211	if (ip->i_size == 0 && (vap->va_mode & S_IFMT) == S_IFLNK) {
212		struct vop_readlink_args rdlnk;
213		struct iovec aiov;
214		struct uio auio;
215		char *cp;
216
217		cp = malloc(MAXPATHLEN, M_TEMP, M_WAITOK);
218		aiov.iov_base = cp;
219		aiov.iov_len = MAXPATHLEN;
220		auio.uio_iov = &aiov;
221		auio.uio_iovcnt = 1;
222		auio.uio_offset = 0;
223		auio.uio_rw = UIO_READ;
224		auio.uio_segflg = UIO_SYSSPACE;
225		auio.uio_td = curthread;
226		auio.uio_resid = MAXPATHLEN;
227		rdlnk.a_uio = &auio;
228		rdlnk.a_vp = ap->a_vp;
229		rdlnk.a_cred = ap->a_cred;
230		if (cd9660_readlink(&rdlnk) == 0)
231			vap->va_size = MAXPATHLEN - auio.uio_resid;
232		free(cp, M_TEMP);
233	}
234	vap->va_flags	= 0;
235	vap->va_gen = 1;
236	vap->va_blocksize = ip->i_mnt->logical_block_size;
237	vap->va_bytes	= (u_quad_t) ip->i_size;
238	vap->va_type	= vp->v_type;
239	vap->va_filerev	= 0;
240	return (0);
241}
242
243/*
244 * Vnode op for ioctl.
245 */
246static int
247cd9660_ioctl(ap)
248	struct vop_ioctl_args /* {
249		struct vnode *a_vp;
250		u_long  a_command;
251		caddr_t  a_data;
252		int  a_fflag;
253		struct ucred *a_cred;
254		struct thread *a_td;
255	} */ *ap;
256{
257	struct vnode *vp;
258	struct iso_node *ip;
259	int error;
260
261	vp = ap->a_vp;
262	vn_lock(vp, LK_SHARED | LK_RETRY);
263	if (vp->v_iflag & VI_DOOMED) {
264		VOP_UNLOCK(vp, 0);
265		return (EBADF);
266	}
267	if (vp->v_type == VCHR || vp->v_type == VBLK) {
268		VOP_UNLOCK(vp, 0);
269		return (EOPNOTSUPP);
270	}
271
272	ip = VTOI(vp);
273	error = 0;
274
275	switch (ap->a_command) {
276	case FIOGETLBA:
277		*(int *)(ap->a_data) = ip->iso_start;
278		break;
279	default:
280		error = ENOTTY;
281		break;
282	}
283
284	VOP_UNLOCK(vp, 0);
285	return (error);
286}
287
288/*
289 * Vnode op for reading.
290 */
291static int
292cd9660_read(ap)
293	struct vop_read_args /* {
294		struct vnode *a_vp;
295		struct uio *a_uio;
296		int a_ioflag;
297		struct ucred *a_cred;
298	} */ *ap;
299{
300	struct vnode *vp = ap->a_vp;
301	struct uio *uio = ap->a_uio;
302	struct iso_node *ip = VTOI(vp);
303	struct iso_mnt *imp;
304	struct buf *bp;
305	daddr_t lbn, rablock;
306	off_t diff;
307	int rasize, error = 0;
308	int seqcount;
309	long size, n, on;
310
311	if (vp->v_type == VCHR || vp->v_type == VBLK)
312		return (EOPNOTSUPP);
313
314	seqcount = ap->a_ioflag >> IO_SEQSHIFT;
315
316	if (uio->uio_resid == 0)
317		return (0);
318	if (uio->uio_offset < 0)
319		return (EINVAL);
320	imp = ip->i_mnt;
321	do {
322		lbn = lblkno(imp, uio->uio_offset);
323		on = blkoff(imp, uio->uio_offset);
324		n = MIN(imp->logical_block_size - on, uio->uio_resid);
325		diff = (off_t)ip->i_size - uio->uio_offset;
326		if (diff <= 0)
327			return (0);
328		if (diff < n)
329			n = diff;
330		size = blksize(imp, ip, lbn);
331		rablock = lbn + 1;
332		if ((vp->v_mount->mnt_flag & MNT_NOCLUSTERR) == 0) {
333			if (lblktosize(imp, rablock) < ip->i_size)
334				error = cluster_read(vp, (off_t)ip->i_size,
335					 lbn, size, NOCRED, uio->uio_resid,
336					 (ap->a_ioflag >> 16), 0, &bp);
337			else
338				error = bread(vp, lbn, size, NOCRED, &bp);
339		} else {
340			if (seqcount > 1 &&
341			    lblktosize(imp, rablock) < ip->i_size) {
342				rasize = blksize(imp, ip, rablock);
343				error = breadn(vp, lbn, size, &rablock,
344					       &rasize, 1, NOCRED, &bp);
345			} else
346				error = bread(vp, lbn, size, NOCRED, &bp);
347		}
348		if (error != 0)
349			return (error);
350		n = MIN(n, size - bp->b_resid);
351
352		error = uiomove(bp->b_data + on, (int)n, uio);
353		brelse(bp);
354	} while (error == 0 && uio->uio_resid > 0 && n != 0);
355	return (error);
356}
357
358/*
359 * Structure for reading directories
360 */
361struct isoreaddir {
362	struct dirent saveent;
363	struct dirent assocent;
364	struct dirent current;
365	off_t saveoff;
366	off_t assocoff;
367	off_t curroff;
368	struct uio *uio;
369	off_t uio_off;
370	int eofflag;
371	u_long *cookies;
372	int ncookies;
373};
374
375static int
376iso_uiodir(idp,dp,off)
377	struct isoreaddir *idp;
378	struct dirent *dp;
379	off_t off;
380{
381	int error;
382
383	dp->d_reclen = GENERIC_DIRSIZ(dp);
384	dirent_terminate(dp);
385
386	if (idp->uio->uio_resid < dp->d_reclen) {
387		idp->eofflag = 0;
388		return (-1);
389	}
390
391	if (idp->cookies) {
392		if (idp->ncookies <= 0) {
393			idp->eofflag = 0;
394			return (-1);
395		}
396
397		*idp->cookies++ = off;
398		--idp->ncookies;
399	}
400
401	if ((error = uiomove(dp, dp->d_reclen, idp->uio)) != 0)
402		return (error);
403	idp->uio_off = off;
404	return (0);
405}
406
407static int
408iso_shipdir(idp)
409	struct isoreaddir *idp;
410{
411	struct dirent *dp;
412	int cl, sl, assoc;
413	int error;
414	char *cname, *sname;
415
416	cl = idp->current.d_namlen;
417	cname = idp->current.d_name;
418	assoc = (cl > 1) && (*cname == ASSOCCHAR);
419	if (assoc) {
420		cl--;
421		cname++;
422	}
423
424	dp = &idp->saveent;
425	sname = dp->d_name;
426	if (!(sl = dp->d_namlen)) {
427		dp = &idp->assocent;
428		sname = dp->d_name + 1;
429		sl = dp->d_namlen - 1;
430	}
431	if (sl > 0) {
432		if (sl != cl
433		    || bcmp(sname,cname,sl)) {
434			if (idp->assocent.d_namlen) {
435				if ((error = iso_uiodir(idp,&idp->assocent,idp->assocoff)) != 0)
436					return (error);
437				idp->assocent.d_namlen = 0;
438			}
439			if (idp->saveent.d_namlen) {
440				if ((error = iso_uiodir(idp,&idp->saveent,idp->saveoff)) != 0)
441					return (error);
442				idp->saveent.d_namlen = 0;
443			}
444		}
445	}
446	idp->current.d_reclen = GENERIC_DIRSIZ(&idp->current);
447	if (assoc) {
448		idp->assocoff = idp->curroff;
449		memcpy(&idp->assocent, &idp->current, idp->current.d_reclen);
450	} else {
451		idp->saveoff = idp->curroff;
452		memcpy(&idp->saveent, &idp->current, idp->current.d_reclen);
453	}
454	return (0);
455}
456
457/*
458 * Vnode op for readdir
459 */
460static int
461cd9660_readdir(ap)
462	struct vop_readdir_args /* {
463		struct vnode *a_vp;
464		struct uio *a_uio;
465		struct ucred *a_cred;
466		int *a_eofflag;
467		int *a_ncookies;
468		u_long **a_cookies;
469	} */ *ap;
470{
471	struct uio *uio = ap->a_uio;
472	struct isoreaddir *idp;
473	struct vnode *vdp = ap->a_vp;
474	struct iso_node *dp;
475	struct iso_mnt *imp;
476	struct buf *bp = NULL;
477	struct iso_directory_record *ep;
478	int entryoffsetinblock;
479	doff_t endsearch;
480	u_long bmask;
481	int error = 0;
482	int reclen;
483	u_short namelen;
484	u_int ncookies = 0;
485	u_long *cookies = NULL;
486	cd_ino_t ino;
487
488	dp = VTOI(vdp);
489	imp = dp->i_mnt;
490	bmask = imp->im_bmask;
491
492	idp = malloc(sizeof(*idp), M_TEMP, M_WAITOK);
493	idp->saveent.d_namlen = idp->assocent.d_namlen = 0;
494	/*
495	 * XXX
496	 * Is it worth trying to figure out the type?
497	 */
498	idp->saveent.d_type = idp->assocent.d_type = idp->current.d_type =
499	    DT_UNKNOWN;
500	idp->uio = uio;
501	if (ap->a_ncookies == NULL) {
502		idp->cookies = NULL;
503	} else {
504		/*
505		 * Guess the number of cookies needed.
506		 */
507		ncookies = uio->uio_resid / 16;
508		cookies = malloc(ncookies * sizeof(u_long),
509		    M_TEMP, M_WAITOK);
510		idp->cookies = cookies;
511		idp->ncookies = ncookies;
512	}
513	idp->eofflag = 1;
514	idp->curroff = uio->uio_offset;
515	idp->uio_off = uio->uio_offset;
516
517	if ((entryoffsetinblock = idp->curroff & bmask) &&
518	    (error = cd9660_blkatoff(vdp, (off_t)idp->curroff, NULL, &bp))) {
519		free(idp, M_TEMP);
520		return (error);
521	}
522	endsearch = dp->i_size;
523
524	while (idp->curroff < endsearch) {
525		/*
526		 * If offset is on a block boundary,
527		 * read the next directory block.
528		 * Release previous if it exists.
529		 */
530		if ((idp->curroff & bmask) == 0) {
531			if (bp != NULL)
532				brelse(bp);
533			if ((error =
534			    cd9660_blkatoff(vdp, (off_t)idp->curroff, NULL, &bp)) != 0)
535				break;
536			entryoffsetinblock = 0;
537		}
538		/*
539		 * Get pointer to next entry.
540		 */
541		ep = (struct iso_directory_record *)
542			((char *)bp->b_data + entryoffsetinblock);
543
544		reclen = isonum_711(ep->length);
545		if (reclen == 0) {
546			/* skip to next block, if any */
547			idp->curroff =
548			    (idp->curroff & ~bmask) + imp->logical_block_size;
549			continue;
550		}
551
552		if (reclen < ISO_DIRECTORY_RECORD_SIZE) {
553			error = EINVAL;
554			/* illegal entry, stop */
555			break;
556		}
557
558		if (entryoffsetinblock + reclen > imp->logical_block_size) {
559			error = EINVAL;
560			/* illegal directory, so stop looking */
561			break;
562		}
563
564		idp->current.d_namlen = isonum_711(ep->name_len);
565
566		if (reclen < ISO_DIRECTORY_RECORD_SIZE + idp->current.d_namlen) {
567			error = EINVAL;
568			/* illegal entry, stop */
569			break;
570		}
571
572		if (isonum_711(ep->flags)&2)
573			idp->current.d_fileno = isodirino(ep, imp);
574		else
575			idp->current.d_fileno = dbtob(bp->b_blkno) +
576				entryoffsetinblock;
577
578		idp->curroff += reclen;
579		/* NOTE: d_off is the offset of *next* entry. */
580		idp->current.d_off = idp->curroff;
581
582		switch (imp->iso_ftype) {
583		case ISO_FTYPE_RRIP:
584			ino = idp->current.d_fileno;
585			cd9660_rrip_getname(ep, idp->current.d_name, &namelen,
586			    &ino, imp);
587			idp->current.d_fileno = ino;
588			idp->current.d_namlen = (u_char)namelen;
589			if (idp->current.d_namlen)
590				error = iso_uiodir(idp,&idp->current,idp->curroff);
591			break;
592		default: /* ISO_FTYPE_DEFAULT || ISO_FTYPE_9660 || ISO_FTYPE_HIGH_SIERRA*/
593			strcpy(idp->current.d_name,"..");
594			if (idp->current.d_namlen == 1 && ep->name[0] == 0) {
595				idp->current.d_namlen = 1;
596				error = iso_uiodir(idp,&idp->current,idp->curroff);
597			} else if (idp->current.d_namlen == 1 && ep->name[0] == 1) {
598				idp->current.d_namlen = 2;
599				error = iso_uiodir(idp,&idp->current,idp->curroff);
600			} else {
601				isofntrans(ep->name,idp->current.d_namlen,
602					   idp->current.d_name, &namelen,
603					   imp->iso_ftype == ISO_FTYPE_9660,
604					   isonum_711(ep->flags)&4,
605					   imp->joliet_level,
606					   imp->im_flags,
607					   imp->im_d2l);
608				idp->current.d_namlen = (u_char)namelen;
609				if (imp->iso_ftype == ISO_FTYPE_DEFAULT)
610					error = iso_shipdir(idp);
611				else
612					error = iso_uiodir(idp,&idp->current,idp->curroff);
613			}
614		}
615		if (error)
616			break;
617
618		entryoffsetinblock += reclen;
619	}
620
621	if (!error && imp->iso_ftype == ISO_FTYPE_DEFAULT) {
622		idp->current.d_namlen = 0;
623		error = iso_shipdir(idp);
624	}
625	if (error < 0)
626		error = 0;
627
628	if (ap->a_ncookies != NULL) {
629		if (error)
630			free(cookies, M_TEMP);
631		else {
632			/*
633			 * Work out the number of cookies actually used.
634			 */
635			*ap->a_ncookies = ncookies - idp->ncookies;
636			*ap->a_cookies = cookies;
637		}
638	}
639
640	if (bp)
641		brelse (bp);
642
643	uio->uio_offset = idp->uio_off;
644	*ap->a_eofflag = idp->eofflag;
645
646	free(idp, M_TEMP);
647
648	return (error);
649}
650
651/*
652 * Return target name of a symbolic link
653 * Shouldn't we get the parent vnode and read the data from there?
654 * This could eventually result in deadlocks in cd9660_lookup.
655 * But otherwise the block read here is in the block buffer two times.
656 */
657typedef struct iso_directory_record ISODIR;
658typedef struct iso_node		    ISONODE;
659typedef struct iso_mnt		    ISOMNT;
660static int
661cd9660_readlink(ap)
662	struct vop_readlink_args /* {
663		struct vnode *a_vp;
664		struct uio *a_uio;
665		struct ucred *a_cred;
666	} */ *ap;
667{
668	ISONODE	*ip;
669	ISODIR	*dirp;
670	ISOMNT	*imp;
671	struct	buf *bp;
672	struct	uio *uio;
673	u_short	symlen;
674	int	error;
675	char	*symname;
676
677	ip  = VTOI(ap->a_vp);
678	imp = ip->i_mnt;
679	uio = ap->a_uio;
680
681	if (imp->iso_ftype != ISO_FTYPE_RRIP)
682		return (EINVAL);
683
684	/*
685	 * Get parents directory record block that this inode included.
686	 */
687	error = bread(imp->im_devvp,
688		      (ip->i_number >> imp->im_bshift) <<
689		      (imp->im_bshift - DEV_BSHIFT),
690		      imp->logical_block_size, NOCRED, &bp);
691	if (error) {
692		brelse(bp);
693		return (EINVAL);
694	}
695
696	/*
697	 * Setup the directory pointer for this inode
698	 */
699	dirp = (ISODIR *)(bp->b_data + (ip->i_number & imp->im_bmask));
700
701	/*
702	 * Just make sure, we have a right one....
703	 *   1: Check not cross boundary on block
704	 */
705	if ((ip->i_number & imp->im_bmask) + isonum_711(dirp->length)
706	    > (unsigned)imp->logical_block_size) {
707		brelse(bp);
708		return (EINVAL);
709	}
710
711	/*
712	 * Now get a buffer
713	 * Abuse a namei buffer for now.
714	 */
715	if (uio->uio_segflg == UIO_SYSSPACE)
716		symname = uio->uio_iov->iov_base;
717	else
718		symname = uma_zalloc(namei_zone, M_WAITOK);
719
720	/*
721	 * Ok, we just gathering a symbolic name in SL record.
722	 */
723	if (cd9660_rrip_getsymname(dirp, symname, &symlen, imp) == 0) {
724		if (uio->uio_segflg != UIO_SYSSPACE)
725			uma_zfree(namei_zone, symname);
726		brelse(bp);
727		return (EINVAL);
728	}
729	/*
730	 * Don't forget before you leave from home ;-)
731	 */
732	brelse(bp);
733
734	/*
735	 * return with the symbolic name to caller's.
736	 */
737	if (uio->uio_segflg != UIO_SYSSPACE) {
738		error = uiomove(symname, symlen, uio);
739		uma_zfree(namei_zone, symname);
740		return (error);
741	}
742	uio->uio_resid -= symlen;
743	uio->uio_iov->iov_base = (char *)uio->uio_iov->iov_base + symlen;
744	uio->uio_iov->iov_len -= symlen;
745	return (0);
746}
747
748/*
749 * Calculate the logical to physical mapping if not done already,
750 * then call the device strategy routine.
751 */
752static int
753cd9660_strategy(ap)
754	struct vop_strategy_args /* {
755		struct buf *a_vp;
756		struct buf *a_bp;
757	} */ *ap;
758{
759	struct buf *bp = ap->a_bp;
760	struct vnode *vp = ap->a_vp;
761	struct iso_node *ip;
762	struct bufobj *bo;
763
764	ip = VTOI(vp);
765	if (vp->v_type == VBLK || vp->v_type == VCHR)
766		panic("cd9660_strategy: spec");
767	if (bp->b_blkno == bp->b_lblkno) {
768		bp->b_blkno = (ip->iso_start + bp->b_lblkno) <<
769		    (ip->i_mnt->im_bshift - DEV_BSHIFT);
770	}
771	bp->b_iooffset = dbtob(bp->b_blkno);
772	bo = ip->i_mnt->im_bo;
773	BO_STRATEGY(bo, bp);
774	return (0);
775}
776
777/*
778 * Return POSIX pathconf information applicable to cd9660 filesystems.
779 */
780static int
781cd9660_pathconf(ap)
782	struct vop_pathconf_args /* {
783		struct vnode *a_vp;
784		int a_name;
785		register_t *a_retval;
786	} */ *ap;
787{
788
789	switch (ap->a_name) {
790	case _PC_FILESIZEBITS:
791		*ap->a_retval = 32;
792		return (0);
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_SYMLINK_MAX:
803		if (VTOI(ap->a_vp)->i_mnt->iso_ftype == ISO_FTYPE_RRIP) {
804			*ap->a_retval = MAXPATHLEN;
805			return (0);
806		}
807		return (EINVAL);
808	case _PC_NO_TRUNC:
809		*ap->a_retval = 1;
810		return (0);
811	default:
812		return (vop_stdpathconf(ap));
813	}
814	/* NOTREACHED */
815}
816
817/*
818 * Vnode pointer to File handle
819 */
820static int
821cd9660_vptofh(ap)
822	struct vop_vptofh_args /* {
823		struct vnode *a_vp;
824		struct fid *a_fhp;
825	} */ *ap;
826{
827	struct ifid ifh;
828	struct iso_node *ip = VTOI(ap->a_vp);
829
830	ifh.ifid_len = sizeof(struct ifid);
831
832	ifh.ifid_ino = ip->i_number;
833	ifh.ifid_start = ip->iso_start;
834	/*
835	 * This intentionally uses sizeof(ifh) in order to not copy stack
836	 * garbage on ILP32.
837	 */
838	memcpy(ap->a_fhp, &ifh, sizeof(ifh));
839
840#ifdef	ISOFS_DBG
841	printf("vptofh: ino %jd, start %ld\n",
842	    (uintmax_t)ifh.ifid_ino, ifh.ifid_start);
843#endif
844
845	return (0);
846}
847
848SYSCTL_NODE(_vfs, OID_AUTO, cd9660, CTLFLAG_RW, 0, "cd9660 filesystem");
849static int use_buf_pager = 1;
850SYSCTL_INT(_vfs_cd9660, OID_AUTO, use_buf_pager, CTLFLAG_RWTUN,
851    &use_buf_pager, 0,
852    "Use buffer pager instead of bmap");
853
854static daddr_t
855cd9660_gbp_getblkno(struct vnode *vp, vm_ooffset_t off)
856{
857
858	return (lblkno(VTOI(vp)->i_mnt, off));
859}
860
861static int
862cd9660_gbp_getblksz(struct vnode *vp, daddr_t lbn)
863{
864	struct iso_node *ip;
865
866	ip = VTOI(vp);
867	return (blksize(ip->i_mnt, ip, lbn));
868}
869
870static int
871cd9660_getpages(struct vop_getpages_args *ap)
872{
873	struct vnode *vp;
874
875	vp = ap->a_vp;
876	if (vp->v_type == VCHR || vp->v_type == VBLK)
877		return (EOPNOTSUPP);
878
879	if (use_buf_pager)
880		return (vfs_bio_getpages(vp, ap->a_m, ap->a_count,
881		    ap->a_rbehind, ap->a_rahead, cd9660_gbp_getblkno,
882		    cd9660_gbp_getblksz));
883	return (vnode_pager_generic_getpages(vp, ap->a_m, ap->a_count,
884	    ap->a_rbehind, ap->a_rahead, NULL, NULL));
885}
886
887/*
888 * Global vfs data structures for cd9660
889 */
890struct vop_vector cd9660_vnodeops = {
891	.vop_default =		&default_vnodeops,
892	.vop_open =		cd9660_open,
893	.vop_access =		cd9660_access,
894	.vop_bmap =		cd9660_bmap,
895	.vop_cachedlookup =	cd9660_lookup,
896	.vop_getattr =		cd9660_getattr,
897	.vop_inactive =		cd9660_inactive,
898	.vop_ioctl =		cd9660_ioctl,
899	.vop_lookup =		vfs_cache_lookup,
900	.vop_pathconf =		cd9660_pathconf,
901	.vop_read =		cd9660_read,
902	.vop_readdir =		cd9660_readdir,
903	.vop_readlink =		cd9660_readlink,
904	.vop_reclaim =		cd9660_reclaim,
905	.vop_setattr =		cd9660_setattr,
906	.vop_strategy =		cd9660_strategy,
907	.vop_vptofh =		cd9660_vptofh,
908	.vop_getpages =		cd9660_getpages,
909};
910
911/*
912 * Special device vnode ops
913 */
914
915struct vop_vector cd9660_fifoops = {
916	.vop_default =		&fifo_specops,
917	.vop_access =		cd9660_access,
918	.vop_getattr =		cd9660_getattr,
919	.vop_inactive =		cd9660_inactive,
920	.vop_reclaim =		cd9660_reclaim,
921	.vop_setattr =		cd9660_setattr,
922	.vop_vptofh =		cd9660_vptofh,
923};
924