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