xref: /minix3/sys/fs/cd9660/cd9660_vfsops.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: cd9660_vfsops.c,v 1.90 2015/03/28 19:24:05 maxv Exp $	*/
284d9c625SLionel Sambuc 
384d9c625SLionel Sambuc /*-
484d9c625SLionel Sambuc  * Copyright (c) 1994
584d9c625SLionel Sambuc  *	The Regents of the University of California.  All rights reserved.
684d9c625SLionel Sambuc  *
784d9c625SLionel Sambuc  * This code is derived from software contributed to Berkeley
884d9c625SLionel Sambuc  * by Pace Willisson (pace@blitz.com).  The Rock Ridge Extension
984d9c625SLionel Sambuc  * Support code is derived from software contributed to Berkeley
1084d9c625SLionel Sambuc  * by Atsushi Murai (amurai@spec.co.jp).
1184d9c625SLionel Sambuc  *
1284d9c625SLionel Sambuc  * Redistribution and use in source and binary forms, with or without
1384d9c625SLionel Sambuc  * modification, are permitted provided that the following conditions
1484d9c625SLionel Sambuc  * are met:
1584d9c625SLionel Sambuc  * 1. Redistributions of source code must retain the above copyright
1684d9c625SLionel Sambuc  *    notice, this list of conditions and the following disclaimer.
1784d9c625SLionel Sambuc  * 2. Redistributions in binary form must reproduce the above copyright
1884d9c625SLionel Sambuc  *    notice, this list of conditions and the following disclaimer in the
1984d9c625SLionel Sambuc  *    documentation and/or other materials provided with the distribution.
2084d9c625SLionel Sambuc  * 3. Neither the name of the University nor the names of its contributors
2184d9c625SLionel Sambuc  *    may be used to endorse or promote products derived from this software
2284d9c625SLionel Sambuc  *    without specific prior written permission.
2384d9c625SLionel Sambuc  *
2484d9c625SLionel Sambuc  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2584d9c625SLionel Sambuc  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2684d9c625SLionel Sambuc  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2784d9c625SLionel Sambuc  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2884d9c625SLionel Sambuc  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2984d9c625SLionel Sambuc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3084d9c625SLionel Sambuc  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3184d9c625SLionel Sambuc  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3284d9c625SLionel Sambuc  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3384d9c625SLionel Sambuc  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3484d9c625SLionel Sambuc  * SUCH DAMAGE.
3584d9c625SLionel Sambuc  *
3684d9c625SLionel Sambuc  *	@(#)cd9660_vfsops.c	8.18 (Berkeley) 5/22/95
3784d9c625SLionel Sambuc  */
3884d9c625SLionel Sambuc 
3984d9c625SLionel Sambuc #include <sys/cdefs.h>
40*0a6a1f1dSLionel Sambuc __KERNEL_RCSID(0, "$NetBSD: cd9660_vfsops.c,v 1.90 2015/03/28 19:24:05 maxv Exp $");
4184d9c625SLionel Sambuc 
4284d9c625SLionel Sambuc #if defined(_KERNEL_OPT)
4384d9c625SLionel Sambuc #include "opt_compat_netbsd.h"
4484d9c625SLionel Sambuc #endif
4584d9c625SLionel Sambuc 
4684d9c625SLionel Sambuc #include <sys/param.h>
4784d9c625SLionel Sambuc #include <sys/sysctl.h>
4884d9c625SLionel Sambuc #include <sys/systm.h>
4984d9c625SLionel Sambuc #include <sys/namei.h>
5084d9c625SLionel Sambuc #include <sys/proc.h>
5184d9c625SLionel Sambuc #include <sys/kernel.h>
5284d9c625SLionel Sambuc #include <sys/vnode.h>
5384d9c625SLionel Sambuc #include <miscfs/genfs/genfs.h>
5484d9c625SLionel Sambuc #include <miscfs/specfs/specdev.h>
5584d9c625SLionel Sambuc #include <sys/mount.h>
5684d9c625SLionel Sambuc #include <sys/buf.h>
5784d9c625SLionel Sambuc #include <sys/file.h>
5884d9c625SLionel Sambuc #include <sys/disklabel.h>
5984d9c625SLionel Sambuc #include <sys/device.h>
6084d9c625SLionel Sambuc #include <sys/ioctl.h>
6184d9c625SLionel Sambuc #include <sys/cdio.h>
6284d9c625SLionel Sambuc #include <sys/errno.h>
6384d9c625SLionel Sambuc #include <sys/malloc.h>
6484d9c625SLionel Sambuc #include <sys/pool.h>
6584d9c625SLionel Sambuc #include <sys/stat.h>
6684d9c625SLionel Sambuc #include <sys/conf.h>
6784d9c625SLionel Sambuc #include <sys/dirent.h>
6884d9c625SLionel Sambuc #include <sys/kauth.h>
6984d9c625SLionel Sambuc #include <sys/module.h>
7084d9c625SLionel Sambuc 
7184d9c625SLionel Sambuc #include <fs/cd9660/iso.h>
7284d9c625SLionel Sambuc #include <fs/cd9660/cd9660_extern.h>
7384d9c625SLionel Sambuc #include <fs/cd9660/iso_rrip.h>
7484d9c625SLionel Sambuc #include <fs/cd9660/cd9660_node.h>
7584d9c625SLionel Sambuc #include <fs/cd9660/cd9660_mount.h>
7684d9c625SLionel Sambuc 
7784d9c625SLionel Sambuc MODULE(MODULE_CLASS_VFS, cd9660, NULL);
7884d9c625SLionel Sambuc 
7984d9c625SLionel Sambuc MALLOC_JUSTDEFINE(M_ISOFSMNT, "ISOFS mount", "ISOFS mount structure");
8084d9c625SLionel Sambuc 
8184d9c625SLionel Sambuc static struct sysctllog *cd9660_sysctl_log;
8284d9c625SLionel Sambuc 
8384d9c625SLionel Sambuc extern const struct vnodeopv_desc cd9660_vnodeop_opv_desc;
8484d9c625SLionel Sambuc extern const struct vnodeopv_desc cd9660_specop_opv_desc;
8584d9c625SLionel Sambuc extern const struct vnodeopv_desc cd9660_fifoop_opv_desc;
8684d9c625SLionel Sambuc 
8784d9c625SLionel Sambuc const struct vnodeopv_desc * const cd9660_vnodeopv_descs[] = {
8884d9c625SLionel Sambuc 	&cd9660_vnodeop_opv_desc,
8984d9c625SLionel Sambuc 	&cd9660_specop_opv_desc,
9084d9c625SLionel Sambuc 	&cd9660_fifoop_opv_desc,
9184d9c625SLionel Sambuc 	NULL,
9284d9c625SLionel Sambuc };
9384d9c625SLionel Sambuc 
9484d9c625SLionel Sambuc struct vfsops cd9660_vfsops = {
95*0a6a1f1dSLionel Sambuc 	.vfs_name = MOUNT_CD9660,
96*0a6a1f1dSLionel Sambuc 	.vfs_min_mount_data = sizeof (struct iso_args),
97*0a6a1f1dSLionel Sambuc 	.vfs_mount = cd9660_mount,
98*0a6a1f1dSLionel Sambuc 	.vfs_start = cd9660_start,
99*0a6a1f1dSLionel Sambuc 	.vfs_unmount = cd9660_unmount,
100*0a6a1f1dSLionel Sambuc 	.vfs_root = cd9660_root,
101*0a6a1f1dSLionel Sambuc 	.vfs_quotactl = (void *)eopnotsupp,
102*0a6a1f1dSLionel Sambuc 	.vfs_statvfs = cd9660_statvfs,
103*0a6a1f1dSLionel Sambuc 	.vfs_sync = cd9660_sync,
104*0a6a1f1dSLionel Sambuc 	.vfs_vget = cd9660_vget,
105*0a6a1f1dSLionel Sambuc 	.vfs_loadvnode = cd9660_loadvnode,
106*0a6a1f1dSLionel Sambuc 	.vfs_fhtovp = cd9660_fhtovp,
107*0a6a1f1dSLionel Sambuc 	.vfs_vptofh = cd9660_vptofh,
108*0a6a1f1dSLionel Sambuc 	.vfs_init = cd9660_init,
109*0a6a1f1dSLionel Sambuc 	.vfs_reinit = cd9660_reinit,
110*0a6a1f1dSLionel Sambuc 	.vfs_done = cd9660_done,
111*0a6a1f1dSLionel Sambuc 	.vfs_mountroot = cd9660_mountroot,
112*0a6a1f1dSLionel Sambuc 	.vfs_snapshot = (void *)eopnotsupp,
113*0a6a1f1dSLionel Sambuc 	.vfs_extattrctl = vfs_stdextattrctl,
114*0a6a1f1dSLionel Sambuc 	.vfs_suspendctl = (void *)eopnotsupp,
115*0a6a1f1dSLionel Sambuc 	.vfs_renamelock_enter = genfs_renamelock_enter,
116*0a6a1f1dSLionel Sambuc 	.vfs_renamelock_exit = genfs_renamelock_exit,
117*0a6a1f1dSLionel Sambuc 	.vfs_fsync = (void *)eopnotsupp,
118*0a6a1f1dSLionel Sambuc 	.vfs_opv_descs = cd9660_vnodeopv_descs
11984d9c625SLionel Sambuc };
12084d9c625SLionel Sambuc 
12184d9c625SLionel Sambuc static const struct genfs_ops cd9660_genfsops = {
12284d9c625SLionel Sambuc 	.gop_size = genfs_size,
12384d9c625SLionel Sambuc };
12484d9c625SLionel Sambuc 
12584d9c625SLionel Sambuc /*
12684d9c625SLionel Sambuc  * Called by vfs_mountroot when iso is going to be mounted as root.
12784d9c625SLionel Sambuc  *
12884d9c625SLionel Sambuc  * Name is updated by mount(8) after booting.
12984d9c625SLionel Sambuc  */
13084d9c625SLionel Sambuc static int iso_makemp(struct iso_mnt *isomp, struct buf *bp, int *ea_len);
13184d9c625SLionel Sambuc static int iso_mountfs(struct vnode *devvp, struct mount *mp,
13284d9c625SLionel Sambuc 		struct lwp *l, struct iso_args *argp);
13384d9c625SLionel Sambuc 
13484d9c625SLionel Sambuc static int
cd9660_modcmd(modcmd_t cmd,void * arg)13584d9c625SLionel Sambuc cd9660_modcmd(modcmd_t cmd, void *arg)
13684d9c625SLionel Sambuc {
13784d9c625SLionel Sambuc 	int error;
13884d9c625SLionel Sambuc 
13984d9c625SLionel Sambuc 	switch (cmd) {
14084d9c625SLionel Sambuc 	case MODULE_CMD_INIT:
14184d9c625SLionel Sambuc 		error = vfs_attach(&cd9660_vfsops);
14284d9c625SLionel Sambuc 		if (error != 0)
14384d9c625SLionel Sambuc 			break;
14484d9c625SLionel Sambuc 		sysctl_createv(&cd9660_sysctl_log, 0, NULL, NULL,
14584d9c625SLionel Sambuc 			       CTLFLAG_PERMANENT, CTLTYPE_NODE, "cd9660",
14684d9c625SLionel Sambuc 			       SYSCTL_DESCR("ISO-9660 file system"),
14784d9c625SLionel Sambuc 			       NULL, 0, NULL, 0,
14884d9c625SLionel Sambuc 			       CTL_VFS, 14, CTL_EOL);
14984d9c625SLionel Sambuc 		sysctl_createv(&cd9660_sysctl_log, 0, NULL, NULL,
15084d9c625SLionel Sambuc 			       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
15184d9c625SLionel Sambuc 			       CTLTYPE_INT, "utf8_joliet",
15284d9c625SLionel Sambuc 			       SYSCTL_DESCR("Encode Joliet filenames to UTF-8"),
15384d9c625SLionel Sambuc 			       NULL, 0, &cd9660_utf8_joliet, 0,
15484d9c625SLionel Sambuc 			       CTL_VFS, 14, CD9660_UTF8_JOLIET, CTL_EOL);
15584d9c625SLionel Sambuc 		/*
15684d9c625SLionel Sambuc 		 * XXX the "14" above could be dynamic, thereby eliminating
15784d9c625SLionel Sambuc 		 * one more instance of the "number to vfs" mapping problem,
15884d9c625SLionel Sambuc 		 * but "14" is the order as taken from sys/mount.h
15984d9c625SLionel Sambuc 		 */
16084d9c625SLionel Sambuc 		break;
16184d9c625SLionel Sambuc 	case MODULE_CMD_FINI:
16284d9c625SLionel Sambuc 		error = vfs_detach(&cd9660_vfsops);
16384d9c625SLionel Sambuc 		if (error != 0)
16484d9c625SLionel Sambuc 			break;
16584d9c625SLionel Sambuc 		sysctl_teardown(&cd9660_sysctl_log);
16684d9c625SLionel Sambuc 		break;
16784d9c625SLionel Sambuc 	default:
16884d9c625SLionel Sambuc 		error = ENOTTY;
16984d9c625SLionel Sambuc 		break;
17084d9c625SLionel Sambuc 	}
17184d9c625SLionel Sambuc 
17284d9c625SLionel Sambuc 	return (error);
17384d9c625SLionel Sambuc }
17484d9c625SLionel Sambuc 
17584d9c625SLionel Sambuc int
cd9660_mountroot(void)17684d9c625SLionel Sambuc cd9660_mountroot(void)
17784d9c625SLionel Sambuc {
17884d9c625SLionel Sambuc 	struct mount *mp;
17984d9c625SLionel Sambuc 	struct lwp *l = curlwp;
18084d9c625SLionel Sambuc 	int error;
18184d9c625SLionel Sambuc 	struct iso_args args;
18284d9c625SLionel Sambuc 
18384d9c625SLionel Sambuc 	if (device_class(root_device) != DV_DISK)
18484d9c625SLionel Sambuc 		return (ENODEV);
18584d9c625SLionel Sambuc 
18684d9c625SLionel Sambuc 	if ((error = vfs_rootmountalloc(MOUNT_CD9660, "root_device", &mp))
18784d9c625SLionel Sambuc 			!= 0) {
18884d9c625SLionel Sambuc 		vrele(rootvp);
18984d9c625SLionel Sambuc 		return (error);
19084d9c625SLionel Sambuc 	}
19184d9c625SLionel Sambuc 
19284d9c625SLionel Sambuc 	args.flags = ISOFSMNT_ROOT;
19384d9c625SLionel Sambuc 	if ((error = iso_mountfs(rootvp, mp, l, &args)) != 0) {
19484d9c625SLionel Sambuc 		vfs_unbusy(mp, false, NULL);
19584d9c625SLionel Sambuc 		vfs_destroy(mp);
19684d9c625SLionel Sambuc 		return (error);
19784d9c625SLionel Sambuc 	}
19884d9c625SLionel Sambuc 	mountlist_append(mp);
19984d9c625SLionel Sambuc 	(void)cd9660_statvfs(mp, &mp->mnt_stat);
20084d9c625SLionel Sambuc 	vfs_unbusy(mp, false, NULL);
20184d9c625SLionel Sambuc 	return (0);
20284d9c625SLionel Sambuc }
20384d9c625SLionel Sambuc 
20484d9c625SLionel Sambuc /*
20584d9c625SLionel Sambuc  * VFS Operations.
20684d9c625SLionel Sambuc  *
20784d9c625SLionel Sambuc  * mount system call
20884d9c625SLionel Sambuc  */
20984d9c625SLionel Sambuc int
cd9660_mount(struct mount * mp,const char * path,void * data,size_t * data_len)21084d9c625SLionel Sambuc cd9660_mount(struct mount *mp, const char *path, void *data, size_t *data_len)
21184d9c625SLionel Sambuc {
21284d9c625SLionel Sambuc 	struct lwp *l = curlwp;
21384d9c625SLionel Sambuc 	struct vnode *devvp;
21484d9c625SLionel Sambuc 	struct iso_args *args = data;
21584d9c625SLionel Sambuc 	int error;
21684d9c625SLionel Sambuc 	struct iso_mnt *imp = VFSTOISOFS(mp);
21784d9c625SLionel Sambuc 
218*0a6a1f1dSLionel Sambuc 	if (args == NULL)
219*0a6a1f1dSLionel Sambuc 		return EINVAL;
22084d9c625SLionel Sambuc 	if (*data_len < sizeof *args)
22184d9c625SLionel Sambuc 		return EINVAL;
22284d9c625SLionel Sambuc 
22384d9c625SLionel Sambuc 	if (mp->mnt_flag & MNT_GETARGS) {
22484d9c625SLionel Sambuc 		if (imp == NULL)
22584d9c625SLionel Sambuc 			return EIO;
22684d9c625SLionel Sambuc 		args->fspec = NULL;
22784d9c625SLionel Sambuc 		args->flags = imp->im_flags;
22884d9c625SLionel Sambuc 		*data_len = sizeof (*args);
22984d9c625SLionel Sambuc 		return 0;
23084d9c625SLionel Sambuc 	}
23184d9c625SLionel Sambuc 
23284d9c625SLionel Sambuc 	if ((mp->mnt_flag & MNT_RDONLY) == 0)
23384d9c625SLionel Sambuc 		return (EROFS);
23484d9c625SLionel Sambuc 
23584d9c625SLionel Sambuc 	if ((mp->mnt_flag & MNT_UPDATE) && args->fspec == NULL)
23684d9c625SLionel Sambuc 		return EINVAL;
23784d9c625SLionel Sambuc 
23884d9c625SLionel Sambuc 	/*
23984d9c625SLionel Sambuc 	 * Not an update, or updating the name: look up the name
24084d9c625SLionel Sambuc 	 * and verify that it refers to a sensible block device.
24184d9c625SLionel Sambuc 	 */
24284d9c625SLionel Sambuc 	error = namei_simple_user(args->fspec,
24384d9c625SLionel Sambuc 				NSM_FOLLOW_NOEMULROOT, &devvp);
24484d9c625SLionel Sambuc 	if (error != 0)
24584d9c625SLionel Sambuc 		return (error);
24684d9c625SLionel Sambuc 
24784d9c625SLionel Sambuc 	if (devvp->v_type != VBLK) {
24884d9c625SLionel Sambuc 		vrele(devvp);
24984d9c625SLionel Sambuc 		return ENOTBLK;
25084d9c625SLionel Sambuc 	}
25184d9c625SLionel Sambuc 	if (bdevsw_lookup(devvp->v_rdev) == NULL) {
25284d9c625SLionel Sambuc 		vrele(devvp);
25384d9c625SLionel Sambuc 		return ENXIO;
25484d9c625SLionel Sambuc 	}
25584d9c625SLionel Sambuc 	/*
25684d9c625SLionel Sambuc 	 * If mount by non-root, then verify that user has necessary
25784d9c625SLionel Sambuc 	 * permissions on the device.
25884d9c625SLionel Sambuc 	 */
25984d9c625SLionel Sambuc 	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
26084d9c625SLionel Sambuc 	error = kauth_authorize_system(l->l_cred, KAUTH_SYSTEM_MOUNT,
26184d9c625SLionel Sambuc 	    KAUTH_REQ_SYSTEM_MOUNT_DEVICE, mp, devvp, KAUTH_ARG(VREAD));
26284d9c625SLionel Sambuc 	if (error) {
263*0a6a1f1dSLionel Sambuc 		goto fail;
26484d9c625SLionel Sambuc 	}
26584d9c625SLionel Sambuc 	if ((mp->mnt_flag & MNT_UPDATE) == 0) {
26684d9c625SLionel Sambuc 		error = VOP_OPEN(devvp, FREAD, FSCRED);
26784d9c625SLionel Sambuc 		if (error)
26884d9c625SLionel Sambuc 			goto fail;
26984d9c625SLionel Sambuc 		VOP_UNLOCK(devvp);
270*0a6a1f1dSLionel Sambuc 		error = iso_mountfs(devvp, mp, l, args);
271*0a6a1f1dSLionel Sambuc 		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
272*0a6a1f1dSLionel Sambuc 		if (error) {
273*0a6a1f1dSLionel Sambuc 			(void)VOP_CLOSE(devvp, FREAD, NOCRED);
27484d9c625SLionel Sambuc 			goto fail;
27584d9c625SLionel Sambuc 		}
276*0a6a1f1dSLionel Sambuc 		VOP_UNLOCK(devvp);
277*0a6a1f1dSLionel Sambuc 		/* reference to devvp is donated through iso_mountfs */
27884d9c625SLionel Sambuc 	} else {
27984d9c625SLionel Sambuc 		if (devvp != imp->im_devvp &&
280*0a6a1f1dSLionel Sambuc 		    devvp->v_rdev != imp->im_devvp->v_rdev) {
281*0a6a1f1dSLionel Sambuc 			error = EINVAL;		/* needs translation */
282*0a6a1f1dSLionel Sambuc 			goto fail;
283*0a6a1f1dSLionel Sambuc 		}
284*0a6a1f1dSLionel Sambuc 		VOP_UNLOCK(devvp);
285*0a6a1f1dSLionel Sambuc 		vrele(devvp);
28684d9c625SLionel Sambuc 	}
28784d9c625SLionel Sambuc 	return set_statvfs_info(path, UIO_USERSPACE, args->fspec, UIO_USERSPACE,
28884d9c625SLionel Sambuc 	    mp->mnt_op->vfs_name, mp, l);
28984d9c625SLionel Sambuc 
29084d9c625SLionel Sambuc fail:
291*0a6a1f1dSLionel Sambuc 	VOP_UNLOCK(devvp);
29284d9c625SLionel Sambuc 	vrele(devvp);
29384d9c625SLionel Sambuc 	return (error);
29484d9c625SLionel Sambuc }
29584d9c625SLionel Sambuc 
29684d9c625SLionel Sambuc /*
29784d9c625SLionel Sambuc  * Make a mount point from a volume descriptor
29884d9c625SLionel Sambuc  */
29984d9c625SLionel Sambuc static int
iso_makemp(struct iso_mnt * isomp,struct buf * bp,int * ea_len)30084d9c625SLionel Sambuc iso_makemp(struct iso_mnt *isomp, struct buf *bp, int *ea_len)
30184d9c625SLionel Sambuc {
30284d9c625SLionel Sambuc 	struct iso_primary_descriptor *pri;
30384d9c625SLionel Sambuc 	int logical_block_size;
30484d9c625SLionel Sambuc 	struct iso_directory_record *rootp;
30584d9c625SLionel Sambuc 
30684d9c625SLionel Sambuc 	pri = (struct iso_primary_descriptor *)bp->b_data;
30784d9c625SLionel Sambuc 
30884d9c625SLionel Sambuc 	logical_block_size = isonum_723 (pri->logical_block_size);
30984d9c625SLionel Sambuc 
31084d9c625SLionel Sambuc 	if (logical_block_size < DEV_BSIZE || logical_block_size > MAXBSIZE
31184d9c625SLionel Sambuc 	    || (logical_block_size & (logical_block_size - 1)) != 0)
31284d9c625SLionel Sambuc 		return -1;
31384d9c625SLionel Sambuc 
31484d9c625SLionel Sambuc 	rootp = (struct iso_directory_record *)pri->root_directory_record;
31584d9c625SLionel Sambuc 
31684d9c625SLionel Sambuc 	isomp->logical_block_size = logical_block_size;
31784d9c625SLionel Sambuc 	isomp->volume_space_size = isonum_733 (pri->volume_space_size);
31884d9c625SLionel Sambuc 	memcpy(isomp->root, rootp, sizeof(isomp->root));
31984d9c625SLionel Sambuc 	isomp->root_extent = isonum_733 (rootp->extent);
32084d9c625SLionel Sambuc 	isomp->root_size = isonum_733 (rootp->size);
32184d9c625SLionel Sambuc 	isomp->im_joliet_level = 0;
32284d9c625SLionel Sambuc 
32384d9c625SLionel Sambuc 	isomp->im_bmask = logical_block_size - 1;
32484d9c625SLionel Sambuc 	isomp->im_bshift = 0;
32584d9c625SLionel Sambuc 	while ((1 << isomp->im_bshift) < isomp->logical_block_size)
32684d9c625SLionel Sambuc 		isomp->im_bshift++;
32784d9c625SLionel Sambuc 
32884d9c625SLionel Sambuc 	if (ea_len != NULL)
32984d9c625SLionel Sambuc 		*ea_len = isonum_711(rootp->ext_attr_length);
33084d9c625SLionel Sambuc 
33184d9c625SLionel Sambuc 	return 0;
33284d9c625SLionel Sambuc }
33384d9c625SLionel Sambuc 
33484d9c625SLionel Sambuc /*
33584d9c625SLionel Sambuc  * Common code for mount and mountroot
33684d9c625SLionel Sambuc  */
33784d9c625SLionel Sambuc static int
iso_mountfs(struct vnode * devvp,struct mount * mp,struct lwp * l,struct iso_args * argp)33884d9c625SLionel Sambuc iso_mountfs(struct vnode *devvp, struct mount *mp, struct lwp *l,
33984d9c625SLionel Sambuc 	struct iso_args *argp)
34084d9c625SLionel Sambuc {
34184d9c625SLionel Sambuc 	struct iso_mnt *isomp = (struct iso_mnt *)0;
34284d9c625SLionel Sambuc 	struct buf *bp = NULL, *pribp = NULL, *supbp = NULL;
34384d9c625SLionel Sambuc 	dev_t dev = devvp->v_rdev;
34484d9c625SLionel Sambuc 	int error = EINVAL;
34584d9c625SLionel Sambuc 	int ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
34684d9c625SLionel Sambuc 	int iso_bsize;
34784d9c625SLionel Sambuc 	int iso_blknum;
34884d9c625SLionel Sambuc 	int joliet_level;
34984d9c625SLionel Sambuc 	struct iso_volume_descriptor *vdp;
35084d9c625SLionel Sambuc 	struct iso_supplementary_descriptor *sup;
35184d9c625SLionel Sambuc 	int sess = 0;
35284d9c625SLionel Sambuc 	int ext_attr_length;
35384d9c625SLionel Sambuc 	struct disklabel label;
35484d9c625SLionel Sambuc 
35584d9c625SLionel Sambuc 	if (!ronly)
35684d9c625SLionel Sambuc 		return EROFS;
35784d9c625SLionel Sambuc 
35884d9c625SLionel Sambuc 	/* Flush out any old buffers remaining from a previous use. */
35984d9c625SLionel Sambuc 	if ((error = vinvalbuf(devvp, V_SAVE, l->l_cred, l, 0, 0)) != 0)
36084d9c625SLionel Sambuc 		return (error);
36184d9c625SLionel Sambuc 
36284d9c625SLionel Sambuc 	/* This is the "logical sector size".  The standard says this
36384d9c625SLionel Sambuc 	 * should be 2048 or the physical sector size on the device,
36484d9c625SLionel Sambuc 	 * whichever is greater.  For now, we'll just use a constant.
36584d9c625SLionel Sambuc 	 */
36684d9c625SLionel Sambuc 	iso_bsize = ISO_DEFAULT_BLOCK_SIZE;
36784d9c625SLionel Sambuc 
36884d9c625SLionel Sambuc 	error = VOP_IOCTL(devvp, DIOCGDINFO, &label, FREAD, FSCRED);
36984d9c625SLionel Sambuc 	if (!error) {
37084d9c625SLionel Sambuc 		/* XXX more sanity checks? */
37184d9c625SLionel Sambuc 		sess = label.d_partitions[DISKPART(dev)].p_cdsession;
37284d9c625SLionel Sambuc 	} else {
37384d9c625SLionel Sambuc 		/* fallback to old method */
37484d9c625SLionel Sambuc 		error = VOP_IOCTL(devvp, CDIOREADMSADDR, &sess, 0, FSCRED);
37584d9c625SLionel Sambuc 		if (error)
37684d9c625SLionel Sambuc 			sess = 0;	/* never mind */
37784d9c625SLionel Sambuc 	}
37884d9c625SLionel Sambuc #ifdef ISO_DEBUG
37984d9c625SLionel Sambuc 	printf("isofs: session offset (part %"PRId32") %d\n", DISKPART(dev), sess);
38084d9c625SLionel Sambuc #endif
38184d9c625SLionel Sambuc 
38284d9c625SLionel Sambuc 	for (iso_blknum = 16; iso_blknum < 100; iso_blknum++) {
38384d9c625SLionel Sambuc 		if ((error = bread(devvp, (iso_blknum+sess) * btodb(iso_bsize),
384*0a6a1f1dSLionel Sambuc 				   iso_bsize, 0, &bp)) != 0)
38584d9c625SLionel Sambuc 			goto out;
38684d9c625SLionel Sambuc 
38784d9c625SLionel Sambuc 		vdp = (struct iso_volume_descriptor *)bp->b_data;
38884d9c625SLionel Sambuc 		if (memcmp(vdp->id, ISO_STANDARD_ID, sizeof(vdp->id)) != 0) {
38984d9c625SLionel Sambuc 			error = EINVAL;
39084d9c625SLionel Sambuc 			goto out;
39184d9c625SLionel Sambuc 		}
39284d9c625SLionel Sambuc 
39384d9c625SLionel Sambuc 		switch (isonum_711(vdp->type)) {
39484d9c625SLionel Sambuc 		case ISO_VD_PRIMARY:
39584d9c625SLionel Sambuc 			if (pribp == NULL) {
39684d9c625SLionel Sambuc 				pribp = bp;
39784d9c625SLionel Sambuc 				bp = NULL;
39884d9c625SLionel Sambuc 			}
39984d9c625SLionel Sambuc 			break;
40084d9c625SLionel Sambuc 
40184d9c625SLionel Sambuc 		case ISO_VD_SUPPLEMENTARY:
40284d9c625SLionel Sambuc 			if (supbp == NULL) {
40384d9c625SLionel Sambuc 				supbp = bp;
40484d9c625SLionel Sambuc 				bp = NULL;
40584d9c625SLionel Sambuc 			}
40684d9c625SLionel Sambuc 			break;
40784d9c625SLionel Sambuc 
40884d9c625SLionel Sambuc 		default:
40984d9c625SLionel Sambuc 			break;
41084d9c625SLionel Sambuc 		}
41184d9c625SLionel Sambuc 
41284d9c625SLionel Sambuc 		if (isonum_711 (vdp->type) == ISO_VD_END) {
41384d9c625SLionel Sambuc 			brelse(bp, 0);
41484d9c625SLionel Sambuc 			bp = NULL;
41584d9c625SLionel Sambuc 			break;
41684d9c625SLionel Sambuc 		}
41784d9c625SLionel Sambuc 
41884d9c625SLionel Sambuc 		if (bp != NULL) {
41984d9c625SLionel Sambuc 			brelse(bp, 0);
42084d9c625SLionel Sambuc 			bp = NULL;
42184d9c625SLionel Sambuc 		}
42284d9c625SLionel Sambuc 	}
42384d9c625SLionel Sambuc 
42484d9c625SLionel Sambuc 	if (pribp == NULL) {
42584d9c625SLionel Sambuc 		error = EINVAL;
42684d9c625SLionel Sambuc 		goto out;
42784d9c625SLionel Sambuc 	}
42884d9c625SLionel Sambuc 
42984d9c625SLionel Sambuc 	isomp = malloc(sizeof *isomp, M_ISOFSMNT, M_WAITOK);
43084d9c625SLionel Sambuc 	memset(isomp, 0, sizeof *isomp);
43184d9c625SLionel Sambuc 	if (iso_makemp(isomp, pribp, &ext_attr_length) == -1) {
43284d9c625SLionel Sambuc 		error = EINVAL;
43384d9c625SLionel Sambuc 		goto out;
43484d9c625SLionel Sambuc 	}
43584d9c625SLionel Sambuc 
43684d9c625SLionel Sambuc 	isomp->volume_space_size += sess;
43784d9c625SLionel Sambuc 
43884d9c625SLionel Sambuc 	brelse(pribp, BC_AGE);
43984d9c625SLionel Sambuc 	pribp = NULL;
44084d9c625SLionel Sambuc 
44184d9c625SLionel Sambuc 	mp->mnt_data = isomp;
44284d9c625SLionel Sambuc 	mp->mnt_stat.f_fsidx.__fsid_val[0] = (long)dev;
44384d9c625SLionel Sambuc 	mp->mnt_stat.f_fsidx.__fsid_val[1] = makefstype(MOUNT_CD9660);
44484d9c625SLionel Sambuc 	mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0];
44584d9c625SLionel Sambuc 	mp->mnt_stat.f_namemax = ISO_MAXNAMLEN;
44684d9c625SLionel Sambuc 	mp->mnt_flag |= MNT_LOCAL;
44784d9c625SLionel Sambuc 	mp->mnt_iflag |= IMNT_MPSAFE;
44884d9c625SLionel Sambuc 	mp->mnt_dev_bshift = iso_bsize;
44984d9c625SLionel Sambuc 	mp->mnt_fs_bshift = isomp->im_bshift;
45084d9c625SLionel Sambuc 	isomp->im_mountp = mp;
45184d9c625SLionel Sambuc 	isomp->im_dev = dev;
45284d9c625SLionel Sambuc 	isomp->im_devvp = devvp;
45384d9c625SLionel Sambuc 
45484d9c625SLionel Sambuc 	/* Check the Rock Ridge Extension support */
45584d9c625SLionel Sambuc 	if (!(argp->flags & ISOFSMNT_NORRIP)) {
45684d9c625SLionel Sambuc 		struct iso_directory_record *rootp;
45784d9c625SLionel Sambuc 
45884d9c625SLionel Sambuc 		if ((error = bread(isomp->im_devvp,
45984d9c625SLionel Sambuc 				   (isomp->root_extent + ext_attr_length) <<
46084d9c625SLionel Sambuc 				   (isomp->im_bshift - DEV_BSHIFT),
461*0a6a1f1dSLionel Sambuc 				   isomp->logical_block_size,
46284d9c625SLionel Sambuc 				   0, &bp)) != 0)
46384d9c625SLionel Sambuc 		    goto out;
46484d9c625SLionel Sambuc 
46584d9c625SLionel Sambuc 		rootp = (struct iso_directory_record *)bp->b_data;
46684d9c625SLionel Sambuc 
46784d9c625SLionel Sambuc 		if ((isomp->rr_skip = cd9660_rrip_offset(rootp,isomp)) < 0) {
46884d9c625SLionel Sambuc 		    argp->flags  |= ISOFSMNT_NORRIP;
46984d9c625SLionel Sambuc 		} else {
47084d9c625SLionel Sambuc 		    argp->flags  &= ~ISOFSMNT_GENS;
47184d9c625SLionel Sambuc 		}
47284d9c625SLionel Sambuc 
47384d9c625SLionel Sambuc 		/*
47484d9c625SLionel Sambuc 		 * The contents are valid,
47584d9c625SLionel Sambuc 		 * but they will get reread as part of another vnode, so...
47684d9c625SLionel Sambuc 		 */
47784d9c625SLionel Sambuc 		brelse(bp, BC_AGE);
47884d9c625SLionel Sambuc 		bp = NULL;
47984d9c625SLionel Sambuc 	}
48084d9c625SLionel Sambuc 	isomp->im_flags = argp->flags & (ISOFSMNT_NORRIP | ISOFSMNT_GENS |
48184d9c625SLionel Sambuc 		 ISOFSMNT_EXTATT | ISOFSMNT_NOJOLIET | ISOFSMNT_RRCASEINS);
48284d9c625SLionel Sambuc 
48384d9c625SLionel Sambuc 	if (isomp->im_flags & ISOFSMNT_GENS)
48484d9c625SLionel Sambuc 		isomp->iso_ftype = ISO_FTYPE_9660;
48584d9c625SLionel Sambuc 	else if (isomp->im_flags & ISOFSMNT_NORRIP) {
48684d9c625SLionel Sambuc 		isomp->iso_ftype = ISO_FTYPE_DEFAULT;
48784d9c625SLionel Sambuc 		if (argp->flags & ISOFSMNT_NOCASETRANS)
48884d9c625SLionel Sambuc 			isomp->im_flags |= ISOFSMNT_NOCASETRANS;
48984d9c625SLionel Sambuc 	} else
49084d9c625SLionel Sambuc 		isomp->iso_ftype = ISO_FTYPE_RRIP;
49184d9c625SLionel Sambuc 
49284d9c625SLionel Sambuc 	/* Check the Joliet Extension support */
49384d9c625SLionel Sambuc 	if ((argp->flags & ISOFSMNT_NORRIP) != 0 &&
49484d9c625SLionel Sambuc 	    (argp->flags & ISOFSMNT_NOJOLIET) == 0 &&
49584d9c625SLionel Sambuc 	    supbp != NULL) {
49684d9c625SLionel Sambuc 		joliet_level = 0;
49784d9c625SLionel Sambuc 		sup = (struct iso_supplementary_descriptor *)supbp->b_data;
49884d9c625SLionel Sambuc 
49984d9c625SLionel Sambuc 		if ((isonum_711(sup->flags) & 1) == 0) {
50084d9c625SLionel Sambuc 			if (memcmp(sup->escape, "%/@", 3) == 0)
50184d9c625SLionel Sambuc 				joliet_level = 1;
50284d9c625SLionel Sambuc 			if (memcmp(sup->escape, "%/C", 3) == 0)
50384d9c625SLionel Sambuc 				joliet_level = 2;
50484d9c625SLionel Sambuc 			if (memcmp(sup->escape, "%/E", 3) == 0)
50584d9c625SLionel Sambuc 				joliet_level = 3;
50684d9c625SLionel Sambuc 		}
50784d9c625SLionel Sambuc 		if (joliet_level != 0) {
50884d9c625SLionel Sambuc 			if (iso_makemp(isomp, supbp, NULL) == -1) {
50984d9c625SLionel Sambuc 				error = EINVAL;
51084d9c625SLionel Sambuc 				goto out;
51184d9c625SLionel Sambuc 			}
51284d9c625SLionel Sambuc 			isomp->im_joliet_level = joliet_level;
51384d9c625SLionel Sambuc 		}
51484d9c625SLionel Sambuc 	}
51584d9c625SLionel Sambuc 
51684d9c625SLionel Sambuc 	if (supbp != NULL) {
51784d9c625SLionel Sambuc 		brelse(supbp, 0);
51884d9c625SLionel Sambuc 		supbp = NULL;
51984d9c625SLionel Sambuc 	}
52084d9c625SLionel Sambuc 
52184d9c625SLionel Sambuc 	spec_node_setmountedfs(devvp, mp);
52284d9c625SLionel Sambuc 
52384d9c625SLionel Sambuc 	return 0;
52484d9c625SLionel Sambuc out:
52584d9c625SLionel Sambuc 	if (bp)
52684d9c625SLionel Sambuc 		brelse(bp, 0);
52784d9c625SLionel Sambuc 	if (pribp)
52884d9c625SLionel Sambuc 		brelse(pribp, 0);
52984d9c625SLionel Sambuc 	if (supbp)
53084d9c625SLionel Sambuc 		brelse(supbp, 0);
53184d9c625SLionel Sambuc 	if (isomp) {
53284d9c625SLionel Sambuc 		free(isomp, M_ISOFSMNT);
53384d9c625SLionel Sambuc 		mp->mnt_data = NULL;
53484d9c625SLionel Sambuc 	}
53584d9c625SLionel Sambuc 	return error;
53684d9c625SLionel Sambuc }
53784d9c625SLionel Sambuc 
53884d9c625SLionel Sambuc /*
53984d9c625SLionel Sambuc  * Make a filesystem operational.
54084d9c625SLionel Sambuc  * Nothing to do at the moment.
54184d9c625SLionel Sambuc  */
54284d9c625SLionel Sambuc /* ARGSUSED */
54384d9c625SLionel Sambuc int
cd9660_start(struct mount * mp,int flags)54484d9c625SLionel Sambuc cd9660_start(struct mount *mp, int flags)
54584d9c625SLionel Sambuc {
54684d9c625SLionel Sambuc 	return 0;
54784d9c625SLionel Sambuc }
54884d9c625SLionel Sambuc 
54984d9c625SLionel Sambuc /*
55084d9c625SLionel Sambuc  * unmount system call
55184d9c625SLionel Sambuc  */
55284d9c625SLionel Sambuc int
cd9660_unmount(struct mount * mp,int mntflags)55384d9c625SLionel Sambuc cd9660_unmount(struct mount *mp, int mntflags)
55484d9c625SLionel Sambuc {
55584d9c625SLionel Sambuc 	struct iso_mnt *isomp;
55684d9c625SLionel Sambuc 	int error, flags = 0;
55784d9c625SLionel Sambuc 
55884d9c625SLionel Sambuc 	if (mntflags & MNT_FORCE)
55984d9c625SLionel Sambuc 		flags |= FORCECLOSE;
56084d9c625SLionel Sambuc 	if ((error = vflush(mp, NULLVP, flags)) != 0)
56184d9c625SLionel Sambuc 		return (error);
56284d9c625SLionel Sambuc 
56384d9c625SLionel Sambuc 	isomp = VFSTOISOFS(mp);
56484d9c625SLionel Sambuc 
56584d9c625SLionel Sambuc 	if (isomp->im_devvp->v_type != VBAD)
56684d9c625SLionel Sambuc 		spec_node_setmountedfs(isomp->im_devvp, NULL);
56784d9c625SLionel Sambuc 
56884d9c625SLionel Sambuc 	vn_lock(isomp->im_devvp, LK_EXCLUSIVE | LK_RETRY);
56984d9c625SLionel Sambuc 	error = VOP_CLOSE(isomp->im_devvp, FREAD, NOCRED);
57084d9c625SLionel Sambuc 	vput(isomp->im_devvp);
57184d9c625SLionel Sambuc 	free(isomp, M_ISOFSMNT);
57284d9c625SLionel Sambuc 	mp->mnt_data = NULL;
57384d9c625SLionel Sambuc 	mp->mnt_flag &= ~MNT_LOCAL;
57484d9c625SLionel Sambuc 	return (error);
57584d9c625SLionel Sambuc }
57684d9c625SLionel Sambuc 
57784d9c625SLionel Sambuc /*
57884d9c625SLionel Sambuc  * Return root of a filesystem
57984d9c625SLionel Sambuc  */
58084d9c625SLionel Sambuc int
cd9660_root(struct mount * mp,struct vnode ** vpp)58184d9c625SLionel Sambuc cd9660_root(struct mount *mp, struct vnode **vpp)
58284d9c625SLionel Sambuc {
58384d9c625SLionel Sambuc 	struct iso_mnt *imp = VFSTOISOFS(mp);
58484d9c625SLionel Sambuc 	struct iso_directory_record *dp =
58584d9c625SLionel Sambuc 	    (struct iso_directory_record *)imp->root;
58684d9c625SLionel Sambuc 	ino_t ino = isodirino(dp, imp);
58784d9c625SLionel Sambuc 
588*0a6a1f1dSLionel Sambuc 	return cd9660_vget(mp, ino, vpp);
58984d9c625SLionel Sambuc }
59084d9c625SLionel Sambuc 
59184d9c625SLionel Sambuc /*
59284d9c625SLionel Sambuc  * Get file system statistics.
59384d9c625SLionel Sambuc  */
59484d9c625SLionel Sambuc int
cd9660_statvfs(struct mount * mp,struct statvfs * sbp)59584d9c625SLionel Sambuc cd9660_statvfs(struct mount *mp, struct statvfs *sbp)
59684d9c625SLionel Sambuc {
59784d9c625SLionel Sambuc 	struct iso_mnt *isomp;
59884d9c625SLionel Sambuc 
59984d9c625SLionel Sambuc 	isomp = VFSTOISOFS(mp);
60084d9c625SLionel Sambuc 
60184d9c625SLionel Sambuc 	sbp->f_bsize = isomp->logical_block_size;
60284d9c625SLionel Sambuc 	sbp->f_frsize = sbp->f_bsize;
60384d9c625SLionel Sambuc 	sbp->f_iosize = sbp->f_bsize;	/* XXX */
60484d9c625SLionel Sambuc 	sbp->f_blocks = isomp->volume_space_size;
60584d9c625SLionel Sambuc 	sbp->f_bfree = 0; /* total free blocks */
60684d9c625SLionel Sambuc 	sbp->f_bavail = 0; /* blocks free for non superuser */
60784d9c625SLionel Sambuc 	sbp->f_bresvd = 0; /* total reserved blocks */
60884d9c625SLionel Sambuc 	sbp->f_files =  0; /* total files */
60984d9c625SLionel Sambuc 	sbp->f_ffree = 0; /* free file nodes */
61084d9c625SLionel Sambuc 	sbp->f_favail = 0; /* free file nodes for non superuser */
61184d9c625SLionel Sambuc 	sbp->f_fresvd = 0; /* reserved file nodes */
61284d9c625SLionel Sambuc 	copy_statvfs_info(sbp, mp);
61384d9c625SLionel Sambuc 	/* Use the first spare for flags: */
61484d9c625SLionel Sambuc 	sbp->f_spare[0] = isomp->im_flags;
61584d9c625SLionel Sambuc 	return 0;
61684d9c625SLionel Sambuc }
61784d9c625SLionel Sambuc 
61884d9c625SLionel Sambuc /* ARGSUSED */
61984d9c625SLionel Sambuc int
cd9660_sync(struct mount * mp,int waitfor,kauth_cred_t cred)62084d9c625SLionel Sambuc cd9660_sync(struct mount *mp, int waitfor, kauth_cred_t cred)
62184d9c625SLionel Sambuc {
62284d9c625SLionel Sambuc 	return 0;
62384d9c625SLionel Sambuc }
62484d9c625SLionel Sambuc 
62584d9c625SLionel Sambuc /*
62684d9c625SLionel Sambuc  * File handle to vnode
62784d9c625SLionel Sambuc  *
62884d9c625SLionel Sambuc  * Have to be really careful about stale file handles:
62984d9c625SLionel Sambuc  * - check that the inode number is in range
63084d9c625SLionel Sambuc  * - call iget() to get the locked inode
63184d9c625SLionel Sambuc  * - check for an unallocated inode (i_mode == 0)
63284d9c625SLionel Sambuc  * - check that the generation number matches
63384d9c625SLionel Sambuc  */
63484d9c625SLionel Sambuc 
63584d9c625SLionel Sambuc struct ifid {
63684d9c625SLionel Sambuc 	ushort	ifid_len;
63784d9c625SLionel Sambuc 	ushort	ifid_pad;
638*0a6a1f1dSLionel Sambuc 	ino_t	ifid_ino;
639*0a6a1f1dSLionel Sambuc #ifdef	ISOFS_DBG
640*0a6a1f1dSLionel Sambuc 	u_long	ifid_start;
641*0a6a1f1dSLionel Sambuc #endif
64284d9c625SLionel Sambuc };
64384d9c625SLionel Sambuc 
64484d9c625SLionel Sambuc /* ARGSUSED */
64584d9c625SLionel Sambuc int
cd9660_fhtovp(struct mount * mp,struct fid * fhp,struct vnode ** vpp)64684d9c625SLionel Sambuc cd9660_fhtovp(struct mount *mp, struct fid *fhp, struct vnode **vpp)
64784d9c625SLionel Sambuc {
64884d9c625SLionel Sambuc 	struct ifid ifh;
64984d9c625SLionel Sambuc 	struct iso_node *ip;
65084d9c625SLionel Sambuc 	struct vnode *nvp;
65184d9c625SLionel Sambuc 	int error;
65284d9c625SLionel Sambuc 
65384d9c625SLionel Sambuc 	if (fhp->fid_len != sizeof(ifh))
65484d9c625SLionel Sambuc 		return EINVAL;
65584d9c625SLionel Sambuc 
65684d9c625SLionel Sambuc 	memcpy(&ifh, fhp, sizeof(ifh));
65784d9c625SLionel Sambuc #ifdef	ISOFS_DBG
658*0a6a1f1dSLionel Sambuc 	printf("fhtovp: ino %"PRIu64", start %lu\n",
65984d9c625SLionel Sambuc 	    ifh.ifid_ino, ifh.ifid_start);
66084d9c625SLionel Sambuc #endif
66184d9c625SLionel Sambuc 
66284d9c625SLionel Sambuc 	if ((error = VFS_VGET(mp, ifh.ifid_ino, &nvp)) != 0) {
66384d9c625SLionel Sambuc 		*vpp = NULLVP;
66484d9c625SLionel Sambuc 		return (error);
66584d9c625SLionel Sambuc 	}
66684d9c625SLionel Sambuc 	ip = VTOI(nvp);
66784d9c625SLionel Sambuc 	if (ip->inode.iso_mode == 0) {
66884d9c625SLionel Sambuc 		vput(nvp);
66984d9c625SLionel Sambuc 		*vpp = NULLVP;
67084d9c625SLionel Sambuc 		return (ESTALE);
67184d9c625SLionel Sambuc 	}
67284d9c625SLionel Sambuc 	*vpp = nvp;
67384d9c625SLionel Sambuc 	return (0);
67484d9c625SLionel Sambuc }
67584d9c625SLionel Sambuc 
67684d9c625SLionel Sambuc int
cd9660_vget(struct mount * mp,ino_t ino,struct vnode ** vpp)67784d9c625SLionel Sambuc cd9660_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
67884d9c625SLionel Sambuc {
679*0a6a1f1dSLionel Sambuc 	int error;
68084d9c625SLionel Sambuc 
681*0a6a1f1dSLionel Sambuc 	error = vcache_get(mp, &ino, sizeof(ino), vpp);
682*0a6a1f1dSLionel Sambuc 	if (error)
683*0a6a1f1dSLionel Sambuc 		return error;
684*0a6a1f1dSLionel Sambuc 	error = vn_lock(*vpp, LK_EXCLUSIVE);
685*0a6a1f1dSLionel Sambuc 	if (error) {
686*0a6a1f1dSLionel Sambuc 		vrele(*vpp);
687*0a6a1f1dSLionel Sambuc 		*vpp = NULL;
688*0a6a1f1dSLionel Sambuc 		return error;
689*0a6a1f1dSLionel Sambuc 	}
690*0a6a1f1dSLionel Sambuc 	return 0;
69184d9c625SLionel Sambuc }
69284d9c625SLionel Sambuc 
69384d9c625SLionel Sambuc int
cd9660_loadvnode(struct mount * mp,struct vnode * vp,const void * key,size_t key_len,const void ** new_key)694*0a6a1f1dSLionel Sambuc cd9660_loadvnode(struct mount *mp, struct vnode *vp,
695*0a6a1f1dSLionel Sambuc     const void *key, size_t key_len, const void **new_key)
69684d9c625SLionel Sambuc {
69784d9c625SLionel Sambuc 	struct iso_mnt *imp;
69884d9c625SLionel Sambuc 	struct iso_node *ip;
699*0a6a1f1dSLionel Sambuc 	struct iso_directory_record *isodir;
70084d9c625SLionel Sambuc 	struct buf *bp;
70184d9c625SLionel Sambuc 	dev_t dev;
702*0a6a1f1dSLionel Sambuc 	ino_t ino;
703*0a6a1f1dSLionel Sambuc 	int lbn, off;
70484d9c625SLionel Sambuc 	int error;
70584d9c625SLionel Sambuc 
706*0a6a1f1dSLionel Sambuc 	KASSERT(key_len == sizeof(ino));
707*0a6a1f1dSLionel Sambuc 	memcpy(&ino, key, key_len);
70884d9c625SLionel Sambuc 	imp = VFSTOISOFS(mp);
70984d9c625SLionel Sambuc 	dev = imp->im_dev;
71084d9c625SLionel Sambuc 
71184d9c625SLionel Sambuc 	ip = pool_get(&cd9660_node_pool, PR_WAITOK);
71284d9c625SLionel Sambuc 
71384d9c625SLionel Sambuc 	memset(ip, 0, sizeof(struct iso_node));
71484d9c625SLionel Sambuc 	ip->i_vnode = vp;
71584d9c625SLionel Sambuc 	ip->i_dev = dev;
71684d9c625SLionel Sambuc 	ip->i_number = ino;
71784d9c625SLionel Sambuc 	ip->i_mnt = imp;
71884d9c625SLionel Sambuc 	ip->i_devvp = imp->im_devvp;
71984d9c625SLionel Sambuc 
72084d9c625SLionel Sambuc 	lbn = cd9660_lblkno(imp, ino);
72184d9c625SLionel Sambuc 	if (lbn >= imp->volume_space_size) {
722*0a6a1f1dSLionel Sambuc 		pool_put(&cd9660_node_pool, ip);
72384d9c625SLionel Sambuc 		printf("fhtovp: lbn exceed volume space %d\n", lbn);
72484d9c625SLionel Sambuc 		return (ESTALE);
72584d9c625SLionel Sambuc 	}
72684d9c625SLionel Sambuc 
72784d9c625SLionel Sambuc 	off = cd9660_blkoff(imp, ino);
72884d9c625SLionel Sambuc 	if (off + ISO_DIRECTORY_RECORD_SIZE > imp->logical_block_size) {
729*0a6a1f1dSLionel Sambuc 		pool_put(&cd9660_node_pool, ip);
73084d9c625SLionel Sambuc 		printf("fhtovp: crosses block boundary %d\n",
73184d9c625SLionel Sambuc 		    off + ISO_DIRECTORY_RECORD_SIZE);
73284d9c625SLionel Sambuc 		return (ESTALE);
73384d9c625SLionel Sambuc 	}
73484d9c625SLionel Sambuc 
73584d9c625SLionel Sambuc 	error = bread(imp->im_devvp,
73684d9c625SLionel Sambuc 		      lbn << (imp->im_bshift - DEV_BSHIFT),
737*0a6a1f1dSLionel Sambuc 		      imp->logical_block_size, 0, &bp);
73884d9c625SLionel Sambuc 	if (error) {
739*0a6a1f1dSLionel Sambuc 		pool_put(&cd9660_node_pool, ip);
74084d9c625SLionel Sambuc 		printf("fhtovp: bread error %d\n",error);
74184d9c625SLionel Sambuc 		return (error);
74284d9c625SLionel Sambuc 	}
74384d9c625SLionel Sambuc 	isodir = (struct iso_directory_record *)((char *)bp->b_data + off);
74484d9c625SLionel Sambuc 
745*0a6a1f1dSLionel Sambuc 	if (off + isonum_711(isodir->length) > imp->logical_block_size) {
746*0a6a1f1dSLionel Sambuc 		pool_put(&cd9660_node_pool, ip);
74784d9c625SLionel Sambuc 		brelse(bp, 0);
74884d9c625SLionel Sambuc 		printf("fhtovp: directory crosses block boundary %d[off=%d/len=%d]\n",
74984d9c625SLionel Sambuc 		    off +isonum_711(isodir->length), off,
75084d9c625SLionel Sambuc 		    isonum_711(isodir->length));
75184d9c625SLionel Sambuc 		return (ESTALE);
75284d9c625SLionel Sambuc 	}
75384d9c625SLionel Sambuc 
75484d9c625SLionel Sambuc #if 0
75584d9c625SLionel Sambuc 	if (isonum_733(isodir->extent) +
75684d9c625SLionel Sambuc 	    isonum_711(isodir->ext_attr_length) != ifhp->ifid_start) {
757*0a6a1f1dSLionel Sambuc 		pool_put(&cd9660_node_pool, ip);
75884d9c625SLionel Sambuc 		if (bp != 0)
75984d9c625SLionel Sambuc 			brelse(bp, 0);
76084d9c625SLionel Sambuc 		printf("fhtovp: file start miss %d vs %d\n",
76184d9c625SLionel Sambuc 		    isonum_733(isodir->extent) + isonum_711(isodir->ext_attr_length),
76284d9c625SLionel Sambuc 		    ifhp->ifid_start);
76384d9c625SLionel Sambuc 		return (ESTALE);
76484d9c625SLionel Sambuc 	}
76584d9c625SLionel Sambuc #endif
76684d9c625SLionel Sambuc 
76784d9c625SLionel Sambuc 	ip->iso_extent = isonum_733(isodir->extent);
76884d9c625SLionel Sambuc 	ip->i_size = isonum_733(isodir->size);
76984d9c625SLionel Sambuc 	ip->iso_start = isonum_711(isodir->ext_attr_length) + ip->iso_extent;
77084d9c625SLionel Sambuc 
771*0a6a1f1dSLionel Sambuc 	vp->v_tag = VT_ISOFS;
772*0a6a1f1dSLionel Sambuc 	vp->v_op = cd9660_vnodeop_p;
773*0a6a1f1dSLionel Sambuc 	vp->v_data = ip;
774*0a6a1f1dSLionel Sambuc 	genfs_node_init(vp, &cd9660_genfsops);
775*0a6a1f1dSLionel Sambuc 
77684d9c625SLionel Sambuc 	/*
77784d9c625SLionel Sambuc 	 * Setup time stamp, attribute
77884d9c625SLionel Sambuc 	 */
77984d9c625SLionel Sambuc 	switch (imp->iso_ftype) {
78084d9c625SLionel Sambuc 	default:	/* ISO_FTYPE_9660 */
78184d9c625SLionel Sambuc 	    {
78284d9c625SLionel Sambuc 		struct buf *bp2;
78384d9c625SLionel Sambuc 		if ((imp->im_flags & ISOFSMNT_EXTATT)
78484d9c625SLionel Sambuc 		    && (off = isonum_711(isodir->ext_attr_length)))
78584d9c625SLionel Sambuc 			cd9660_blkatoff(vp, (off_t)-(off << imp->im_bshift),
78684d9c625SLionel Sambuc 			    NULL, &bp2);
78784d9c625SLionel Sambuc 		else
78884d9c625SLionel Sambuc 			bp2 = NULL;
78984d9c625SLionel Sambuc 		cd9660_defattr(isodir, ip, bp2);
79084d9c625SLionel Sambuc 		cd9660_deftstamp(isodir, ip, bp2);
79184d9c625SLionel Sambuc 		if (bp2)
79284d9c625SLionel Sambuc 			brelse(bp2, 0);
79384d9c625SLionel Sambuc 		break;
79484d9c625SLionel Sambuc 	    }
79584d9c625SLionel Sambuc 	case ISO_FTYPE_RRIP:
79684d9c625SLionel Sambuc 		cd9660_rrip_analyze(isodir, ip, imp);
79784d9c625SLionel Sambuc 		break;
79884d9c625SLionel Sambuc 	}
79984d9c625SLionel Sambuc 
80084d9c625SLionel Sambuc 	brelse(bp, 0);
80184d9c625SLionel Sambuc 
80284d9c625SLionel Sambuc 	/*
80384d9c625SLionel Sambuc 	 * Initialize the associated vnode
80484d9c625SLionel Sambuc 	 */
80584d9c625SLionel Sambuc 	switch (vp->v_type = IFTOVT(ip->inode.iso_mode)) {
80684d9c625SLionel Sambuc 	case VFIFO:
80784d9c625SLionel Sambuc 		vp->v_op = cd9660_fifoop_p;
80884d9c625SLionel Sambuc 		break;
80984d9c625SLionel Sambuc 	case VCHR:
81084d9c625SLionel Sambuc 	case VBLK:
81184d9c625SLionel Sambuc 		/*
81284d9c625SLionel Sambuc 		 * if device, look at device number table for translation
81384d9c625SLionel Sambuc 		 */
81484d9c625SLionel Sambuc 		vp->v_op = cd9660_specop_p;
81584d9c625SLionel Sambuc 		spec_node_init(vp, ip->inode.iso_rdev);
81684d9c625SLionel Sambuc 		break;
81784d9c625SLionel Sambuc 	case VLNK:
81884d9c625SLionel Sambuc 	case VNON:
81984d9c625SLionel Sambuc 	case VSOCK:
82084d9c625SLionel Sambuc 	case VDIR:
82184d9c625SLionel Sambuc 	case VBAD:
82284d9c625SLionel Sambuc 		break;
82384d9c625SLionel Sambuc 	case VREG:
82484d9c625SLionel Sambuc 		uvm_vnp_setsize(vp, ip->i_size);
82584d9c625SLionel Sambuc 		break;
82684d9c625SLionel Sambuc 	}
82784d9c625SLionel Sambuc 
82884d9c625SLionel Sambuc 	if (vp->v_type != VREG)
82984d9c625SLionel Sambuc 		uvm_vnp_setsize(vp, 0);
83084d9c625SLionel Sambuc 
83184d9c625SLionel Sambuc 	if (ip->iso_extent == imp->root_extent)
83284d9c625SLionel Sambuc 		vp->v_vflag |= VV_ROOT;
83384d9c625SLionel Sambuc 
83484d9c625SLionel Sambuc 	/*
83584d9c625SLionel Sambuc 	 * XXX need generation number?
83684d9c625SLionel Sambuc 	 */
83784d9c625SLionel Sambuc 
838*0a6a1f1dSLionel Sambuc 	*new_key = &ip->i_number;
839*0a6a1f1dSLionel Sambuc 	return 0;
84084d9c625SLionel Sambuc }
84184d9c625SLionel Sambuc 
84284d9c625SLionel Sambuc /*
84384d9c625SLionel Sambuc  * Vnode pointer to File handle
84484d9c625SLionel Sambuc  */
84584d9c625SLionel Sambuc /* ARGSUSED */
84684d9c625SLionel Sambuc int
cd9660_vptofh(struct vnode * vp,struct fid * fhp,size_t * fh_size)84784d9c625SLionel Sambuc cd9660_vptofh(struct vnode *vp, struct fid *fhp, size_t *fh_size)
84884d9c625SLionel Sambuc {
84984d9c625SLionel Sambuc 	struct iso_node *ip = VTOI(vp);
85084d9c625SLionel Sambuc 	struct ifid ifh;
85184d9c625SLionel Sambuc 
85284d9c625SLionel Sambuc 	if (*fh_size < sizeof(struct ifid)) {
85384d9c625SLionel Sambuc 		*fh_size = sizeof(struct ifid);
85484d9c625SLionel Sambuc 		return E2BIG;
85584d9c625SLionel Sambuc 	}
85684d9c625SLionel Sambuc 	*fh_size = sizeof(struct ifid);
85784d9c625SLionel Sambuc 
85884d9c625SLionel Sambuc 	memset(&ifh, 0, sizeof(ifh));
85984d9c625SLionel Sambuc 	ifh.ifid_len = sizeof(struct ifid);
86084d9c625SLionel Sambuc 	ifh.ifid_ino = ip->i_number;
861*0a6a1f1dSLionel Sambuc #ifdef	ISOFS_DBG
86284d9c625SLionel Sambuc 	ifh.ifid_start = ip->iso_start;
863*0a6a1f1dSLionel Sambuc #endif
86484d9c625SLionel Sambuc 	memcpy(fhp, &ifh, sizeof(ifh));
86584d9c625SLionel Sambuc 
86684d9c625SLionel Sambuc #ifdef	ISOFS_DBG
867*0a6a1f1dSLionel Sambuc 	printf("vptofh: ino %"PRIu64", start %lu\n",
86884d9c625SLionel Sambuc 	    ifh.ifid_ino,ifh.ifid_start);
86984d9c625SLionel Sambuc #endif
87084d9c625SLionel Sambuc 	return 0;
87184d9c625SLionel Sambuc }
872