1 /*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1994
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley
8 * by Pace Willisson (pace@blitz.com). The Rock Ridge Extension
9 * Support code is derived from software contributed to Berkeley
10 * by Atsushi Murai (amurai@spec.co.jp).
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 * 3. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 * @(#)cd9660_vfsops.c 8.18 (Berkeley) 5/22/95
37 */
38
39 #include <sys/cdefs.h>
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/namei.h>
43 #include <sys/priv.h>
44 #include <sys/proc.h>
45 #include <sys/kernel.h>
46 #include <sys/vnode.h>
47 #include <sys/mount.h>
48 #include <sys/bio.h>
49 #include <sys/buf.h>
50 #include <sys/cdio.h>
51 #include <sys/conf.h>
52 #include <sys/fcntl.h>
53 #include <sys/malloc.h>
54 #include <sys/stat.h>
55 #include <sys/syslog.h>
56 #include <sys/iconv.h>
57
58 #include <fs/cd9660/iso.h>
59 #include <fs/cd9660/iso_rrip.h>
60 #include <fs/cd9660/cd9660_node.h>
61 #include <fs/cd9660/cd9660_mount.h>
62
63 #include <geom/geom.h>
64 #include <geom/geom_vfs.h>
65
66 MALLOC_DEFINE(M_ISOFSMNT, "isofs_mount", "ISOFS mount structure");
67 MALLOC_DEFINE(M_ISOFSNODE, "isofs_node", "ISOFS vnode private part");
68
69 struct iconv_functions *cd9660_iconv = NULL;
70
71 static vfs_mount_t cd9660_mount;
72 static vfs_cmount_t cd9660_cmount;
73 static vfs_unmount_t cd9660_unmount;
74 static vfs_root_t cd9660_root;
75 static vfs_statfs_t cd9660_statfs;
76 static vfs_vget_t cd9660_vget;
77 static vfs_fhtovp_t cd9660_fhtovp;
78
79 static struct vfsops cd9660_vfsops = {
80 .vfs_fhtovp = cd9660_fhtovp,
81 .vfs_mount = cd9660_mount,
82 .vfs_cmount = cd9660_cmount,
83 .vfs_root = cd9660_root,
84 .vfs_statfs = cd9660_statfs,
85 .vfs_unmount = cd9660_unmount,
86 .vfs_vget = cd9660_vget,
87 };
88 VFS_SET(cd9660_vfsops, cd9660, VFCF_READONLY);
89 MODULE_VERSION(cd9660, 1);
90
91 static int cd9660_vfs_hash_cmp(struct vnode *vp, void *pino);
92 static int iso_mountfs(struct vnode *devvp, struct mount *mp);
93
94 /*
95 * VFS Operations.
96 */
97
98 static int
cd9660_cmount(struct mntarg * ma,void * data,uint64_t flags)99 cd9660_cmount(struct mntarg *ma, void *data, uint64_t flags)
100 {
101 struct iso_args args;
102 int error;
103
104 error = copyin(data, &args, sizeof args);
105 if (error)
106 return (error);
107
108 ma = mount_argsu(ma, "from", args.fspec, MAXPATHLEN);
109 ma = mount_arg(ma, "export", &args.export, sizeof(args.export));
110 if (args.flags & ISOFSMNT_UID)
111 ma = mount_argf(ma, "uid", "%d", args.uid);
112 if (args.flags & ISOFSMNT_GID)
113 ma = mount_argf(ma, "gid", "%d", args.gid);
114 ma = mount_argf(ma, "mask", "%d", args.fmask);
115 ma = mount_argf(ma, "dirmask", "%d", args.dmask);
116 ma = mount_argsu(ma, "cs_disk", args.cs_disk, 64);
117 ma = mount_argsu(ma, "cs_local", args.cs_local, 64);
118 ma = mount_argf(ma, "ssector", "%u", args.ssector);
119 ma = mount_argb(ma, !(args.flags & ISOFSMNT_NORRIP), "norrip");
120 ma = mount_argb(ma, args.flags & ISOFSMNT_GENS, "nogens");
121 ma = mount_argb(ma, args.flags & ISOFSMNT_EXTATT, "noextatt");
122 ma = mount_argb(ma, !(args.flags & ISOFSMNT_NOJOLIET), "nojoliet");
123 ma = mount_argb(ma,
124 args.flags & ISOFSMNT_BROKENJOLIET, "nobrokenjoliet");
125 ma = mount_argb(ma, args.flags & ISOFSMNT_KICONV, "nokiconv");
126
127 error = kernel_mount(ma, flags);
128
129 return (error);
130 }
131
132 static int
cd9660_mount(struct mount * mp)133 cd9660_mount(struct mount *mp)
134 {
135 struct vnode *devvp;
136 struct thread *td;
137 char *fspec;
138 int error;
139 accmode_t accmode;
140 struct nameidata ndp;
141 struct iso_mnt *imp = NULL;
142
143 td = curthread;
144
145 /*
146 * Unconditionally mount as read-only.
147 */
148 MNT_ILOCK(mp);
149 mp->mnt_flag |= MNT_RDONLY;
150 MNT_IUNLOCK(mp);
151
152 fspec = vfs_getopts(mp->mnt_optnew, "from", &error);
153 if (error)
154 return (error);
155
156 imp = VFSTOISOFS(mp);
157
158 if (mp->mnt_flag & MNT_UPDATE) {
159 if (vfs_flagopt(mp->mnt_optnew, "export", NULL, 0))
160 return (0);
161 }
162 /*
163 * Not an update, or updating the name: look up the name
164 * and verify that it refers to a sensible block device.
165 */
166 NDINIT(&ndp, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, fspec, td);
167 if ((error = namei(&ndp)))
168 return (error);
169 NDFREE(&ndp, NDF_ONLY_PNBUF);
170 devvp = ndp.ni_vp;
171
172 if (!vn_isdisk_error(devvp, &error)) {
173 vput(devvp);
174 return (error);
175 }
176
177 /*
178 * Verify that user has necessary permissions on the device,
179 * or has superuser abilities
180 */
181 accmode = VREAD;
182 error = VOP_ACCESS(devvp, accmode, td->td_ucred, td);
183 if (error)
184 error = priv_check(td, PRIV_VFS_MOUNT_PERM);
185 if (error) {
186 vput(devvp);
187 return (error);
188 }
189
190 if ((mp->mnt_flag & MNT_UPDATE) == 0) {
191 error = iso_mountfs(devvp, mp);
192 if (error)
193 vrele(devvp);
194 } else {
195 if (devvp != imp->im_devvp)
196 error = EINVAL; /* needs translation */
197 vput(devvp);
198 }
199 if (error)
200 return (error);
201 vfs_mountedfrom(mp, fspec);
202 return (0);
203 }
204
205 /*
206 * Common code for mount and mountroot
207 */
208 static int
iso_mountfs(devvp,mp)209 iso_mountfs(devvp, mp)
210 struct vnode *devvp;
211 struct mount *mp;
212 {
213 struct iso_mnt *isomp = NULL;
214 struct buf *bp = NULL;
215 struct buf *pribp = NULL, *supbp = NULL;
216 struct cdev *dev;
217 int error = EINVAL;
218 int high_sierra = 0;
219 int iso_bsize;
220 int iso_blknum;
221 int joliet_level;
222 int isverified = 0;
223 struct iso_volume_descriptor *vdp = NULL;
224 struct iso_primary_descriptor *pri = NULL;
225 struct iso_sierra_primary_descriptor *pri_sierra = NULL;
226 struct iso_supplementary_descriptor *sup = NULL;
227 struct iso_directory_record *rootp;
228 int logical_block_size, ssector;
229 struct g_consumer *cp;
230 struct bufobj *bo;
231 char *cs_local, *cs_disk;
232 int v;
233
234 dev = devvp->v_rdev;
235 dev_ref(dev);
236 g_topology_lock();
237 error = g_vfs_open(devvp, &cp, "cd9660", 0);
238 if (error == 0)
239 g_getattr("MNT::verified", cp, &isverified);
240 g_topology_unlock();
241 VOP_UNLOCK(devvp);
242 if (error)
243 goto out;
244 if (devvp->v_rdev->si_iosize_max != 0)
245 mp->mnt_iosize_max = devvp->v_rdev->si_iosize_max;
246 if (mp->mnt_iosize_max > maxphys)
247 mp->mnt_iosize_max = maxphys;
248
249 bo = &devvp->v_bufobj;
250
251 /* This is the "logical sector size". The standard says this
252 * should be 2048 or the physical sector size on the device,
253 * whichever is greater.
254 */
255 if ((ISO_DEFAULT_BLOCK_SIZE % cp->provider->sectorsize) != 0) {
256 error = EINVAL;
257 goto out;
258 }
259
260 iso_bsize = cp->provider->sectorsize;
261
262 joliet_level = 0;
263 if (1 != vfs_scanopt(mp->mnt_optnew, "ssector", "%d", &ssector))
264 ssector = 0;
265 for (iso_blknum = 16 + ssector;
266 iso_blknum < 100 + ssector;
267 iso_blknum++) {
268 if ((error = bread(devvp, iso_blknum * btodb(ISO_DEFAULT_BLOCK_SIZE),
269 iso_bsize, NOCRED, &bp)) != 0)
270 goto out;
271
272 vdp = (struct iso_volume_descriptor *)bp->b_data;
273 if (bcmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) != 0) {
274 if (bcmp (vdp->id_sierra, ISO_SIERRA_ID,
275 sizeof vdp->id_sierra) != 0) {
276 error = EINVAL;
277 goto out;
278 } else
279 high_sierra = 1;
280 }
281 switch (isonum_711 (high_sierra? vdp->type_sierra: vdp->type)){
282 case ISO_VD_PRIMARY:
283 if (pribp == NULL) {
284 pribp = bp;
285 bp = NULL;
286 pri = (struct iso_primary_descriptor *)vdp;
287 pri_sierra =
288 (struct iso_sierra_primary_descriptor *)vdp;
289 }
290 break;
291
292 case ISO_VD_SUPPLEMENTARY:
293 if (supbp == NULL) {
294 supbp = bp;
295 bp = NULL;
296 sup = (struct iso_supplementary_descriptor *)vdp;
297
298 if (!vfs_flagopt(mp->mnt_optnew, "nojoliet", NULL, 0)) {
299 if (bcmp(sup->escape, "%/@", 3) == 0)
300 joliet_level = 1;
301 if (bcmp(sup->escape, "%/C", 3) == 0)
302 joliet_level = 2;
303 if (bcmp(sup->escape, "%/E", 3) == 0)
304 joliet_level = 3;
305
306 if ((isonum_711 (sup->flags) & 1) &&
307 !vfs_flagopt(mp->mnt_optnew, "brokenjoliet", NULL, 0))
308 joliet_level = 0;
309 }
310 }
311 break;
312
313 case ISO_VD_END:
314 goto vd_end;
315
316 default:
317 break;
318 }
319 if (bp != NULL) {
320 brelse(bp);
321 bp = NULL;
322 }
323 }
324 vd_end:
325 if (bp != NULL) {
326 brelse(bp);
327 bp = NULL;
328 }
329
330 if (pri == NULL) {
331 error = EINVAL;
332 goto out;
333 }
334
335 logical_block_size =
336 isonum_723 (high_sierra?
337 pri_sierra->logical_block_size:
338 pri->logical_block_size);
339
340 if (logical_block_size < DEV_BSIZE || logical_block_size > MAXBSIZE
341 || (logical_block_size & (logical_block_size - 1)) != 0) {
342 error = EINVAL;
343 goto out;
344 }
345
346 if (logical_block_size < cp->provider->sectorsize) {
347 printf("cd9660: Unsupported logical block size %u\n",
348 logical_block_size);
349 error = EINVAL;
350 goto out;
351 }
352
353 rootp = (struct iso_directory_record *)
354 (high_sierra?
355 pri_sierra->root_directory_record:
356 pri->root_directory_record);
357
358 isomp = malloc(sizeof *isomp, M_ISOFSMNT, M_WAITOK | M_ZERO);
359 isomp->im_cp = cp;
360 isomp->im_bo = bo;
361 isomp->logical_block_size = logical_block_size;
362 isomp->volume_space_size =
363 isonum_733 (high_sierra?
364 pri_sierra->volume_space_size:
365 pri->volume_space_size);
366 isomp->joliet_level = 0;
367 /*
368 * Since an ISO9660 multi-session CD can also access previous
369 * sessions, we have to include them into the space consider-
370 * ations. This doesn't yield a very accurate number since
371 * parts of the old sessions might be inaccessible now, but we
372 * can't do much better. This is also important for the NFS
373 * filehandle validation.
374 */
375 isomp->volume_space_size += ssector;
376 memcpy(isomp->root, rootp, sizeof isomp->root);
377 isomp->root_extent = isonum_733 (rootp->extent);
378 isomp->root_size = isonum_733 (rootp->size);
379
380 isomp->im_bmask = logical_block_size - 1;
381 isomp->im_bshift = ffs(logical_block_size) - 1;
382
383 pribp->b_flags |= B_AGE;
384 brelse(pribp);
385 pribp = NULL;
386 rootp = NULL;
387 pri = NULL;
388 pri_sierra = NULL;
389
390 mp->mnt_data = isomp;
391 mp->mnt_stat.f_fsid.val[0] = dev2udev(dev);
392 mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
393 MNT_ILOCK(mp);
394 if (isverified)
395 mp->mnt_flag |= MNT_VERIFIED;
396 mp->mnt_flag |= MNT_LOCAL;
397 mp->mnt_kern_flag |= MNTK_LOOKUP_SHARED | MNTK_EXTENDED_SHARED;
398 MNT_IUNLOCK(mp);
399 isomp->im_mountp = mp;
400 isomp->im_dev = dev;
401 isomp->im_devvp = devvp;
402 isomp->im_fmask = isomp->im_dmask = ALLPERMS;
403
404 vfs_flagopt(mp->mnt_optnew, "norrip", &isomp->im_flags, ISOFSMNT_NORRIP);
405 vfs_flagopt(mp->mnt_optnew, "gens", &isomp->im_flags, ISOFSMNT_GENS);
406 vfs_flagopt(mp->mnt_optnew, "extatt", &isomp->im_flags, ISOFSMNT_EXTATT);
407 vfs_flagopt(mp->mnt_optnew, "nojoliet", &isomp->im_flags, ISOFSMNT_NOJOLIET);
408 vfs_flagopt(mp->mnt_optnew, "kiconv", &isomp->im_flags, ISOFSMNT_KICONV);
409
410 if (vfs_scanopt(mp->mnt_optnew, "uid", "%d", &v) == 1) {
411 isomp->im_flags |= ISOFSMNT_UID;
412 isomp->im_uid = v;
413 }
414 if (vfs_scanopt(mp->mnt_optnew, "gid", "%d", &v) == 1) {
415 isomp->im_flags |= ISOFSMNT_GID;
416 isomp->im_gid = v;
417 }
418 if (vfs_scanopt(mp->mnt_optnew, "mask", "%d", &v) == 1) {
419 isomp->im_fmask &= v;
420 }
421 if (vfs_scanopt(mp->mnt_optnew, "dirmask", "%d", &v) == 1) {
422 isomp->im_dmask &= v;
423 }
424
425 /* Check the Rock Ridge Extension support */
426 if (!(isomp->im_flags & ISOFSMNT_NORRIP)) {
427 if ((error = bread(isomp->im_devvp, (isomp->root_extent +
428 isonum_711(((struct iso_directory_record *)isomp->root)->
429 ext_attr_length)) << (isomp->im_bshift - DEV_BSHIFT),
430 isomp->logical_block_size, NOCRED, &bp)) != 0)
431 goto out;
432
433 rootp = (struct iso_directory_record *)bp->b_data;
434
435 if ((isomp->rr_skip = cd9660_rrip_offset(rootp,isomp)) < 0) {
436 isomp->im_flags |= ISOFSMNT_NORRIP;
437 } else {
438 isomp->im_flags &= ~ISOFSMNT_GENS;
439 }
440
441 /*
442 * The contents are valid,
443 * but they will get reread as part of another vnode, so...
444 */
445 bp->b_flags |= B_AGE;
446 brelse(bp);
447 bp = NULL;
448 rootp = NULL;
449 }
450
451 if (isomp->im_flags & ISOFSMNT_KICONV && cd9660_iconv) {
452 cs_local = vfs_getopts(mp->mnt_optnew, "cs_local", &error);
453 if (error)
454 goto out;
455 cs_disk = vfs_getopts(mp->mnt_optnew, "cs_disk", &error);
456 if (error)
457 goto out;
458 cd9660_iconv->open(cs_local, cs_disk, &isomp->im_d2l);
459 cd9660_iconv->open(cs_disk, cs_local, &isomp->im_l2d);
460 } else {
461 isomp->im_d2l = NULL;
462 isomp->im_l2d = NULL;
463 }
464
465 if (high_sierra) {
466 /* this effectively ignores all the mount flags */
467 if (bootverbose)
468 log(LOG_INFO, "cd9660: High Sierra Format\n");
469 isomp->iso_ftype = ISO_FTYPE_HIGH_SIERRA;
470 } else
471 switch (isomp->im_flags&(ISOFSMNT_NORRIP|ISOFSMNT_GENS)) {
472 default:
473 isomp->iso_ftype = ISO_FTYPE_DEFAULT;
474 break;
475 case ISOFSMNT_GENS|ISOFSMNT_NORRIP:
476 isomp->iso_ftype = ISO_FTYPE_9660;
477 break;
478 case 0:
479 if (bootverbose)
480 log(LOG_INFO, "cd9660: RockRidge Extension\n");
481 isomp->iso_ftype = ISO_FTYPE_RRIP;
482 break;
483 }
484
485 /* Decide whether to use the Joliet descriptor */
486
487 if (isomp->iso_ftype != ISO_FTYPE_RRIP && joliet_level) {
488 if (bootverbose)
489 log(LOG_INFO, "cd9660: Joliet Extension (Level %d)\n",
490 joliet_level);
491 rootp = (struct iso_directory_record *)
492 sup->root_directory_record;
493 memcpy(isomp->root, rootp, sizeof isomp->root);
494 isomp->root_extent = isonum_733 (rootp->extent);
495 isomp->root_size = isonum_733 (rootp->size);
496 isomp->joliet_level = joliet_level;
497 supbp->b_flags |= B_AGE;
498 }
499
500 if (supbp) {
501 brelse(supbp);
502 supbp = NULL;
503 sup = NULL;
504 }
505
506 return 0;
507 out:
508 if (bp != NULL)
509 brelse(bp);
510 if (pribp != NULL)
511 brelse(pribp);
512 if (supbp != NULL)
513 brelse(supbp);
514 if (cp != NULL) {
515 g_topology_lock();
516 g_vfs_close(cp);
517 g_topology_unlock();
518 }
519 if (isomp) {
520 free(isomp, M_ISOFSMNT);
521 mp->mnt_data = NULL;
522 }
523 dev_rel(dev);
524 return error;
525 }
526
527 /*
528 * unmount system call
529 */
530 static int
cd9660_unmount(mp,mntflags)531 cd9660_unmount(mp, mntflags)
532 struct mount *mp;
533 int mntflags;
534 {
535 struct iso_mnt *isomp;
536 int error, flags = 0;
537
538 if (mntflags & MNT_FORCE)
539 flags |= FORCECLOSE;
540 if ((error = vflush(mp, 0, flags, curthread)))
541 return (error);
542
543 isomp = VFSTOISOFS(mp);
544
545 if (isomp->im_flags & ISOFSMNT_KICONV && cd9660_iconv) {
546 if (isomp->im_d2l)
547 cd9660_iconv->close(isomp->im_d2l);
548 if (isomp->im_l2d)
549 cd9660_iconv->close(isomp->im_l2d);
550 }
551 g_topology_lock();
552 g_vfs_close(isomp->im_cp);
553 g_topology_unlock();
554 vrele(isomp->im_devvp);
555 dev_rel(isomp->im_dev);
556 free(isomp, M_ISOFSMNT);
557 mp->mnt_data = NULL;
558 return (error);
559 }
560
561 /*
562 * Return root of a filesystem
563 */
564 static int
cd9660_root(mp,flags,vpp)565 cd9660_root(mp, flags, vpp)
566 struct mount *mp;
567 int flags;
568 struct vnode **vpp;
569 {
570 struct iso_mnt *imp = VFSTOISOFS(mp);
571 struct iso_directory_record *dp =
572 (struct iso_directory_record *)imp->root;
573 cd_ino_t ino = isodirino(dp, imp);
574
575 /*
576 * With RRIP we must use the `.' entry of the root directory.
577 * Simply tell vget, that it's a relocated directory.
578 */
579 return (cd9660_vget_internal(mp, ino, flags, vpp,
580 imp->iso_ftype == ISO_FTYPE_RRIP, dp));
581 }
582
583 /*
584 * Get filesystem statistics.
585 */
586 static int
cd9660_statfs(mp,sbp)587 cd9660_statfs(mp, sbp)
588 struct mount *mp;
589 struct statfs *sbp;
590 {
591 struct iso_mnt *isomp;
592
593 isomp = VFSTOISOFS(mp);
594
595 sbp->f_bsize = isomp->logical_block_size;
596 sbp->f_iosize = sbp->f_bsize; /* XXX */
597 sbp->f_blocks = isomp->volume_space_size;
598 sbp->f_bfree = 0; /* total free blocks */
599 sbp->f_bavail = 0; /* blocks free for non superuser */
600 sbp->f_files = 0; /* total files */
601 sbp->f_ffree = 0; /* free file nodes */
602 return 0;
603 }
604
605 /*
606 * File handle to vnode
607 *
608 * Have to be really careful about stale file handles:
609 * - check that the inode number is in range
610 * - call iget() to get the locked inode
611 * - check for an unallocated inode (i_mode == 0)
612 * - check that the generation number matches
613 */
614
615 /* ARGSUSED */
616 static int
cd9660_fhtovp(mp,fhp,flags,vpp)617 cd9660_fhtovp(mp, fhp, flags, vpp)
618 struct mount *mp;
619 struct fid *fhp;
620 int flags;
621 struct vnode **vpp;
622 {
623 struct ifid ifh;
624 struct iso_node *ip;
625 struct vnode *nvp;
626 int error;
627
628 memcpy(&ifh, fhp, sizeof(ifh));
629
630 #ifdef ISOFS_DBG
631 printf("fhtovp: ino %d, start %ld\n",
632 ifh.ifid_ino, ifh.ifid_start);
633 #endif
634
635 if ((error = VFS_VGET(mp, ifh.ifid_ino, LK_EXCLUSIVE, &nvp)) != 0) {
636 *vpp = NULLVP;
637 return (error);
638 }
639 ip = VTOI(nvp);
640 if (ip->inode.iso_mode == 0) {
641 vput(nvp);
642 *vpp = NULLVP;
643 return (ESTALE);
644 }
645 *vpp = nvp;
646 vnode_create_vobject(*vpp, ip->i_size, curthread);
647 return (0);
648 }
649
650 /*
651 * Conform to standard VFS interface; can't vget arbitrary inodes beyond 4GB
652 * into media with current inode scheme and 32-bit ino_t. This shouldn't be
653 * needed for anything other than nfsd, and who exports a mounted DVD over NFS?
654 */
655 static int
cd9660_vget(mp,ino,flags,vpp)656 cd9660_vget(mp, ino, flags, vpp)
657 struct mount *mp;
658 ino_t ino;
659 int flags;
660 struct vnode **vpp;
661 {
662
663 /*
664 * XXXX
665 * It would be nice if we didn't always set the `relocated' flag
666 * and force the extra read, but I don't want to think about fixing
667 * that right now.
668 */
669 return (cd9660_vget_internal(mp, ino, flags, vpp,
670 #if 0
671 VFSTOISOFS(mp)->iso_ftype == ISO_FTYPE_RRIP,
672 #else
673 0,
674 #endif
675 (struct iso_directory_record *)0));
676 }
677
678 /* Use special comparator for full 64-bit ino comparison. */
679 static int
cd9660_vfs_hash_cmp(vp,pino)680 cd9660_vfs_hash_cmp(vp, pino)
681 struct vnode *vp;
682 void *pino;
683 {
684 struct iso_node *ip;
685 cd_ino_t ino;
686
687 ip = VTOI(vp);
688 ino = *(cd_ino_t *)pino;
689 return (ip->i_number != ino);
690 }
691
692 int
cd9660_vget_internal(mp,ino,flags,vpp,relocated,isodir)693 cd9660_vget_internal(mp, ino, flags, vpp, relocated, isodir)
694 struct mount *mp;
695 cd_ino_t ino;
696 int flags;
697 struct vnode **vpp;
698 int relocated;
699 struct iso_directory_record *isodir;
700 {
701 struct iso_mnt *imp;
702 struct iso_node *ip;
703 struct buf *bp;
704 struct vnode *vp;
705 int error;
706 struct thread *td;
707
708 td = curthread;
709 error = vfs_hash_get(mp, ino, flags, td, vpp, cd9660_vfs_hash_cmp,
710 &ino);
711 if (error || *vpp != NULL)
712 return (error);
713
714 /*
715 * We must promote to an exclusive lock for vnode creation. This
716 * can happen if lookup is passed LOCKSHARED.
717 */
718 if ((flags & LK_TYPE_MASK) == LK_SHARED) {
719 flags &= ~LK_TYPE_MASK;
720 flags |= LK_EXCLUSIVE;
721 }
722
723 /*
724 * We do not lock vnode creation as it is believed to be too
725 * expensive for such rare case as simultaneous creation of vnode
726 * for same ino by different processes. We just allow them to race
727 * and check later to decide who wins. Let the race begin!
728 */
729
730 imp = VFSTOISOFS(mp);
731
732 /* Allocate a new vnode/iso_node. */
733 if ((error = getnewvnode("isofs", mp, &cd9660_vnodeops, &vp)) != 0) {
734 *vpp = NULLVP;
735 return (error);
736 }
737 ip = malloc(sizeof(struct iso_node), M_ISOFSNODE,
738 M_WAITOK | M_ZERO);
739 vp->v_data = ip;
740 ip->i_vnode = vp;
741 ip->i_number = ino;
742
743 lockmgr(vp->v_vnlock, LK_EXCLUSIVE, NULL);
744 error = insmntque(vp, mp);
745 if (error != 0) {
746 free(ip, M_ISOFSNODE);
747 *vpp = NULLVP;
748 return (error);
749 }
750 error = vfs_hash_insert(vp, ino, flags, td, vpp, cd9660_vfs_hash_cmp,
751 &ino);
752 if (error || *vpp != NULL)
753 return (error);
754
755 if (isodir == NULL) {
756 int lbn, off;
757
758 lbn = lblkno(imp, ino);
759 if (lbn >= imp->volume_space_size) {
760 vput(vp);
761 printf("fhtovp: lbn exceed volume space %d\n", lbn);
762 return (ESTALE);
763 }
764
765 off = blkoff(imp, ino);
766 if (off + ISO_DIRECTORY_RECORD_SIZE > imp->logical_block_size) {
767 vput(vp);
768 printf("fhtovp: crosses block boundary %d\n",
769 off + ISO_DIRECTORY_RECORD_SIZE);
770 return (ESTALE);
771 }
772
773 error = bread(imp->im_devvp,
774 lbn << (imp->im_bshift - DEV_BSHIFT),
775 imp->logical_block_size, NOCRED, &bp);
776 if (error) {
777 vput(vp);
778 printf("fhtovp: bread error %d\n",error);
779 return (error);
780 }
781 isodir = (struct iso_directory_record *)(bp->b_data + off);
782
783 if (off + isonum_711(isodir->length) >
784 imp->logical_block_size) {
785 vput(vp);
786 brelse(bp);
787 printf("fhtovp: directory crosses block boundary %d[off=%d/len=%d]\n",
788 off +isonum_711(isodir->length), off,
789 isonum_711(isodir->length));
790 return (ESTALE);
791 }
792
793 #if 0
794 if (isonum_733(isodir->extent) +
795 isonum_711(isodir->ext_attr_length) != ifhp->ifid_start) {
796 brelse(bp);
797 printf("fhtovp: file start miss %d vs %d\n",
798 isonum_733(isodir->extent) + isonum_711(isodir->ext_attr_length),
799 ifhp->ifid_start);
800 return (ESTALE);
801 }
802 #endif
803 } else
804 bp = NULL;
805
806 ip->i_mnt = imp;
807
808 if (relocated) {
809 /*
810 * On relocated directories we must
811 * read the `.' entry out of a dir.
812 */
813 ip->iso_start = ino >> imp->im_bshift;
814 if (bp != NULL)
815 brelse(bp);
816 if ((error = cd9660_blkatoff(vp, (off_t)0, NULL, &bp)) != 0) {
817 vput(vp);
818 return (error);
819 }
820 isodir = (struct iso_directory_record *)bp->b_data;
821 }
822
823 ip->iso_extent = isonum_733(isodir->extent);
824 ip->i_size = isonum_733(isodir->size);
825 ip->iso_start = isonum_711(isodir->ext_attr_length) + ip->iso_extent;
826
827 /*
828 * Setup time stamp, attribute
829 */
830 vp->v_type = VNON;
831 switch (imp->iso_ftype) {
832 default: /* ISO_FTYPE_9660 */
833 {
834 struct buf *bp2;
835 int off;
836 if ((imp->im_flags & ISOFSMNT_EXTATT)
837 && (off = isonum_711(isodir->ext_attr_length)))
838 cd9660_blkatoff(vp, (off_t)-(off << imp->im_bshift), NULL,
839 &bp2);
840 else
841 bp2 = NULL;
842 cd9660_defattr(isodir, ip, bp2, ISO_FTYPE_9660);
843 cd9660_deftstamp(isodir, ip, bp2, ISO_FTYPE_9660);
844 if (bp2)
845 brelse(bp2);
846 break;
847 }
848 case ISO_FTYPE_RRIP:
849 cd9660_rrip_analyze(isodir, ip, imp);
850 break;
851 }
852
853 brelse(bp);
854
855 /*
856 * Initialize the associated vnode
857 */
858 switch (vp->v_type = IFTOVT(ip->inode.iso_mode)) {
859 case VFIFO:
860 vp->v_op = &cd9660_fifoops;
861 break;
862 default:
863 VN_LOCK_ASHARE(vp);
864 break;
865 }
866
867 if (ip->iso_extent == imp->root_extent)
868 vp->v_vflag |= VV_ROOT;
869
870 /*
871 * XXX need generation number?
872 */
873
874 *vpp = vp;
875 return (0);
876 }
877