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