cd9660_vnops.c revision 29653
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 * $Id: cd9660_vnops.c,v 1.38 1997/09/14 02:57:43 peter Exp $
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/sysctl.h>
48#include <sys/buf.h>
49#include <sys/mount.h>
50#include <sys/vnode.h>
51#include <miscfs/specfs/specdev.h>
52#include <miscfs/fifofs/fifo.h>
53#include <sys/malloc.h>
54#include <sys/dirent.h>
55#include <sys/unistd.h>
56
57#include <isofs/cd9660/iso.h>
58#include <isofs/cd9660/cd9660_node.h>
59#include <isofs/cd9660/iso_rrip.h>
60
61static int cd9660_setattr __P((struct vop_setattr_args *));
62static int cd9660_open __P((struct vop_open_args *));
63static int cd9660_close __P((struct vop_close_args *));
64static int cd9660_access __P((struct vop_access_args *));
65static int cd9660_getattr __P((struct vop_getattr_args *));
66static int cd9660_read __P((struct vop_read_args *));
67static int cd9660_ioctl __P((struct vop_ioctl_args *));
68static int cd9660_mmap __P((struct vop_mmap_args *));
69static int cd9660_seek __P((struct vop_seek_args *));
70struct isoreaddir;
71static int iso_uiodir __P((struct isoreaddir *idp, struct dirent *dp,
72			   off_t off));
73static int iso_shipdir __P((struct isoreaddir *idp));
74static int cd9660_readdir __P((struct vop_readdir_args *));
75static int cd9660_readlink __P((struct vop_readlink_args *ap));
76static int cd9660_abortop __P((struct vop_abortop_args *));
77static int cd9660_lock __P((struct vop_lock_args *));
78static int cd9660_unlock __P((struct vop_unlock_args *));
79static int cd9660_strategy __P((struct vop_strategy_args *));
80static int cd9660_print __P((struct vop_print_args *));
81static int cd9660_islocked __P((struct vop_islocked_args *));
82
83/*
84 * Sysctl values for the cd9660 filesystem.
85 */
86#define	CD9660_CLUSTERREAD	1	/* cluster reading enabled */
87#define	CD9660_MAXID		2	/* number of valid cd9660 ids */
88
89#define	CD9660_NAMES { \
90	{0, 0}, \
91	{ "doclusterread", CTLTYPE_INT}, \
92}
93
94/*
95 * Setattr call. Only allowed for block and character special devices.
96 */
97int
98cd9660_setattr(ap)
99	struct vop_setattr_args /* {
100		struct vnodeop_desc *a_desc;
101		struct vnode *a_vp;
102		struct vattr *a_vap;
103		struct ucred *a_cred;
104		struct proc *a_p;
105	} */ *ap;
106{
107	struct vnode *vp = ap->a_vp;
108	struct vattr *vap = ap->a_vap;
109
110  	if (vap->va_flags != (u_long)VNOVAL || vap->va_uid != (uid_t)VNOVAL ||
111	    vap->va_gid != (gid_t)VNOVAL || vap->va_atime.tv_sec != VNOVAL ||
112	    vap->va_mtime.tv_sec != VNOVAL || vap->va_mode != (mode_t)VNOVAL)
113		return (EROFS);
114	if (vap->va_size != (u_quad_t)VNOVAL) {
115 		switch (vp->v_type) {
116 		case VDIR:
117 			return (EISDIR);
118		case VLNK:
119		case VREG:
120			return (EROFS);
121 		case VCHR:
122 		case VBLK:
123 		case VSOCK:
124 		case VFIFO:
125			return (0);
126		}
127	}
128	return (0);
129}
130
131/*
132 * Open called.
133 *
134 * Nothing to do.
135 */
136/* ARGSUSED */
137static int
138cd9660_open(ap)
139	struct vop_open_args /* {
140		struct vnode *a_vp;
141		int  a_mode;
142		struct ucred *a_cred;
143		struct proc *a_p;
144	} */ *ap;
145{
146	return (0);
147}
148
149/*
150 * Close called
151 *
152 * Update the times on the inode on writeable file systems.
153 */
154/* ARGSUSED */
155static int
156cd9660_close(ap)
157	struct vop_close_args /* {
158		struct vnode *a_vp;
159		int  a_fflag;
160		struct ucred *a_cred;
161		struct proc *a_p;
162	} */ *ap;
163{
164	return (0);
165}
166
167/*
168 * Check mode permission on inode pointer. Mode is READ, WRITE or EXEC.
169 * The mode is shifted to select the owner/group/other fields. The
170 * super user is granted all permissions.
171 */
172/* ARGSUSED */
173static int
174cd9660_access(ap)
175	struct vop_access_args /* {
176		struct vnode *a_vp;
177		int  a_mode;
178		struct ucred *a_cred;
179		struct proc *a_p;
180	} */ *ap;
181{
182	struct vnode *vp = ap->a_vp;
183	struct iso_node *ip = VTOI(vp);
184	struct ucred *cred = ap->a_cred;
185	mode_t mask, mode = ap->a_mode;
186	gid_t *gp;
187	int i;
188
189	/*
190	 * Disallow write attempts unless the file is a socket,
191	 * fifo, or a block or character device resident on the
192	 * file system.
193	 */
194	if (mode & VWRITE) {
195		switch (vp->v_type) {
196		case VDIR:
197		case VLNK:
198		case VREG:
199			return (EROFS);
200		}
201	}
202
203	/* User id 0 always gets access. */
204	if (cred->cr_uid == 0)
205		return (0);
206
207	mask = 0;
208
209	/* Otherwise, check the owner. */
210	if (cred->cr_uid == ip->inode.iso_uid) {
211		if (mode & VEXEC)
212			mask |= S_IXUSR;
213		if (mode & VREAD)
214			mask |= S_IRUSR;
215		if (mode & VWRITE)
216			mask |= S_IWUSR;
217		return ((ip->inode.iso_mode & mask) == mask ? 0 : EACCES);
218	}
219
220	/* Otherwise, check the groups. */
221	for (i = 0, gp = cred->cr_groups; i < cred->cr_ngroups; i++, gp++)
222		if (ip->inode.iso_gid == *gp) {
223			if (mode & VEXEC)
224				mask |= S_IXGRP;
225			if (mode & VREAD)
226				mask |= S_IRGRP;
227			if (mode & VWRITE)
228				mask |= S_IWGRP;
229			return ((ip->inode.iso_mode & mask) == mask ?
230			    0 : EACCES);
231		}
232
233	/* Otherwise, check everyone else. */
234	if (mode & VEXEC)
235		mask |= S_IXOTH;
236	if (mode & VREAD)
237		mask |= S_IROTH;
238	if (mode & VWRITE)
239		mask |= S_IWOTH;
240	return ((ip->inode.iso_mode & mask) == mask ? 0 : EACCES);
241}
242
243static int
244cd9660_getattr(ap)
245	struct vop_getattr_args /* {
246		struct vnode *a_vp;
247		struct vattr *a_vap;
248		struct ucred *a_cred;
249		struct proc *a_p;
250	} */ *ap;
251
252{
253	struct vnode *vp = ap->a_vp;
254	register struct vattr *vap = ap->a_vap;
255	register struct iso_node *ip = VTOI(vp);
256
257	vap->va_fsid	= ip->i_dev;
258	vap->va_fileid	= ip->i_number;
259
260	vap->va_mode	= ip->inode.iso_mode;
261	vap->va_nlink	= ip->inode.iso_links;
262	vap->va_uid	= ip->inode.iso_uid;
263	vap->va_gid	= ip->inode.iso_gid;
264	vap->va_atime	= ip->inode.iso_atime;
265	vap->va_mtime	= ip->inode.iso_mtime;
266	vap->va_ctime	= ip->inode.iso_ctime;
267	vap->va_rdev	= ip->inode.iso_rdev;
268
269	vap->va_size	= (u_quad_t) ip->i_size;
270	if (ip->i_size == 0 && (vap->va_mode & S_IFMT) == S_IFLNK) {
271		struct vop_readlink_args rdlnk;
272		struct iovec aiov;
273		struct uio auio;
274		char *cp;
275
276		MALLOC(cp, char *, MAXPATHLEN, M_TEMP, M_WAITOK);
277		aiov.iov_base = cp;
278		aiov.iov_len = MAXPATHLEN;
279		auio.uio_iov = &aiov;
280		auio.uio_iovcnt = 1;
281		auio.uio_offset = 0;
282		auio.uio_rw = UIO_READ;
283		auio.uio_segflg = UIO_SYSSPACE;
284		auio.uio_procp = ap->a_p;
285		auio.uio_resid = MAXPATHLEN;
286		rdlnk.a_uio = &auio;
287		rdlnk.a_vp = ap->a_vp;
288		rdlnk.a_cred = ap->a_cred;
289		if (cd9660_readlink(&rdlnk) == 0)
290			vap->va_size = MAXPATHLEN - auio.uio_resid;
291		FREE(cp, M_TEMP);
292	}
293	vap->va_flags	= 0;
294	vap->va_gen = 1;
295	vap->va_blocksize = ip->i_mnt->logical_block_size;
296	vap->va_bytes	= (u_quad_t) ip->i_size;
297	vap->va_type	= vp->v_type;
298	vap->va_filerev	= 0;
299	return (0);
300}
301
302static int	cd9660_doclusterread = 1;
303SYSCTL_NODE(_vfs, MOUNT_CD9660, cd9660, CTLFLAG_RW, 0, "CD9660 filesystem");
304SYSCTL_INT(_vfs_cd9660, CD9660_CLUSTERREAD, doclusterread,
305		   CTLFLAG_RW, &cd9660_doclusterread, 0, "");
306
307/*
308 * Vnode op for reading.
309 */
310static int
311cd9660_read(ap)
312	struct vop_read_args /* {
313		struct vnode *a_vp;
314		struct uio *a_uio;
315		int a_ioflag;
316		struct ucred *a_cred;
317	} */ *ap;
318{
319	struct vnode *vp = ap->a_vp;
320	register struct uio *uio = ap->a_uio;
321	register struct iso_node *ip = VTOI(vp);
322	register struct iso_mnt *imp;
323	struct buf *bp;
324	daddr_t lbn, rablock;
325	off_t diff;
326	int rasize, error = 0;
327	long size, n, on;
328
329	if (uio->uio_resid == 0)
330		return (0);
331	if (uio->uio_offset < 0)
332		return (EINVAL);
333	ip->i_flag |= IN_ACCESS;
334	imp = ip->i_mnt;
335	do {
336		lbn = lblkno(imp, uio->uio_offset);
337		on = blkoff(imp, uio->uio_offset);
338		n = min((u_int)(imp->logical_block_size - on),
339			uio->uio_resid);
340		diff = (off_t)ip->i_size - uio->uio_offset;
341		if (diff <= 0)
342			return (0);
343		if (diff < n)
344			n = diff;
345		size = blksize(imp, ip, lbn);
346		rablock = lbn + 1;
347		if (cd9660_doclusterread) {
348			if (lblktosize(imp, rablock) <= ip->i_size)
349				error = cluster_read(vp, (off_t)ip->i_size,
350				         lbn, size, NOCRED, uio->uio_resid,
351					 (ap->a_ioflag >> 16), &bp);
352			else
353				error = bread(vp, lbn, size, NOCRED, &bp);
354		} else {
355			if (vp->v_lastr + 1 == lbn &&
356			    lblktosize(imp, rablock) < ip->i_size) {
357				rasize = blksize(imp, ip, rablock);
358				error = breadn(vp, lbn, size, &rablock,
359					       &rasize, 1, NOCRED, &bp);
360			} else
361				error = bread(vp, lbn, size, NOCRED, &bp);
362		}
363		vp->v_lastr = lbn;
364		n = min(n, size - bp->b_resid);
365		if (error) {
366			brelse(bp);
367			return (error);
368		}
369
370		error = uiomove(bp->b_data + on, (int)n, uio);
371		brelse(bp);
372	} while (error == 0 && uio->uio_resid > 0 && n != 0);
373	return (error);
374}
375
376/* ARGSUSED */
377static int
378cd9660_ioctl(ap)
379	struct vop_ioctl_args /* {
380		struct vnode *a_vp;
381		u_long a_command;
382		caddr_t  a_data;
383		int  a_fflag;
384		struct ucred *a_cred;
385		struct proc *a_p;
386	} */ *ap;
387{
388	printf("You did ioctl for isofs !!\n");
389	return (ENOTTY);
390}
391
392/*
393 * Mmap a file
394 *
395 * NB Currently unsupported.
396 */
397/* ARGSUSED */
398static int
399cd9660_mmap(ap)
400	struct vop_mmap_args /* {
401		struct vnode *a_vp;
402		int  a_fflags;
403		struct ucred *a_cred;
404		struct proc *a_p;
405	} */ *ap;
406{
407
408	return (EINVAL);
409}
410
411/*
412 * Seek on a file
413 *
414 * Nothing to do, so just return.
415 */
416/* ARGSUSED */
417static int
418cd9660_seek(ap)
419	struct vop_seek_args /* {
420		struct vnode *a_vp;
421		off_t  a_oldoff;
422		off_t  a_newoff;
423		struct ucred *a_cred;
424	} */ *ap;
425{
426
427	return (0);
428}
429
430/*
431 * Structure for reading directories
432 */
433struct isoreaddir {
434	struct dirent saveent;
435	struct dirent assocent;
436	struct dirent current;
437	off_t saveoff;
438	off_t assocoff;
439	off_t curroff;
440	struct uio *uio;
441	off_t uio_off;
442	int eofflag;
443	u_long *cookies;
444	int ncookies;
445};
446
447int
448iso_uiodir(idp,dp,off)
449	struct isoreaddir *idp;
450	struct dirent *dp;
451	off_t off;
452{
453	int error;
454
455	dp->d_name[dp->d_namlen] = 0;
456	dp->d_reclen = GENERIC_DIRSIZ(dp);
457
458	if (idp->uio->uio_resid < dp->d_reclen) {
459		idp->eofflag = 0;
460		return (-1);
461	}
462
463	if (idp->cookies) {
464		if (idp->ncookies <= 0) {
465			idp->eofflag = 0;
466			return (-1);
467		}
468
469		*idp->cookies++ = off;
470		--idp->ncookies;
471	}
472
473	if (error = uiomove((caddr_t) dp,dp->d_reclen,idp->uio))
474		return (error);
475	idp->uio_off = off;
476	return (0);
477}
478
479int
480iso_shipdir(idp)
481	struct isoreaddir *idp;
482{
483	struct dirent *dp;
484	int cl, sl, assoc;
485	int error;
486	char *cname, *sname;
487
488	cl = idp->current.d_namlen;
489	cname = idp->current.d_name;
490assoc = (cl > 1) && (*cname == ASSOCCHAR);
491	if (assoc) {
492		cl--;
493		cname++;
494	}
495
496	dp = &idp->saveent;
497	sname = dp->d_name;
498	if (!(sl = dp->d_namlen)) {
499		dp = &idp->assocent;
500		sname = dp->d_name + 1;
501		sl = dp->d_namlen - 1;
502	}
503	if (sl > 0) {
504		if (sl != cl
505		    || bcmp(sname,cname,sl)) {
506			if (idp->assocent.d_namlen) {
507				if (error = iso_uiodir(idp,&idp->assocent,idp->assocoff))
508					return (error);
509				idp->assocent.d_namlen = 0;
510			}
511			if (idp->saveent.d_namlen) {
512				if (error = iso_uiodir(idp,&idp->saveent,idp->saveoff))
513					return (error);
514				idp->saveent.d_namlen = 0;
515			}
516		}
517	}
518	idp->current.d_reclen = GENERIC_DIRSIZ(&idp->current);
519	if (assoc) {
520		idp->assocoff = idp->curroff;
521		bcopy(&idp->current,&idp->assocent,idp->current.d_reclen);
522	} else {
523		idp->saveoff = idp->curroff;
524		bcopy(&idp->current,&idp->saveent,idp->current.d_reclen);
525	}
526	return (0);
527}
528
529/*
530 * Vnode op for readdir
531 */
532static int
533cd9660_readdir(ap)
534	struct vop_readdir_args /* {
535		struct vnode *a_vp;
536		struct uio *a_uio;
537		struct ucred *a_cred;
538		int *a_eofflag;
539		int *a_ncookies;
540		u_long *a_cookies;
541	} */ *ap;
542{
543	register struct uio *uio = ap->a_uio;
544	struct isoreaddir *idp;
545	struct vnode *vdp = ap->a_vp;
546	struct iso_node *dp;
547	struct iso_mnt *imp;
548	struct buf *bp = NULL;
549	struct iso_directory_record *ep;
550	int entryoffsetinblock;
551	doff_t endsearch;
552	u_long bmask;
553	int error = 0;
554	int reclen;
555	u_short namelen;
556	int ncookies = 0;
557	u_long *cookies = NULL;
558
559	dp = VTOI(vdp);
560	imp = dp->i_mnt;
561	bmask = imp->im_bmask;
562
563	MALLOC(idp, struct isoreaddir *, sizeof(*idp), M_TEMP, M_WAITOK);
564	idp->saveent.d_namlen = idp->assocent.d_namlen = 0;
565	/*
566	 * XXX
567	 * Is it worth trying to figure out the type?
568	 */
569	idp->saveent.d_type = idp->assocent.d_type = idp->current.d_type =
570	    DT_UNKNOWN;
571	idp->uio = uio;
572	if (ap->a_ncookies == NULL) {
573		idp->cookies = NULL;
574	} else {
575		/*
576		 * Guess the number of cookies needed.
577		 */
578		ncookies = uio->uio_resid / 16;
579		MALLOC(cookies, u_long *, ncookies * sizeof(u_int), M_TEMP,
580		    M_WAITOK);
581		idp->cookies = cookies;
582		idp->ncookies = ncookies;
583	}
584	idp->eofflag = 1;
585	idp->curroff = uio->uio_offset;
586
587	if ((entryoffsetinblock = idp->curroff & bmask) &&
588	    (error = VOP_BLKATOFF(vdp, (off_t)idp->curroff, NULL, &bp))) {
589		FREE(idp, M_TEMP);
590		return (error);
591	}
592	endsearch = dp->i_size;
593
594	while (idp->curroff < endsearch) {
595		/*
596		 * If offset is on a block boundary,
597		 * read the next directory block.
598		 * Release previous if it exists.
599		 */
600		if ((idp->curroff & bmask) == 0) {
601			if (bp != NULL)
602				brelse(bp);
603			if (error =
604			    VOP_BLKATOFF(vdp, (off_t)idp->curroff, NULL, &bp))
605				break;
606			entryoffsetinblock = 0;
607		}
608		/*
609		 * Get pointer to next entry.
610		 */
611		ep = (struct iso_directory_record *)
612			((char *)bp->b_data + entryoffsetinblock);
613
614		reclen = isonum_711(ep->length);
615		if (reclen == 0) {
616			/* skip to next block, if any */
617			idp->curroff =
618			    (idp->curroff & ~bmask) + imp->logical_block_size;
619			continue;
620		}
621
622		if (reclen < ISO_DIRECTORY_RECORD_SIZE) {
623			error = EINVAL;
624			/* illegal entry, stop */
625			break;
626		}
627
628		if (entryoffsetinblock + reclen > imp->logical_block_size) {
629			error = EINVAL;
630			/* illegal directory, so stop looking */
631			break;
632		}
633
634		idp->current.d_namlen = isonum_711(ep->name_len);
635
636		if (reclen < ISO_DIRECTORY_RECORD_SIZE + idp->current.d_namlen) {
637			error = EINVAL;
638			/* illegal entry, stop */
639			break;
640		}
641
642		if (isonum_711(ep->flags)&2)
643			idp->current.d_fileno = isodirino(ep, imp);
644		else
645			idp->current.d_fileno = dbtob(bp->b_blkno) +
646				entryoffsetinblock;
647
648		idp->curroff += reclen;
649
650		switch (imp->iso_ftype) {
651		case ISO_FTYPE_RRIP:
652			cd9660_rrip_getname(ep,idp->current.d_name, &namelen,
653					   &idp->current.d_fileno,imp);
654			idp->current.d_namlen = (u_char)namelen;
655			if (idp->current.d_namlen)
656				error = iso_uiodir(idp,&idp->current,idp->curroff);
657			break;
658		default: /* ISO_FTYPE_DEFAULT || ISO_FTYPE_9660 || ISO_FTYPE_HIGH_SIERRA*/
659			strcpy(idp->current.d_name,"..");
660			switch (ep->name[0]) {
661			case 0:
662				idp->current.d_namlen = 1;
663				error = iso_uiodir(idp,&idp->current,idp->curroff);
664				break;
665			case 1:
666				idp->current.d_namlen = 2;
667				error = iso_uiodir(idp,&idp->current,idp->curroff);
668				break;
669			default:
670				isofntrans(ep->name,idp->current.d_namlen,
671					   idp->current.d_name, &namelen,
672					   imp->iso_ftype == ISO_FTYPE_9660,
673					   isonum_711(ep->flags)&4);
674				idp->current.d_namlen = (u_char)namelen;
675				if (imp->iso_ftype == ISO_FTYPE_DEFAULT)
676					error = iso_shipdir(idp);
677				else
678					error = iso_uiodir(idp,&idp->current,idp->curroff);
679				break;
680			}
681		}
682		if (error)
683			break;
684
685		entryoffsetinblock += reclen;
686	}
687
688	if (!error && imp->iso_ftype == ISO_FTYPE_DEFAULT) {
689		idp->current.d_namlen = 0;
690		error = iso_shipdir(idp);
691	}
692	if (error < 0)
693		error = 0;
694
695	if (ap->a_ncookies != NULL) {
696		if (error)
697			free(cookies, M_TEMP);
698		else {
699			/*
700			 * Work out the number of cookies actually used.
701			 */
702			*ap->a_ncookies = ncookies - idp->ncookies;
703			*ap->a_cookies = cookies;
704		}
705	}
706
707	if (bp)
708		brelse (bp);
709
710	uio->uio_offset = idp->uio_off;
711	*ap->a_eofflag = idp->eofflag;
712
713	FREE(idp, M_TEMP);
714
715	return (error);
716}
717
718/*
719 * Return target name of a symbolic link
720 * Shouldn't we get the parent vnode and read the data from there?
721 * This could eventually result in deadlocks in cd9660_lookup.
722 * But otherwise the block read here is in the block buffer two times.
723 */
724typedef struct iso_directory_record ISODIR;
725typedef struct iso_node		    ISONODE;
726typedef struct iso_mnt		    ISOMNT;
727static int
728cd9660_readlink(ap)
729	struct vop_readlink_args /* {
730		struct vnode *a_vp;
731		struct uio *a_uio;
732		struct ucred *a_cred;
733	} */ *ap;
734{
735	ISONODE	*ip;
736	ISODIR	*dirp;
737	ISOMNT	*imp;
738	struct	buf *bp;
739	struct	uio *uio;
740	u_short	symlen;
741	int	error;
742	char	*symname;
743
744	ip  = VTOI(ap->a_vp);
745	imp = ip->i_mnt;
746	uio = ap->a_uio;
747
748	if (imp->iso_ftype != ISO_FTYPE_RRIP)
749		return (EINVAL);
750
751	/*
752	 * Get parents directory record block that this inode included.
753	 */
754	error = bread(imp->im_devvp,
755		      (ip->i_number >> imp->im_bshift) <<
756		      (imp->im_bshift - DEV_BSHIFT),
757		      imp->logical_block_size, NOCRED, &bp);
758	if (error) {
759		brelse(bp);
760		return (EINVAL);
761	}
762
763	/*
764	 * Setup the directory pointer for this inode
765	 */
766	dirp = (ISODIR *)(bp->b_data + (ip->i_number & imp->im_bmask));
767
768	/*
769	 * Just make sure, we have a right one....
770	 *   1: Check not cross boundary on block
771	 */
772	if ((ip->i_number & imp->im_bmask) + isonum_711(dirp->length)
773	    > (unsigned)imp->logical_block_size) {
774		brelse(bp);
775		return (EINVAL);
776	}
777
778	/*
779	 * Now get a buffer
780	 * Abuse a namei buffer for now.
781	 */
782	if (uio->uio_segflg == UIO_SYSSPACE)
783		symname = uio->uio_iov->iov_base;
784	else
785		symname = zalloc(namei_zone);
786
787	/*
788	 * Ok, we just gathering a symbolic name in SL record.
789	 */
790	if (cd9660_rrip_getsymname(dirp, symname, &symlen, imp) == 0) {
791		if (uio->uio_segflg != UIO_SYSSPACE)
792			zfree(namei_zone, symname);
793		brelse(bp);
794		return (EINVAL);
795	}
796	/*
797	 * Don't forget before you leave from home ;-)
798	 */
799	brelse(bp);
800
801	/*
802	 * return with the symbolic name to caller's.
803	 */
804	if (uio->uio_segflg != UIO_SYSSPACE) {
805		error = uiomove(symname, symlen, uio);
806		zfree(namei_zone, symname);
807		return (error);
808	}
809	uio->uio_resid -= symlen;
810	uio->uio_iov->iov_base += symlen;
811	uio->uio_iov->iov_len -= symlen;
812	return (0);
813}
814
815/*
816 * Ufs abort op, called after namei() when a CREATE/DELETE isn't actually
817 * done. If a buffer has been saved in anticipation of a CREATE, delete it.
818 */
819static int
820cd9660_abortop(ap)
821	struct vop_abortop_args /* {
822		struct vnode *a_dvp;
823		struct componentname *a_cnp;
824	} */ *ap;
825{
826	if ((ap->a_cnp->cn_flags & (HASBUF | SAVESTART)) == HASBUF)
827		zfree(namei_zone, ap->a_cnp->cn_pnbuf);
828	return (0);
829}
830
831/*
832 * Lock an inode.
833 */
834static int
835cd9660_lock(ap)
836	struct vop_lock_args /* {
837		struct vnode *a_vp;
838		int a_flags;
839		struct proc *a_p;
840	} */ *ap;
841{
842	struct vnode *vp = ap->a_vp;
843
844	return (lockmgr(&VTOI(vp)->i_lock, ap->a_flags, &vp->v_interlock,
845		ap->a_p));
846}
847
848/*
849 * Unlock an inode.
850 */
851static int
852cd9660_unlock(ap)
853	struct vop_unlock_args /* {
854		struct vnode *a_vp;
855		int a_flags;
856		struct proc *a_p;
857	} */ *ap;
858{
859	struct vnode *vp = ap->a_vp;
860
861	return (lockmgr(&VTOI(vp)->i_lock, ap->a_flags | LK_RELEASE,
862		&vp->v_interlock, ap->a_p));
863}
864
865/*
866 * Calculate the logical to physical mapping if not done already,
867 * then call the device strategy routine.
868 */
869static int
870cd9660_strategy(ap)
871	struct vop_strategy_args /* {
872		struct buf *a_bp;
873	} */ *ap;
874{
875	register struct buf *bp = ap->a_bp;
876	register struct vnode *vp = bp->b_vp;
877	register struct iso_node *ip;
878	int error;
879
880	ip = VTOI(vp);
881	if (vp->v_type == VBLK || vp->v_type == VCHR)
882		panic("cd9660_strategy: spec");
883	if (bp->b_blkno == bp->b_lblkno) {
884		if ((error =
885		    VOP_BMAP(vp, bp->b_lblkno, NULL, &bp->b_blkno, NULL, NULL))) {
886			bp->b_error = error;
887			bp->b_flags |= B_ERROR;
888			biodone(bp);
889			return (error);
890		}
891		if ((long)bp->b_blkno == -1)
892			clrbuf(bp);
893	}
894	if ((long)bp->b_blkno == -1) {
895		biodone(bp);
896		return (0);
897	}
898	vp = ip->i_devvp;
899	bp->b_dev = vp->v_rdev;
900	VOCALL (vp->v_op, VOFFSET(vop_strategy), ap);
901	return (0);
902}
903
904/*
905 * Print out the contents of an inode.
906 */
907static int
908cd9660_print(ap)
909	struct vop_print_args /* {
910		struct vnode *a_vp;
911	} */ *ap;
912{
913
914	printf("tag VT_ISOFS, isofs vnode\n");
915	return (0);
916}
917
918/*
919 * Check for a locked inode.
920 */
921int
922cd9660_islocked(ap)
923	struct vop_islocked_args /* {
924		struct vnode *a_vp;
925	} */ *ap;
926{
927
928	return (lockstatus(&VTOI(ap->a_vp)->i_lock));
929}
930
931/*
932 * Return POSIX pathconf information applicable to cd9660 filesystems.
933 */
934int
935cd9660_pathconf(ap)
936	struct vop_pathconf_args /* {
937		struct vnode *a_vp;
938		int a_name;
939		register_t *a_retval;
940	} */ *ap;
941{
942
943	switch (ap->a_name) {
944	case _PC_LINK_MAX:
945		*ap->a_retval = 1;
946		return (0);
947	case _PC_NAME_MAX:
948		if (VTOI(ap->a_vp)->i_mnt->iso_ftype == ISO_FTYPE_RRIP)
949			*ap->a_retval = NAME_MAX;
950		else
951			*ap->a_retval = 37;
952		return (0);
953	case _PC_PATH_MAX:
954		*ap->a_retval = PATH_MAX;
955		return (0);
956	case _PC_PIPE_BUF:
957		*ap->a_retval = PIPE_BUF;
958		return (0);
959	case _PC_CHOWN_RESTRICTED:
960		*ap->a_retval = 1;
961		return (0);
962	case _PC_NO_TRUNC:
963		*ap->a_retval = 1;
964		return (0);
965	default:
966		return (EINVAL);
967	}
968	/* NOTREACHED */
969}
970
971/*
972 * Global vfs data structures for isofs
973 */
974#define cd9660_create \
975	((int (*) __P((struct  vop_create_args *)))eopnotsupp)
976#define cd9660_mknod ((int (*) __P((struct  vop_mknod_args *)))eopnotsupp)
977#define cd9660_write ((int (*) __P((struct  vop_write_args *)))eopnotsupp)
978#ifdef NFS
979#define	 cd9660_lease_check lease_check
980#else
981#define	 cd9660_lease_check ((int (*) __P((struct vop_lease_args *)))nullop)
982#endif
983#define cd9660_poll vop_nopoll
984#define cd9660_fsync ((int (*) __P((struct  vop_fsync_args *)))nullop)
985#define cd9660_remove \
986	((int (*) __P((struct  vop_remove_args *)))eopnotsupp)
987#define cd9660_link ((int (*) __P((struct  vop_link_args *)))eopnotsupp)
988#define cd9660_rename \
989	((int (*) __P((struct  vop_rename_args *)))eopnotsupp)
990#define cd9660_mkdir ((int (*) __P((struct  vop_mkdir_args *)))eopnotsupp)
991#define cd9660_rmdir ((int (*) __P((struct  vop_rmdir_args *)))eopnotsupp)
992#define cd9660_symlink \
993	((int (*) __P((struct vop_symlink_args *)))eopnotsupp)
994#define cd9660_advlock \
995	((int (*) __P((struct vop_advlock_args *)))eopnotsupp)
996#define cd9660_valloc ((int(*) __P(( \
997		struct vnode *pvp, \
998		int mode, \
999		struct ucred *cred, \
1000		struct vnode **vpp))) eopnotsupp)
1001#define cd9660_vfree ((int (*) __P((struct  vop_vfree_args *)))eopnotsupp)
1002#define cd9660_truncate \
1003	((int (*) __P((struct  vop_truncate_args *)))eopnotsupp)
1004#define cd9660_update \
1005	((int (*) __P((struct  vop_update_args *)))eopnotsupp)
1006#define cd9660_bwrite \
1007	((int (*) __P((struct  vop_bwrite_args *)))eopnotsupp)
1008
1009/*
1010 * Global vfs data structures for cd9660
1011 */
1012vop_t **cd9660_vnodeop_p;
1013struct vnodeopv_entry_desc cd9660_vnodeop_entries[] = {
1014
1015	{ &vop_default_desc, (vop_t *)vn_default_error },
1016	{ &vop_lookup_desc, (vop_t *)vfs_cache_lookup },	/* lookup */
1017	{ &vop_cachedlookup_desc, (vop_t *)cd9660_lookup },	/* lookup */
1018	{ &vop_create_desc, (vop_t *)cd9660_create },	/* create */
1019/* XXX: vop_whiteout */
1020	{ &vop_mknod_desc, (vop_t *)cd9660_mknod },	/* mknod */
1021	{ &vop_open_desc, (vop_t *)cd9660_open },	/* open */
1022	{ &vop_close_desc, (vop_t *)cd9660_close },	/* close */
1023	{ &vop_access_desc, (vop_t *)cd9660_access },	/* access */
1024	{ &vop_getattr_desc, (vop_t *)cd9660_getattr },	/* getattr */
1025	{ &vop_setattr_desc, (vop_t *)cd9660_setattr },	/* setattr */
1026	{ &vop_read_desc, (vop_t *)cd9660_read },	/* read */
1027	{ &vop_write_desc, (vop_t *)cd9660_write },	/* write */
1028	{ &vop_lease_desc, (vop_t *)cd9660_lease_check },/* lease */
1029	{ &vop_ioctl_desc, (vop_t *)cd9660_ioctl },	/* ioctl */
1030	{ &vop_poll_desc, (vop_t *)cd9660_poll },	/* poll */
1031	{ &vop_revoke_desc, (vop_t *)cd9660_revoke },	/* revoke */
1032	{ &vop_mmap_desc, (vop_t *)cd9660_mmap },	/* mmap */
1033	{ &vop_fsync_desc, (vop_t *)cd9660_fsync },	/* fsync */
1034	{ &vop_seek_desc, (vop_t *)cd9660_seek },	/* seek */
1035	{ &vop_remove_desc, (vop_t *)cd9660_remove },	/* remove */
1036	{ &vop_link_desc, (vop_t *)cd9660_link },	/* link */
1037	{ &vop_rename_desc, (vop_t *)cd9660_rename },	/* rename */
1038	{ &vop_mkdir_desc, (vop_t *)cd9660_mkdir },	/* mkdir */
1039	{ &vop_rmdir_desc, (vop_t *)cd9660_rmdir },	/* rmdir */
1040	{ &vop_symlink_desc, (vop_t *)cd9660_symlink },	/* symlink */
1041	{ &vop_readdir_desc, (vop_t *)cd9660_readdir },	/* readdir */
1042	{ &vop_readlink_desc, (vop_t *)cd9660_readlink },/* readlink */
1043	{ &vop_abortop_desc, (vop_t *)cd9660_abortop },	/* abortop */
1044	{ &vop_inactive_desc, (vop_t *)cd9660_inactive },/* inactive */
1045	{ &vop_reclaim_desc, (vop_t *)cd9660_reclaim },	/* reclaim */
1046	{ &vop_lock_desc, (vop_t *)cd9660_lock },	/* lock */
1047	{ &vop_unlock_desc, (vop_t *)cd9660_unlock },	/* unlock */
1048	{ &vop_bmap_desc, (vop_t *)cd9660_bmap },	/* bmap */
1049	{ &vop_strategy_desc, (vop_t *)cd9660_strategy },/* strategy */
1050	{ &vop_print_desc, (vop_t *)cd9660_print },	/* print */
1051	{ &vop_islocked_desc, (vop_t *)cd9660_islocked },/* islocked */
1052	{ &vop_pathconf_desc, (vop_t *)cd9660_pathconf },/* pathconf */
1053	{ &vop_advlock_desc, (vop_t *)cd9660_advlock },	/* advlock */
1054	{ &vop_blkatoff_desc, (vop_t *)cd9660_blkatoff },/* blkatoff */
1055	{ &vop_valloc_desc, (vop_t *)cd9660_valloc },	/* valloc */
1056/* XXX: vop_reallocblks */
1057	{ &vop_vfree_desc, (vop_t *)cd9660_vfree },	/* vfree */
1058	{ &vop_truncate_desc, (vop_t *)cd9660_truncate },/* truncate */
1059	{ &vop_update_desc, (vop_t *)cd9660_update },	/* update */
1060/* XXX: vop_getpages */
1061/* XXX: vop_putpages */
1062	{ &vop_bwrite_desc, (vop_t *)vn_bwrite },
1063	{ NULL, NULL }
1064};
1065static struct vnodeopv_desc cd9660_vnodeop_opv_desc =
1066	{ &cd9660_vnodeop_p, cd9660_vnodeop_entries };
1067VNODEOP_SET(cd9660_vnodeop_opv_desc);
1068
1069/*
1070 * Special device vnode ops
1071 */
1072vop_t **cd9660_specop_p;
1073struct vnodeopv_entry_desc cd9660_specop_entries[] = {
1074	{ &vop_default_desc, (vop_t *)vn_default_error },
1075	{ &vop_lookup_desc, (vop_t *)spec_lookup },	/* lookup */
1076/* XXX: vop_cachedlookup */
1077	{ &vop_create_desc, (vop_t *)spec_create },	/* create */
1078/* XXX: vop_whiteout */
1079	{ &vop_mknod_desc, (vop_t *)spec_mknod },	/* mknod */
1080	{ &vop_open_desc, (vop_t *)spec_open },		/* open */
1081	{ &vop_close_desc, (vop_t *)spec_close },	/* close */
1082	{ &vop_access_desc, (vop_t *)cd9660_access },	/* access */
1083	{ &vop_getattr_desc, (vop_t *)cd9660_getattr },	/* getattr */
1084	{ &vop_setattr_desc, (vop_t *)cd9660_setattr },	/* setattr */
1085	{ &vop_read_desc, (vop_t *)spec_read },		/* read */
1086	{ &vop_write_desc, (vop_t *)spec_write },	/* write */
1087	{ &vop_lease_desc, (vop_t *)spec_lease_check },	/* lease */
1088	{ &vop_ioctl_desc, (vop_t *)spec_ioctl },	/* ioctl */
1089	{ &vop_poll_desc, (vop_t *)spec_poll },		/* poll */
1090	{ &vop_revoke_desc, (vop_t *)spec_revoke },	/* revoke */
1091	{ &vop_mmap_desc, (vop_t *)spec_mmap },		/* mmap */
1092	{ &vop_fsync_desc, (vop_t *)spec_fsync },	/* fsync */
1093	{ &vop_seek_desc, (vop_t *)spec_seek },		/* seek */
1094	{ &vop_remove_desc, (vop_t *)spec_remove },	/* remove */
1095	{ &vop_link_desc, (vop_t *)spec_link },		/* link */
1096	{ &vop_rename_desc, (vop_t *)spec_rename },	/* rename */
1097	{ &vop_mkdir_desc, (vop_t *)spec_mkdir },	/* mkdir */
1098	{ &vop_rmdir_desc, (vop_t *)spec_rmdir },	/* rmdir */
1099	{ &vop_symlink_desc, (vop_t *)spec_symlink },	/* symlink */
1100	{ &vop_readdir_desc, (vop_t *)spec_readdir },	/* readdir */
1101	{ &vop_readlink_desc, (vop_t *)spec_readlink },	/* readlink */
1102	{ &vop_abortop_desc, (vop_t *)spec_abortop },	/* abortop */
1103	{ &vop_inactive_desc, (vop_t *)cd9660_inactive },/* inactive */
1104	{ &vop_reclaim_desc, (vop_t *)cd9660_reclaim },	/* reclaim */
1105	{ &vop_lock_desc, (vop_t *)cd9660_lock },	/* lock */
1106	{ &vop_unlock_desc, (vop_t *)cd9660_unlock },	/* unlock */
1107	{ &vop_bmap_desc, (vop_t *)spec_bmap },		/* bmap */
1108	{ &vop_strategy_desc, (vop_t *)spec_strategy },	/* strategy */
1109	{ &vop_print_desc, (vop_t *)cd9660_print },	/* print */
1110	{ &vop_islocked_desc, (vop_t *)cd9660_islocked },/* islocked */
1111	{ &vop_pathconf_desc, (vop_t *)spec_pathconf },	/* pathconf */
1112	{ &vop_advlock_desc, (vop_t *)spec_advlock },	/* advlock */
1113	{ &vop_blkatoff_desc, (vop_t *)spec_blkatoff },	/* blkatoff */
1114	{ &vop_valloc_desc, (vop_t *)spec_valloc },	/* valloc */
1115/* XXX: vop_reallocblks */
1116	{ &vop_vfree_desc, (vop_t *)spec_vfree },	/* vfree */
1117	{ &vop_truncate_desc, (vop_t *)spec_truncate },	/* truncate */
1118	{ &vop_update_desc, (vop_t *)cd9660_update },	/* update */
1119/* XXX: vop_getpages */
1120/* XXX: vop_putpages */
1121	{ &vop_bwrite_desc, (vop_t *)vn_bwrite },
1122	{ NULL, NULL }
1123};
1124static struct vnodeopv_desc cd9660_specop_opv_desc =
1125	{ &cd9660_specop_p, cd9660_specop_entries };
1126VNODEOP_SET(cd9660_specop_opv_desc);
1127
1128vop_t **cd9660_fifoop_p;
1129struct vnodeopv_entry_desc cd9660_fifoop_entries[] = {
1130	{ &vop_default_desc, (vop_t *)vn_default_error },
1131	{ &vop_lookup_desc, (vop_t *)fifo_lookup },	/* lookup */
1132/* XXX: vop_cachedlookup */
1133	{ &vop_create_desc, (vop_t *)fifo_create },	/* create */
1134/* XXX: vop_whiteout */
1135	{ &vop_mknod_desc, (vop_t *)fifo_mknod },	/* mknod */
1136	{ &vop_open_desc, (vop_t *)fifo_open },		/* open */
1137	{ &vop_close_desc, (vop_t *)fifo_close },	/* close */
1138	{ &vop_access_desc, (vop_t *)cd9660_access },	/* access */
1139	{ &vop_getattr_desc, (vop_t *)cd9660_getattr },	/* getattr */
1140	{ &vop_setattr_desc, (vop_t *)cd9660_setattr },	/* setattr */
1141	{ &vop_read_desc, (vop_t *)fifo_read },		/* read */
1142	{ &vop_write_desc, (vop_t *)fifo_write },	/* write */
1143	{ &vop_lease_desc, (vop_t *)fifo_lease_check },	/* lease */
1144	{ &vop_ioctl_desc, (vop_t *)fifo_ioctl },	/* ioctl */
1145	{ &vop_poll_desc, (vop_t *)fifo_poll },		/* poll */
1146	{ &vop_revoke_desc, (vop_t *)fifo_revoke },	/* revoke */
1147	{ &vop_mmap_desc, (vop_t *)fifo_mmap },		/* mmap */
1148	{ &vop_fsync_desc, (vop_t *)fifo_fsync },	/* fsync */
1149	{ &vop_seek_desc, (vop_t *)fifo_seek },		/* seek */
1150	{ &vop_remove_desc, (vop_t *)fifo_remove },	/* remove */
1151	{ &vop_link_desc, (vop_t *)fifo_link }	,	/* link */
1152	{ &vop_rename_desc, (vop_t *)fifo_rename },	/* rename */
1153	{ &vop_mkdir_desc, (vop_t *)fifo_mkdir },	/* mkdir */
1154	{ &vop_rmdir_desc, (vop_t *)fifo_rmdir },	/* rmdir */
1155	{ &vop_symlink_desc, (vop_t *)fifo_symlink },	/* symlink */
1156	{ &vop_readdir_desc, (vop_t *)fifo_readdir },	/* readdir */
1157	{ &vop_readlink_desc, (vop_t *)fifo_readlink },	/* readlink */
1158	{ &vop_abortop_desc, (vop_t *)fifo_abortop },	/* abortop */
1159	{ &vop_inactive_desc, (vop_t *)cd9660_inactive },/* inactive */
1160	{ &vop_reclaim_desc, (vop_t *)cd9660_reclaim },	/* reclaim */
1161	{ &vop_lock_desc, (vop_t *)cd9660_lock },	/* lock */
1162	{ &vop_unlock_desc, (vop_t *)cd9660_unlock },	/* unlock */
1163	{ &vop_bmap_desc, (vop_t *)fifo_bmap },		/* bmap */
1164	{ &vop_strategy_desc, (vop_t *)fifo_strategy },	/* strategy */
1165	{ &vop_print_desc, (vop_t *)cd9660_print },	/* print */
1166	{ &vop_islocked_desc, (vop_t *)cd9660_islocked },/* islocked */
1167	{ &vop_pathconf_desc, (vop_t *)fifo_pathconf },	/* pathconf */
1168	{ &vop_advlock_desc, (vop_t *)fifo_advlock },	/* advlock */
1169	{ &vop_blkatoff_desc, (vop_t *)fifo_blkatoff },	/* blkatoff */
1170	{ &vop_valloc_desc, (vop_t *)fifo_valloc },	/* valloc */
1171/* XXX: vop_reallocpages */
1172	{ &vop_vfree_desc, (vop_t *)fifo_vfree },	/* vfree */
1173	{ &vop_truncate_desc, (vop_t *)fifo_truncate },	/* truncate */
1174	{ &vop_update_desc, (vop_t *)cd9660_update },	/* update */
1175/* XXX: vop_getpages */
1176/* XXX: vop_putpages */
1177	{ &vop_bwrite_desc, (vop_t *)vn_bwrite },
1178	{ NULL, NULL }
1179};
1180static struct vnodeopv_desc cd9660_fifoop_opv_desc =
1181	{ &cd9660_fifoop_p, cd9660_fifoop_entries };
1182
1183VNODEOP_SET(cd9660_fifoop_opv_desc);
1184