xref: /freebsd/sys/fs/cd9660/cd9660_vfsops.c (revision 0de89efe5c443f213c7ea28773ef2dc6cf3af2ed)
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_vfsops.c	8.18 (Berkeley) 5/22/95
39  * $Id: cd9660_vfsops.c,v 1.28 1997/09/07 16:20:42 bde Exp $
40  */
41 
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/namei.h>
45 #include <sys/proc.h>
46 #include <sys/kernel.h>
47 #include <sys/vnode.h>
48 #include <miscfs/specfs/specdev.h>
49 #include <sys/mount.h>
50 #include <sys/buf.h>
51 #include <sys/cdio.h>
52 #include <sys/conf.h>
53 #include <sys/fcntl.h>
54 #include <sys/malloc.h>
55 #include <sys/stat.h>
56 
57 #include <isofs/cd9660/iso.h>
58 #include <isofs/cd9660/iso_rrip.h>
59 #include <isofs/cd9660/cd9660_node.h>
60 #include <isofs/cd9660/cd9660_mount.h>
61 
62 
63 static int cd9660_mount __P((struct mount *,
64 	    char *, caddr_t, struct nameidata *, struct proc *));
65 static int cd9660_start __P((struct mount *, int, struct proc *));
66 static int cd9660_unmount __P((struct mount *, int, struct proc *));
67 static int cd9660_root __P((struct mount *, struct vnode **));
68 static int cd9660_quotactl __P((struct mount *, int, uid_t, caddr_t,
69 	    struct proc *));
70 static int cd9660_statfs __P((struct mount *, struct statfs *, struct proc *));
71 static int cd9660_sync __P((struct mount *, int, struct ucred *,
72 	    struct proc *));
73 static int cd9660_vget __P((struct mount *, ino_t, struct vnode **));
74 static int cd9660_fhtovp __P((struct mount *, struct fid *, struct sockaddr *,
75 	    struct vnode **, int *, struct ucred **));
76 static int cd9660_vptofh __P((struct vnode *, struct fid *));
77 
78 static struct vfsops cd9660_vfsops = {
79 	cd9660_mount,
80 	cd9660_start,
81 	cd9660_unmount,
82 	cd9660_root,
83 	cd9660_quotactl,
84 	cd9660_statfs,
85 	cd9660_sync,
86 	cd9660_vget,
87 	cd9660_fhtovp,
88 	cd9660_vptofh,
89 	cd9660_init
90 };
91 VFS_SET(cd9660_vfsops, cd9660, MOUNT_CD9660, VFCF_READONLY);
92 
93 
94 /*
95  * Called by vfs_mountroot when iso is going to be mounted as root.
96  */
97 
98 static int iso_get_ssector __P((dev_t dev, struct proc *p));
99 static int iso_mountfs __P((struct vnode *devvp, struct mount *mp,
100 			    struct proc *p, struct iso_args *argp));
101 static int iso_mountroot __P((struct mount *mp, struct proc *p));
102 
103 /*
104  * Try to find the start of the last data track on this CD-ROM.  This
105  * is used to mount the last session of a multi-session CD.  Bail out
106  * and return 0 if we fail, this is always a safe bet.
107  */
108 static int
109 iso_get_ssector(dev, p)
110 	dev_t dev;
111 	struct proc *p;
112 {
113 	struct ioc_toc_header h;
114 	struct ioc_read_toc_single_entry t;
115 	int i;
116 	struct bdevsw *bd;
117 	d_ioctl_t *ioctlp;
118 
119 	bd = bdevsw[major(dev)];
120 	ioctlp = bd->d_ioctl;
121 	if (ioctlp == NULL)
122 		return 0;
123 
124 	if (ioctlp(dev, CDIOREADTOCHEADER, (caddr_t)&h, FREAD, p) == -1)
125 		return 0;
126 
127 	for (i = h.ending_track; i >= 0; i--) {
128 		t.address_format = CD_LBA_FORMAT;
129 		t.track = i;
130 		if (ioctlp(dev, CDIOREADTOCENTRY, (caddr_t)&t, FREAD, p) == -1)
131 			return 0;
132 		if ((t.entry.control & 4) != 0)
133 			/* found a data track */
134 			break;
135 	}
136 
137 	if (i < 0)
138 		return 0;
139 
140 	return ntohl(t.entry.addr.lba);
141 }
142 
143 static int
144 iso_mountroot(mp, p)
145 	struct mount *mp;
146 	struct proc *p;
147 {
148 	struct iso_args args;
149 	int error;
150 
151 	if ((error = bdevvp(rootdev, &rootvp))) {
152 		printf("iso_mountroot: can't find rootvp");
153 		return (error);
154 	}
155 	args.flags = ISOFSMNT_ROOT;
156 	args.ssector = iso_get_ssector(rootdev, p);
157 	if (bootverbose)
158 		printf("iso_mountroot(): using session at block %d\n",
159 		       args.ssector);
160 	if (error = iso_mountfs(rootvp, mp, p, &args))
161 		return (error);
162 
163 	(void)cd9660_statfs(mp, &mp->mnt_stat, p);
164 	return (0);
165 }
166 
167 /*
168  * VFS Operations.
169  *
170  * mount system call
171  */
172 static int
173 cd9660_mount(mp, path, data, ndp, p)
174 	register struct mount *mp;
175 	char *path;
176 	caddr_t data;
177 	struct nameidata *ndp;
178 	struct proc *p;
179 {
180 	struct vnode *devvp;
181 	struct iso_args args;
182 	u_int size;
183 	int error;
184 	struct iso_mnt *imp = 0;
185 
186 	if ((mp->mnt_flag & MNT_ROOTFS) != 0) {
187 		if (bdevsw[major(rootdev)]->d_flags & D_NOCLUSTERR)
188 			mp->mnt_flag |= MNT_NOCLUSTERR;
189 		return (iso_mountroot(mp, p));
190 	}
191 	if ((error = copyin(data, (caddr_t)&args, sizeof (struct iso_args))))
192 		return (error);
193 
194 	if ((mp->mnt_flag & MNT_RDONLY) == 0)
195 		return (EROFS);
196 
197 	/*
198 	 * If updating, check whether changing from read-only to
199 	 * read/write; if there is no device name, that's all we do.
200 	 * Disallow clearing MNT_NOCLUSTERR flag, if block device requests.
201 	 */
202 	if (mp->mnt_flag & MNT_UPDATE) {
203 		imp = VFSTOISOFS(mp);
204 		if (bdevsw[major(imp->im_devvp->v_rdev)]->d_flags &
205 		    D_NOCLUSTERR)
206 			mp->mnt_flag |= MNT_NOCLUSTERR;
207 		if (args.fspec == 0)
208 			return (vfs_export(mp, &imp->im_export, &args.export));
209 	}
210 	/*
211 	 * Not an update, or updating the name: look up the name
212 	 * and verify that it refers to a sensible block device.
213 	 */
214 	NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
215 	if ((error = namei(ndp)))
216 		return (error);
217 	devvp = ndp->ni_vp;
218 
219 	if (devvp->v_type != VBLK) {
220 		vrele(devvp);
221 		return ENOTBLK;
222 	}
223 	if (major(devvp->v_rdev) >= nblkdev) {
224 		vrele(devvp);
225 		return ENXIO;
226 	}
227 	if ((mp->mnt_flag & MNT_UPDATE) == 0) {
228 		if (bdevsw[major(devvp->v_rdev)]->d_flags & D_NOCLUSTERR)
229 			mp->mnt_flag |= MNT_NOCLUSTERR;
230 		error = iso_mountfs(devvp, mp, p, &args);
231 	} else {
232 		if (devvp != imp->im_devvp)
233 			error = EINVAL;	/* needs translation */
234 		else
235 			vrele(devvp);
236 	}
237 	if (error) {
238 		vrele(devvp);
239 		return error;
240 	}
241 	imp = VFSTOISOFS(mp);
242 	(void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
243 	bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
244 	(void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
245 	    &size);
246 	bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
247 	(void) cd9660_statfs(mp, &mp->mnt_stat, p);
248 	return 0;
249 }
250 
251 /*
252  * Common code for mount and mountroot
253  */
254 static int
255 iso_mountfs(devvp, mp, p, argp)
256 	register struct vnode *devvp;
257 	struct mount *mp;
258 	struct proc *p;
259 	struct iso_args *argp;
260 {
261 	register struct iso_mnt *isomp = (struct iso_mnt *)0;
262 	struct buf *bp = NULL;
263 	dev_t dev = devvp->v_rdev;
264 	int error = EINVAL;
265 	int needclose = 0;
266 	int high_sierra = 0;
267 	int ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
268 	int iso_bsize;
269 	int iso_blknum;
270 	struct iso_volume_descriptor *vdp;
271 	struct iso_primary_descriptor *pri;
272 	struct iso_sierra_primary_descriptor *pri_sierra;
273 	struct iso_directory_record *rootp;
274 	int logical_block_size;
275 
276 	if (!ronly)
277 		return EROFS;
278 
279 	/*
280 	 * Disallow multiple mounts of the same device.
281 	 * Disallow mounting of a device that is currently in use
282 	 * (except for root, which might share swap device for miniroot).
283 	 * Flush out any old buffers remaining from a previous use.
284 	 */
285 	if ((error = vfs_mountedon(devvp)))
286 		return error;
287 	if (vcount(devvp) > 1 && devvp != rootvp)
288 		return EBUSY;
289 	if ((error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0)))
290 		return (error);
291 
292 	if ((error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p)))
293 		return error;
294 	needclose = 1;
295 
296 	/* This is the "logical sector size".  The standard says this
297 	 * should be 2048 or the physical sector size on the device,
298 	 * whichever is greater.  For now, we'll just use a constant.
299 	 */
300 	iso_bsize = ISO_DEFAULT_BLOCK_SIZE;
301 
302 	for (iso_blknum = 16 + argp->ssector;
303 	     iso_blknum < 100 + argp->ssector;
304 	     iso_blknum++) {
305 		if (error = bread(devvp, iso_blknum * btodb(iso_bsize),
306 				  iso_bsize, NOCRED, &bp))
307 			goto out;
308 
309 		vdp = (struct iso_volume_descriptor *)bp->b_data;
310 		if (bcmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) != 0) {
311 			if (bcmp (vdp->id_sierra, ISO_SIERRA_ID,
312 				  sizeof vdp->id) != 0) {
313 				error = EINVAL;
314 				goto out;
315 			} else
316 				high_sierra = 1;
317 		}
318 
319 		if (isonum_711 (high_sierra? vdp->type_sierra: vdp->type) == ISO_VD_END) {
320 			error = EINVAL;
321 			goto out;
322 		}
323 
324 		if (isonum_711 (high_sierra? vdp->type_sierra: vdp->type) == ISO_VD_PRIMARY)
325 			break;
326 		brelse(bp);
327 	}
328 
329 	if (isonum_711 (high_sierra? vdp->type_sierra: vdp->type) != ISO_VD_PRIMARY) {
330 		error = EINVAL;
331 		goto out;
332 	}
333 
334 	pri = (struct iso_primary_descriptor *)vdp;
335 	pri_sierra = (struct iso_sierra_primary_descriptor *)vdp;
336 
337 	logical_block_size =
338 		isonum_723 (high_sierra?
339 			    pri_sierra->logical_block_size:
340 			    pri->logical_block_size);
341 
342 	if (logical_block_size < DEV_BSIZE || logical_block_size > MAXBSIZE
343 	    || (logical_block_size & (logical_block_size - 1)) != 0) {
344 		error = EINVAL;
345 		goto out;
346 	}
347 
348 	rootp = (struct iso_directory_record *)
349 		(high_sierra?
350 		 pri_sierra->root_directory_record:
351 		 pri->root_directory_record);
352 
353 	isomp = malloc(sizeof *isomp, M_ISOFSMNT, M_WAITOK);
354 	bzero((caddr_t)isomp, sizeof *isomp);
355 	isomp->logical_block_size = logical_block_size;
356 	isomp->volume_space_size =
357 		isonum_733 (high_sierra?
358 			    pri_sierra->volume_space_size:
359 			    pri->volume_space_size);
360 	/*
361 	 * Since an ISO9660 multi-session CD can also access previous
362 	 * sessions, we have to include them into the space consider-
363 	 * ations.  This doesn't yield a very accurate number since
364 	 * parts of the old sessions might be inaccessible now, but we
365 	 * can't do much better.  This is also important for the NFS
366 	 * filehandle validation.
367 	 */
368 	isomp->volume_space_size += argp->ssector;
369 	bcopy (rootp, isomp->root, sizeof isomp->root);
370 	isomp->root_extent = isonum_733 (rootp->extent);
371 	isomp->root_size = isonum_733 (rootp->size);
372 
373 	isomp->im_bmask = logical_block_size - 1;
374 	isomp->im_bshift = 0;
375 	while ((1 << isomp->im_bshift) < isomp->logical_block_size)
376 		isomp->im_bshift++;
377 
378 	bp->b_flags |= B_AGE;
379 	brelse(bp);
380 	bp = NULL;
381 
382 	mp->mnt_data = (qaddr_t)isomp;
383 	mp->mnt_stat.f_fsid.val[0] = (long)dev;
384 	mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
385 	mp->mnt_maxsymlinklen = 0;
386 	mp->mnt_flag |= MNT_LOCAL;
387 	isomp->im_mountp = mp;
388 	isomp->im_dev = dev;
389 	isomp->im_devvp = devvp;
390 
391 	devvp->v_specflags |= SI_MOUNTEDON;
392 
393 	/* Check the Rock Ridge Extention support */
394 	if (!(argp->flags & ISOFSMNT_NORRIP)) {
395 		if (error = bread(isomp->im_devvp,
396 				  (isomp->root_extent + isonum_711(rootp->ext_attr_length)) <<
397 				  (isomp->im_bshift - DEV_BSHIFT),
398 				  isomp->logical_block_size, NOCRED, &bp))
399 		    goto out;
400 
401 		rootp = (struct iso_directory_record *)bp->b_data;
402 
403 		if ((isomp->rr_skip = cd9660_rrip_offset(rootp,isomp)) < 0) {
404 		    argp->flags	 |= ISOFSMNT_NORRIP;
405 		} else {
406 		    argp->flags	 &= ~ISOFSMNT_GENS;
407 		}
408 
409 		/*
410 		 * The contents are valid,
411 		 * but they will get reread as part of another vnode, so...
412 		 */
413 		bp->b_flags |= B_AGE;
414 		brelse(bp);
415 		bp = NULL;
416 	}
417 	isomp->im_flags = argp->flags&(ISOFSMNT_NORRIP|ISOFSMNT_GENS|ISOFSMNT_EXTATT);
418 
419 	if(high_sierra)
420 		/* this effectively ignores all the mount flags */
421 		isomp->iso_ftype = ISO_FTYPE_HIGH_SIERRA;
422 	else
423 		switch (isomp->im_flags&(ISOFSMNT_NORRIP|ISOFSMNT_GENS)) {
424 		  default:
425 			  isomp->iso_ftype = ISO_FTYPE_DEFAULT;
426 			  break;
427 		  case ISOFSMNT_GENS|ISOFSMNT_NORRIP:
428 			  isomp->iso_ftype = ISO_FTYPE_9660;
429 			  break;
430 		  case 0:
431 			  isomp->iso_ftype = ISO_FTYPE_RRIP;
432 			  break;
433 		}
434 
435 	return 0;
436 out:
437 	if (bp)
438 		brelse(bp);
439 	if (needclose)
440 		(void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p);
441 	if (isomp) {
442 		free((caddr_t)isomp, M_ISOFSMNT);
443 		mp->mnt_data = (qaddr_t)0;
444 	}
445 	return error;
446 }
447 
448 /*
449  * Make a filesystem operational.
450  * Nothing to do at the moment.
451  */
452 /* ARGSUSED */
453 static int
454 cd9660_start(mp, flags, p)
455 	struct mount *mp;
456 	int flags;
457 	struct proc *p;
458 {
459 	return 0;
460 }
461 
462 /*
463  * unmount system call
464  */
465 static int
466 cd9660_unmount(mp, mntflags, p)
467 	struct mount *mp;
468 	int mntflags;
469 	struct proc *p;
470 {
471 	register struct iso_mnt *isomp;
472 	int error, flags = 0;
473 
474 	if (mntflags & MNT_FORCE)
475 		flags |= FORCECLOSE;
476 #if 0
477 	mntflushbuf(mp, 0);
478 	if (mntinvalbuf(mp))
479 		return EBUSY;
480 #endif
481 	if ((error = vflush(mp, NULLVP, flags)))
482 		return (error);
483 
484 	isomp = VFSTOISOFS(mp);
485 
486 
487 	isomp->im_devvp->v_specflags &= ~SI_MOUNTEDON;
488 	error = VOP_CLOSE(isomp->im_devvp, FREAD, NOCRED, p);
489 	vrele(isomp->im_devvp);
490 	free((caddr_t)isomp, M_ISOFSMNT);
491 	mp->mnt_data = (qaddr_t)0;
492 	mp->mnt_flag &= ~MNT_LOCAL;
493 	return (error);
494 }
495 
496 /*
497  * Return root of a filesystem
498  */
499 static int
500 cd9660_root(mp, vpp)
501 	struct mount *mp;
502 	struct vnode **vpp;
503 {
504 	struct iso_mnt *imp = VFSTOISOFS(mp);
505 	struct iso_directory_record *dp =
506 	    (struct iso_directory_record *)imp->root;
507 	ino_t ino = isodirino(dp, imp);
508 
509 	/*
510 	 * With RRIP we must use the `.' entry of the root directory.
511 	 * Simply tell vget, that it's a relocated directory.
512 	 */
513 	return (cd9660_vget_internal(mp, ino, vpp,
514 	    imp->iso_ftype == ISO_FTYPE_RRIP, dp));
515 }
516 
517 /*
518  * Do operations associated with quotas, not supported
519  */
520 /* ARGSUSED */
521 static int
522 cd9660_quotactl(mp, cmd, uid, arg, p)
523 	struct mount *mp;
524 	int cmd;
525 	uid_t uid;
526 	caddr_t arg;
527 	struct proc *p;
528 {
529 
530 	return (EOPNOTSUPP);
531 }
532 
533 /*
534  * Get file system statistics.
535  */
536 int
537 cd9660_statfs(mp, sbp, p)
538 	struct mount *mp;
539 	register struct statfs *sbp;
540 	struct proc *p;
541 {
542 	register struct iso_mnt *isomp;
543 
544 	isomp = VFSTOISOFS(mp);
545 
546 	sbp->f_type = MOUNT_CD9660;
547 	sbp->f_bsize = isomp->logical_block_size;
548 	sbp->f_iosize = sbp->f_bsize;	/* XXX */
549 	sbp->f_blocks = isomp->volume_space_size;
550 	sbp->f_bfree = 0; /* total free blocks */
551 	sbp->f_bavail = 0; /* blocks free for non superuser */
552 	sbp->f_files =	0; /* total files */
553 	sbp->f_ffree = 0; /* free file nodes */
554 	if (sbp != &mp->mnt_stat) {
555 		bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
556 		bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
557 	}
558 	/* Use the first spare for flags: */
559 	sbp->f_spare[0] = isomp->im_flags;
560 	return 0;
561 }
562 
563 /* ARGSUSED */
564 static int
565 cd9660_sync(mp, waitfor, cred, p)
566 	struct mount *mp;
567 	int waitfor;
568 	struct ucred *cred;
569 	struct proc *p;
570 {
571 	return (0);
572 }
573 
574 /*
575  * File handle to vnode
576  *
577  * Have to be really careful about stale file handles:
578  * - check that the inode number is in range
579  * - call iget() to get the locked inode
580  * - check for an unallocated inode (i_mode == 0)
581  * - check that the generation number matches
582  */
583 
584 struct ifid {
585 	ushort	ifid_len;
586 	ushort	ifid_pad;
587 	int	ifid_ino;
588 	long	ifid_start;
589 };
590 
591 /* ARGSUSED */
592 int
593 cd9660_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
594 	register struct mount *mp;
595 	struct fid *fhp;
596 	struct sockaddr *nam;
597 	struct vnode **vpp;
598 	int *exflagsp;
599 	struct ucred **credanonp;
600 {
601 	struct ifid *ifhp = (struct ifid *)fhp;
602 	register struct iso_node *ip;
603 	register struct netcred *np;
604 	register struct iso_mnt *imp = VFSTOISOFS(mp);
605 	struct vnode *nvp;
606 	int error;
607 
608 #ifdef	ISOFS_DBG
609 	printf("fhtovp: ino %d, start %ld\n",
610 	       ifhp->ifid_ino, ifhp->ifid_start);
611 #endif
612 
613 	/*
614 	 * Get the export permission structure for this <mp, client> tuple.
615 	 */
616 	np = vfs_export_lookup(mp, &imp->im_export, nam);
617 	if (np == NULL)
618 		return (EACCES);
619 
620 	if (error = VFS_VGET(mp, ifhp->ifid_ino, &nvp)) {
621 		*vpp = NULLVP;
622 		return (error);
623 	}
624 	ip = VTOI(nvp);
625 	if (ip->inode.iso_mode == 0) {
626 		vput(nvp);
627 		*vpp = NULLVP;
628 		return (ESTALE);
629 	}
630 	*vpp = nvp;
631 	*exflagsp = np->netc_exflags;
632 	*credanonp = &np->netc_anon;
633 	return (0);
634 }
635 
636 int
637 cd9660_vget(mp, ino, vpp)
638 	struct mount *mp;
639 	ino_t ino;
640 	struct vnode **vpp;
641 {
642 
643 	/*
644 	 * XXXX
645 	 * It would be nice if we didn't always set the `relocated' flag
646 	 * and force the extra read, but I don't want to think about fixing
647 	 * that right now.
648 	 */
649 	return (cd9660_vget_internal(mp, ino, vpp,
650 #if 0
651 	    VFSTOISOFS(mp)->iso_ftype == ISO_FTYPE_RRIP,
652 #else
653 	    0,
654 #endif
655 	    (struct iso_directory_record *)0));
656 }
657 
658 int
659 cd9660_vget_internal(mp, ino, vpp, relocated, isodir)
660 	struct mount *mp;
661 	ino_t ino;
662 	struct vnode **vpp;
663 	int relocated;
664 	struct iso_directory_record *isodir;
665 {
666 	struct iso_mnt *imp;
667 	struct iso_node *ip;
668 	struct buf *bp;
669 	struct vnode *vp, *nvp;
670 	dev_t dev;
671 	int error;
672 
673 	imp = VFSTOISOFS(mp);
674 	dev = imp->im_dev;
675 	if ((*vpp = cd9660_ihashget(dev, ino)) != NULLVP)
676 		return (0);
677 
678 	/* Allocate a new vnode/iso_node. */
679 	if (error = getnewvnode(VT_ISOFS, mp, cd9660_vnodeop_p, &vp)) {
680 		*vpp = NULLVP;
681 		return (error);
682 	}
683 	MALLOC(ip, struct iso_node *, sizeof(struct iso_node), M_ISOFSNODE,
684 	    M_WAITOK);
685 	bzero((caddr_t)ip, sizeof(struct iso_node));
686 	lockinit(&ip->i_lock, PINOD, "isonode", 0, 0);
687 	vp->v_data = ip;
688 	ip->i_vnode = vp;
689 	ip->i_dev = dev;
690 	ip->i_number = ino;
691 
692 	/*
693 	 * Put it onto its hash chain and lock it so that other requests for
694 	 * this inode will block if they arrive while we are sleeping waiting
695 	 * for old data structures to be purged or for the contents of the
696 	 * disk portion of this inode to be read.
697 	 */
698 	cd9660_ihashins(ip);
699 
700 	if (isodir == 0) {
701 		int lbn, off;
702 
703 		lbn = lblkno(imp, ino);
704 		if (lbn >= imp->volume_space_size) {
705 			vput(vp);
706 			printf("fhtovp: lbn exceed volume space %d\n", lbn);
707 			return (ESTALE);
708 		}
709 
710 		off = blkoff(imp, ino);
711 		if (off + ISO_DIRECTORY_RECORD_SIZE > imp->logical_block_size) {
712 			vput(vp);
713 			printf("fhtovp: crosses block boundary %d\n",
714 			       off + ISO_DIRECTORY_RECORD_SIZE);
715 			return (ESTALE);
716 		}
717 
718 		error = bread(imp->im_devvp,
719 			      lbn << (imp->im_bshift - DEV_BSHIFT),
720 			      imp->logical_block_size, NOCRED, &bp);
721 		if (error) {
722 			vput(vp);
723 			brelse(bp);
724 			printf("fhtovp: bread error %d\n",error);
725 			return (error);
726 		}
727 		isodir = (struct iso_directory_record *)(bp->b_data + off);
728 
729 		if (off + isonum_711(isodir->length) >
730 		    imp->logical_block_size) {
731 			vput(vp);
732 			if (bp != 0)
733 				brelse(bp);
734 			printf("fhtovp: directory crosses block boundary %d[off=%d/len=%d]\n",
735 			       off +isonum_711(isodir->length), off,
736 			       isonum_711(isodir->length));
737 			return (ESTALE);
738 		}
739 
740 #if 0
741 		if (isonum_733(isodir->extent) +
742 		    isonum_711(isodir->ext_attr_length) != ifhp->ifid_start) {
743 			if (bp != 0)
744 				brelse(bp);
745 			printf("fhtovp: file start miss %d vs %d\n",
746 			       isonum_733(isodir->extent) + isonum_711(isodir->ext_attr_length),
747 			       ifhp->ifid_start);
748 			return (ESTALE);
749 		}
750 #endif
751 	} else
752 		bp = 0;
753 
754 	ip->i_mnt = imp;
755 	ip->i_devvp = imp->im_devvp;
756 	VREF(ip->i_devvp);
757 
758 	if (relocated) {
759 		/*
760 		 * On relocated directories we must
761 		 * read the `.' entry out of a dir.
762 		 */
763 		ip->iso_start = ino >> imp->im_bshift;
764 		if (bp != 0)
765 			brelse(bp);
766 		if (error = VOP_BLKATOFF(vp, (off_t)0, NULL, &bp)) {
767 			vput(vp);
768 			return (error);
769 		}
770 		isodir = (struct iso_directory_record *)bp->b_data;
771 	}
772 
773 	ip->iso_extent = isonum_733(isodir->extent);
774 	ip->i_size = isonum_733(isodir->size);
775 	ip->iso_start = isonum_711(isodir->ext_attr_length) + ip->iso_extent;
776 
777 	/*
778 	 * Setup time stamp, attribute
779 	 */
780 	vp->v_type = VNON;
781 	switch (imp->iso_ftype) {
782 	default:	/* ISO_FTYPE_9660 */
783 	    {
784 		struct buf *bp2;
785 		int off;
786 		if ((imp->im_flags & ISOFSMNT_EXTATT)
787 		    && (off = isonum_711(isodir->ext_attr_length)))
788 			VOP_BLKATOFF(vp, (off_t)-(off << imp->im_bshift), NULL,
789 				     &bp2);
790 		else
791 			bp2 = NULL;
792 		cd9660_defattr(isodir, ip, bp2, ISO_FTYPE_9660);
793 		cd9660_deftstamp(isodir, ip, bp2, ISO_FTYPE_9660);
794 		if (bp2)
795 			brelse(bp2);
796 		break;
797 	    }
798 	case ISO_FTYPE_RRIP:
799 		cd9660_rrip_analyze(isodir, ip, imp);
800 		break;
801 	}
802 
803 	if (bp != 0)
804 		brelse(bp);
805 
806 	/*
807 	 * Initialize the associated vnode
808 	 */
809 	switch (vp->v_type = IFTOVT(ip->inode.iso_mode)) {
810 	case VFIFO:
811 		vp->v_op = cd9660_fifoop_p;
812 		break;
813 	case VCHR:
814 	case VBLK:
815 		/*
816 		 * if device, look at device number table for translation
817 		 */
818 		vp->v_op = cd9660_specop_p;
819 		if (nvp = checkalias(vp, ip->inode.iso_rdev, mp)) {
820 			/*
821 			 * Discard unneeded vnode, but save its iso_node.
822 			 * Note that the lock is carried over in the iso_node
823 			 * to the replacement vnode.
824 			 */
825 			nvp->v_data = vp->v_data;
826 			vp->v_data = NULL;
827 			vp->v_op = spec_vnodeop_p;
828 			vrele(vp);
829 			vgone(vp);
830 			/*
831 			 * Reinitialize aliased inode.
832 			 */
833 			vp = nvp;
834 			ip->i_vnode = vp;
835 		}
836 		break;
837 	}
838 
839 	if (ip->iso_extent == imp->root_extent)
840 		vp->v_flag |= VROOT;
841 
842 	/*
843 	 * XXX need generation number?
844 	 */
845 
846 	*vpp = vp;
847 	return (0);
848 }
849 
850 /*
851  * Vnode pointer to File handle
852  */
853 /* ARGSUSED */
854 int
855 cd9660_vptofh(vp, fhp)
856 	struct vnode *vp;
857 	struct fid *fhp;
858 {
859 	register struct iso_node *ip = VTOI(vp);
860 	register struct ifid *ifhp;
861 
862 	ifhp = (struct ifid *)fhp;
863 	ifhp->ifid_len = sizeof(struct ifid);
864 
865 	ifhp->ifid_ino = ip->i_number;
866 	ifhp->ifid_start = ip->iso_start;
867 
868 #ifdef	ISOFS_DBG
869 	printf("vptofh: ino %d, start %ld\n",
870 	       ifhp->ifid_ino,ifhp->ifid_start);
871 #endif
872 	return 0;
873 }
874