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