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