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