cd9660_vfsops.c revision 1.29 1 /* $NetBSD: cd9660_vfsops.c,v 1.29 2005/11/02 12:38:58 yamt Exp $ */
2
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 (at) blitz.com). The Rock Ridge Extension
9 * Support code is derived from software contributed to Berkeley
10 * by Atsushi Murai (amurai (at) 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 __KERNEL_RCSID(0, "$NetBSD: cd9660_vfsops.c,v 1.29 2005/11/02 12:38:58 yamt Exp $");
41
42 #if defined(_KERNEL_OPT)
43 #include "opt_compat_netbsd.h"
44 #endif
45
46 #include <sys/param.h>
47 #include <sys/sysctl.h>
48 #include <sys/systm.h>
49 #include <sys/namei.h>
50 #include <sys/proc.h>
51 #include <sys/kernel.h>
52 #include <sys/vnode.h>
53 #include <miscfs/specfs/specdev.h>
54 #include <sys/mount.h>
55 #include <sys/buf.h>
56 #include <sys/file.h>
57 #include <sys/disklabel.h>
58 #include <sys/device.h>
59 #include <sys/ioctl.h>
60 #include <sys/cdio.h>
61 #include <sys/errno.h>
62 #include <sys/malloc.h>
63 #include <sys/pool.h>
64 #include <sys/stat.h>
65 #include <sys/conf.h>
66 #include <sys/dirent.h>
67
68 #include <fs/cd9660/iso.h>
69 #include <fs/cd9660/cd9660_extern.h>
70 #include <fs/cd9660/iso_rrip.h>
71 #include <fs/cd9660/cd9660_node.h>
72 #include <fs/cd9660/cd9660_mount.h>
73
74 MALLOC_DEFINE(M_ISOFSMNT, "ISOFS mount", "ISOFS mount structure");
75
76 extern const struct vnodeopv_desc cd9660_vnodeop_opv_desc;
77 extern const struct vnodeopv_desc cd9660_specop_opv_desc;
78 extern const struct vnodeopv_desc cd9660_fifoop_opv_desc;
79
80 const struct vnodeopv_desc * const cd9660_vnodeopv_descs[] = {
81 &cd9660_vnodeop_opv_desc,
82 &cd9660_specop_opv_desc,
83 &cd9660_fifoop_opv_desc,
84 NULL,
85 };
86
87 struct vfsops cd9660_vfsops = {
88 MOUNT_CD9660,
89 cd9660_mount,
90 cd9660_start,
91 cd9660_unmount,
92 cd9660_root,
93 cd9660_quotactl,
94 cd9660_statvfs,
95 cd9660_sync,
96 cd9660_vget,
97 cd9660_fhtovp,
98 cd9660_vptofh,
99 cd9660_init,
100 cd9660_reinit,
101 cd9660_done,
102 cd9660_mountroot,
103 (int (*)(struct mount *, struct vnode *, struct timespec *)) eopnotsupp,
104 vfs_stdextattrctl,
105 cd9660_vnodeopv_descs,
106 };
107 VFS_ATTACH(cd9660_vfsops);
108
109 static const struct genfs_ops cd9660_genfsops = {
110 .gop_size = genfs_size,
111 };
112
113 /*
114 * Called by vfs_mountroot when iso is going to be mounted as root.
115 *
116 * Name is updated by mount(8) after booting.
117 */
118 #define ROOTNAME "root_device"
119
120 static int iso_makemp(struct iso_mnt *isomp, struct buf *bp, int *ea_len);
121 static int iso_mountfs(struct vnode *devvp, struct mount *mp,
122 struct proc *p, struct iso_args *argp);
123
124 int
125 cd9660_mountroot()
126 {
127 struct mount *mp;
128 struct proc *p = curproc; /* XXX */
129 int error;
130 struct iso_args args;
131
132 if (root_device->dv_class != DV_DISK)
133 return (ENODEV);
134
135 if ((error = vfs_rootmountalloc(MOUNT_CD9660, "root_device", &mp))
136 != 0) {
137 vrele(rootvp);
138 return (error);
139 }
140
141 args.flags = ISOFSMNT_ROOT;
142 if ((error = iso_mountfs(rootvp, mp, p, &args)) != 0) {
143 mp->mnt_op->vfs_refcount--;
144 vfs_unbusy(mp);
145 free(mp, M_MOUNT);
146 return (error);
147 }
148 simple_lock(&mountlist_slock);
149 CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
150 simple_unlock(&mountlist_slock);
151 (void)cd9660_statvfs(mp, &mp->mnt_stat, p);
152 vfs_unbusy(mp);
153 return (0);
154 }
155
156 /*
157 * VFS Operations.
158 *
159 * mount system call
160 */
161 int
162 cd9660_mount(mp, path, data, ndp, p)
163 struct mount *mp;
164 const char *path;
165 void *data;
166 struct nameidata *ndp;
167 struct proc *p;
168 {
169 struct vnode *devvp;
170 struct iso_args args;
171 int error;
172 struct iso_mnt *imp = VFSTOISOFS(mp);
173
174 if (mp->mnt_flag & MNT_GETARGS) {
175 if (imp == NULL)
176 return EIO;
177 args.fspec = NULL;
178 args.flags = imp->im_flags;
179 return copyout(&args, data, sizeof(args));
180 }
181 error = copyin(data, &args, sizeof (struct iso_args));
182 if (error)
183 return (error);
184
185 if ((mp->mnt_flag & MNT_RDONLY) == 0)
186 return (EROFS);
187
188 if ((mp->mnt_flag & MNT_UPDATE) && args.fspec == NULL)
189 return EINVAL;
190
191 /*
192 * Not an update, or updating the name: look up the name
193 * and verify that it refers to a sensible block device.
194 */
195 NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
196 if ((error = namei(ndp)) != 0)
197 return (error);
198 devvp = ndp->ni_vp;
199
200 if (devvp->v_type != VBLK) {
201 vrele(devvp);
202 return ENOTBLK;
203 }
204 if (bdevsw_lookup(devvp->v_rdev) == NULL) {
205 vrele(devvp);
206 return ENXIO;
207 }
208 /*
209 * If mount by non-root, then verify that user has necessary
210 * permissions on the device.
211 */
212 if (p->p_ucred->cr_uid != 0) {
213 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
214 error = VOP_ACCESS(devvp, VREAD, p->p_ucred, p);
215 VOP_UNLOCK(devvp, 0);
216 if (error) {
217 vrele(devvp);
218 return (error);
219 }
220 }
221 if ((mp->mnt_flag & MNT_UPDATE) == 0) {
222 /*
223 * Disallow multiple mounts of the same device.
224 * Disallow mounting of a device that is currently in use
225 * (except for root, which might share swap device for
226 * miniroot).
227 */
228 error = vfs_mountedon(devvp);
229 if (error)
230 goto fail;
231 if (vcount(devvp) > 1 && devvp != rootvp) {
232 error = EBUSY;
233 goto fail;
234 }
235 error = VOP_OPEN(devvp, FREAD, FSCRED, p);
236 if (error)
237 goto fail;
238 error = iso_mountfs(devvp, mp, p, &args);
239 if (error) {
240 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY);
241 (void)VOP_CLOSE(devvp, FREAD, NOCRED, p);
242 VOP_UNLOCK(devvp, 0);
243 goto fail;
244 }
245 } else {
246 vrele(devvp);
247 if (devvp != imp->im_devvp)
248 return (EINVAL); /* needs translation */
249 }
250 return set_statvfs_info(path, UIO_USERSPACE, args.fspec, UIO_USERSPACE,
251 mp, p);
252
253 fail:
254 vrele(devvp);
255 return (error);
256 }
257
258 /*
259 * Make a mount point from a volume descriptor
260 */
261 static int
262 iso_makemp(isomp, bp, ea_len)
263 struct iso_mnt *isomp;
264 struct buf *bp;
265 int *ea_len;
266 {
267 struct iso_primary_descriptor *pri;
268 int logical_block_size;
269 struct iso_directory_record *rootp;
270
271 pri = (struct iso_primary_descriptor *)bp->b_data;
272
273 logical_block_size = isonum_723 (pri->logical_block_size);
274
275 if (logical_block_size < DEV_BSIZE || logical_block_size > MAXBSIZE
276 || (logical_block_size & (logical_block_size - 1)) != 0)
277 return -1;
278
279 rootp = (struct iso_directory_record *)pri->root_directory_record;
280
281 isomp->logical_block_size = logical_block_size;
282 isomp->volume_space_size = isonum_733 (pri->volume_space_size);
283 memcpy(isomp->root, rootp, sizeof(isomp->root));
284 isomp->root_extent = isonum_733 (rootp->extent);
285 isomp->root_size = isonum_733 (rootp->size);
286 isomp->im_joliet_level = 0;
287
288 isomp->im_bmask = logical_block_size - 1;
289 isomp->im_bshift = 0;
290 while ((1 << isomp->im_bshift) < isomp->logical_block_size)
291 isomp->im_bshift++;
292
293 if (ea_len != NULL)
294 *ea_len = isonum_711(rootp->ext_attr_length);
295
296 return 0;
297 }
298
299 /*
300 * Common code for mount and mountroot
301 */
302 static int
303 iso_mountfs(devvp, mp, p, argp)
304 struct vnode *devvp;
305 struct mount *mp;
306 struct proc *p;
307 struct iso_args *argp;
308 {
309 struct iso_mnt *isomp = (struct iso_mnt *)0;
310 struct buf *bp = NULL, *pribp = NULL, *supbp = NULL;
311 dev_t dev = devvp->v_rdev;
312 int error = EINVAL;
313 int ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
314 int iso_bsize;
315 int iso_blknum;
316 int joliet_level;
317 struct iso_volume_descriptor *vdp;
318 struct iso_supplementary_descriptor *sup;
319 int sess = 0;
320 int ext_attr_length;
321 struct disklabel label;
322
323 if (!ronly)
324 return EROFS;
325
326 /* Flush out any old buffers remaining from a previous use. */
327 if ((error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0)) != 0)
328 return (error);
329
330 /* This is the "logical sector size". The standard says this
331 * should be 2048 or the physical sector size on the device,
332 * whichever is greater. For now, we'll just use a constant.
333 */
334 iso_bsize = ISO_DEFAULT_BLOCK_SIZE;
335
336 error = VOP_IOCTL(devvp, DIOCGDINFO, &label, FREAD, FSCRED, p);
337 if (!error &&
338 label.d_partitions[DISKPART(dev)].p_fstype == FS_ISO9660) {
339 /* XXX more sanity checks? */
340 sess = label.d_partitions[DISKPART(dev)].p_cdsession;
341 } else {
342 /* fallback to old method */
343 error = VOP_IOCTL(devvp, CDIOREADMSADDR, &sess, 0, FSCRED, p);
344 if (error)
345 sess = 0; /* never mind */
346 }
347 #ifdef ISO_DEBUG
348 printf("isofs: session offset (part %d) %d\n", DISKPART(dev), sess);
349 #endif
350
351 for (iso_blknum = 16; iso_blknum < 100; iso_blknum++) {
352 if ((error = bread(devvp, (iso_blknum+sess) * btodb(iso_bsize),
353 iso_bsize, NOCRED, &bp)) != 0)
354 goto out;
355
356 vdp = (struct iso_volume_descriptor *)bp->b_data;
357 if (memcmp(vdp->id, ISO_STANDARD_ID, sizeof(vdp->id)) != 0) {
358 error = EINVAL;
359 goto out;
360 }
361
362 switch (isonum_711(vdp->type)) {
363 case ISO_VD_PRIMARY:
364 if (pribp == NULL) {
365 pribp = bp;
366 bp = NULL;
367 }
368 break;
369
370 case ISO_VD_SUPPLEMENTARY:
371 if (supbp == NULL) {
372 supbp = bp;
373 bp = NULL;
374 }
375 break;
376
377 default:
378 break;
379 }
380
381 if (isonum_711 (vdp->type) == ISO_VD_END) {
382 brelse(bp);
383 bp = NULL;
384 break;
385 }
386
387 if (bp != NULL) {
388 brelse(bp);
389 bp = NULL;
390 }
391 }
392
393 if (pribp == NULL) {
394 error = EINVAL;
395 goto out;
396 }
397
398 isomp = malloc(sizeof *isomp, M_ISOFSMNT, M_WAITOK);
399 memset(isomp, 0, sizeof *isomp);
400 if (iso_makemp(isomp, pribp, &ext_attr_length) == -1) {
401 error = EINVAL;
402 goto out;
403 }
404
405 isomp->volume_space_size += sess;
406
407 pribp->b_flags |= B_AGE;
408 brelse(pribp);
409 pribp = NULL;
410
411 mp->mnt_data = isomp;
412 mp->mnt_stat.f_fsidx.__fsid_val[0] = (long)dev;
413 mp->mnt_stat.f_fsidx.__fsid_val[1] = makefstype(MOUNT_CD9660);
414 mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0];
415 mp->mnt_stat.f_namemax = MAXNAMLEN;
416 mp->mnt_flag |= MNT_LOCAL;
417 mp->mnt_dev_bshift = iso_bsize;
418 mp->mnt_fs_bshift = isomp->im_bshift;
419 isomp->im_mountp = mp;
420 isomp->im_dev = dev;
421 isomp->im_devvp = devvp;
422
423 devvp->v_specmountpoint = mp;
424
425 /* Check the Rock Ridge Extension support */
426 if (!(argp->flags & ISOFSMNT_NORRIP)) {
427 struct iso_directory_record *rootp;
428
429 if ((error = bread(isomp->im_devvp,
430 (isomp->root_extent + ext_attr_length) <<
431 (isomp->im_bshift - DEV_BSHIFT),
432 isomp->logical_block_size, NOCRED,
433 &bp)) != 0)
434 goto out;
435
436 rootp = (struct iso_directory_record *)bp->b_data;
437
438 if ((isomp->rr_skip = cd9660_rrip_offset(rootp,isomp)) < 0) {
439 argp->flags |= ISOFSMNT_NORRIP;
440 } else {
441 argp->flags &= ~ISOFSMNT_GENS;
442 }
443
444 /*
445 * The contents are valid,
446 * but they will get reread as part of another vnode, so...
447 */
448 bp->b_flags |= B_AGE;
449 brelse(bp);
450 bp = NULL;
451 }
452 isomp->im_flags = argp->flags & (ISOFSMNT_NORRIP | ISOFSMNT_GENS |
453 ISOFSMNT_EXTATT | ISOFSMNT_NOJOLIET | ISOFSMNT_RRCASEINS);
454
455 if (isomp->im_flags & ISOFSMNT_GENS)
456 isomp->iso_ftype = ISO_FTYPE_9660;
457 else if (isomp->im_flags & ISOFSMNT_NORRIP) {
458 isomp->iso_ftype = ISO_FTYPE_DEFAULT;
459 if (argp->flags & ISOFSMNT_NOCASETRANS)
460 isomp->im_flags |= ISOFSMNT_NOCASETRANS;
461 } else
462 isomp->iso_ftype = ISO_FTYPE_RRIP;
463
464 /* Check the Joliet Extension support */
465 if ((argp->flags & ISOFSMNT_NORRIP) != 0 &&
466 (argp->flags & ISOFSMNT_NOJOLIET) == 0 &&
467 supbp != NULL) {
468 joliet_level = 0;
469 sup = (struct iso_supplementary_descriptor *)supbp->b_data;
470
471 if ((isonum_711(sup->flags) & 1) == 0) {
472 if (memcmp(sup->escape, "%/@", 3) == 0)
473 joliet_level = 1;
474 if (memcmp(sup->escape, "%/C", 3) == 0)
475 joliet_level = 2;
476 if (memcmp(sup->escape, "%/E", 3) == 0)
477 joliet_level = 3;
478 }
479 if (joliet_level != 0) {
480 if (iso_makemp(isomp, supbp, NULL) == -1) {
481 error = EINVAL;
482 goto out;
483 }
484 isomp->im_joliet_level = joliet_level;
485 }
486 }
487
488 if (supbp != NULL) {
489 brelse(supbp);
490 supbp = NULL;
491 }
492
493 return 0;
494 out:
495 if (bp)
496 brelse(bp);
497 if (pribp)
498 brelse(pribp);
499 if (supbp)
500 brelse(supbp);
501 if (isomp) {
502 free(isomp, M_ISOFSMNT);
503 mp->mnt_data = NULL;
504 }
505 return error;
506 }
507
508 /*
509 * Make a filesystem operational.
510 * Nothing to do at the moment.
511 */
512 /* ARGSUSED */
513 int
514 cd9660_start(mp, flags, p)
515 struct mount *mp;
516 int flags;
517 struct proc *p;
518 {
519 return 0;
520 }
521
522 /*
523 * unmount system call
524 */
525 int
526 cd9660_unmount(mp, mntflags, p)
527 struct mount *mp;
528 int mntflags;
529 struct proc *p;
530 {
531 struct iso_mnt *isomp;
532 int error, flags = 0;
533
534 if (mntflags & MNT_FORCE)
535 flags |= FORCECLOSE;
536 #if 0
537 mntflushbuf(mp, 0);
538 if (mntinvalbuf(mp))
539 return EBUSY;
540 #endif
541 if ((error = vflush(mp, NULLVP, flags)) != 0)
542 return (error);
543
544 isomp = VFSTOISOFS(mp);
545
546 #ifdef ISODEVMAP
547 if (isomp->iso_ftype == ISO_FTYPE_RRIP)
548 iso_dunmap(isomp->im_dev);
549 #endif
550
551 if (isomp->im_devvp->v_type != VBAD)
552 isomp->im_devvp->v_specmountpoint = NULL;
553
554 vn_lock(isomp->im_devvp, LK_EXCLUSIVE | LK_RETRY);
555 error = VOP_CLOSE(isomp->im_devvp, FREAD, NOCRED, p);
556 vput(isomp->im_devvp);
557 free(isomp, M_ISOFSMNT);
558 mp->mnt_data = NULL;
559 mp->mnt_flag &= ~MNT_LOCAL;
560 return (error);
561 }
562
563 /*
564 * Return root of a filesystem
565 */
566 int
567 cd9660_root(mp, vpp)
568 struct mount *mp;
569 struct vnode **vpp;
570 {
571 struct iso_mnt *imp = VFSTOISOFS(mp);
572 struct iso_directory_record *dp =
573 (struct iso_directory_record *)imp->root;
574 ino_t ino = isodirino(dp, imp);
575
576 /*
577 * With RRIP we must use the `.' entry of the root directory.
578 * Simply tell vget, that it's a relocated directory.
579 */
580 return (cd9660_vget_internal(mp, ino, vpp,
581 imp->iso_ftype == ISO_FTYPE_RRIP, dp));
582 }
583
584 /*
585 * Do operations associated with quotas, not supported
586 */
587 /* ARGSUSED */
588 int
589 cd9660_quotactl(mp, cmd, uid, arg, p)
590 struct mount *mp;
591 int cmd;
592 uid_t uid;
593 void *arg;
594 struct proc *p;
595 {
596
597 return (EOPNOTSUPP);
598 }
599
600 /*
601 * Get file system statistics.
602 */
603 int
604 cd9660_statvfs(mp, sbp, p)
605 struct mount *mp;
606 struct statvfs *sbp;
607 struct proc *p;
608 {
609 struct iso_mnt *isomp;
610
611 isomp = VFSTOISOFS(mp);
612
613 sbp->f_bsize = isomp->logical_block_size;
614 sbp->f_frsize = sbp->f_bsize;
615 sbp->f_iosize = sbp->f_bsize; /* XXX */
616 sbp->f_blocks = isomp->volume_space_size;
617 sbp->f_bfree = 0; /* total free blocks */
618 sbp->f_bavail = 0; /* blocks free for non superuser */
619 sbp->f_bresvd = 0; /* total reserved blocks */
620 sbp->f_files = 0; /* total files */
621 sbp->f_ffree = 0; /* free file nodes */
622 sbp->f_favail = 0; /* free file nodes for non superuser */
623 sbp->f_fresvd = 0; /* reserved file nodes */
624 copy_statvfs_info(sbp, mp);
625 /* Use the first spare for flags: */
626 sbp->f_spare[0] = isomp->im_flags;
627 return 0;
628 }
629
630 /* ARGSUSED */
631 int
632 cd9660_sync(mp, waitfor, cred, p)
633 struct mount *mp;
634 int waitfor;
635 struct ucred *cred;
636 struct proc *p;
637 {
638 return (0);
639 }
640
641 /*
642 * File handle to vnode
643 *
644 * Have to be really careful about stale file handles:
645 * - check that the inode number is in range
646 * - call iget() to get the locked inode
647 * - check for an unallocated inode (i_mode == 0)
648 * - check that the generation number matches
649 */
650
651 struct ifid {
652 ushort ifid_len;
653 ushort ifid_pad;
654 int ifid_ino;
655 long ifid_start;
656 };
657
658 /* ARGSUSED */
659 int
660 cd9660_fhtovp(mp, fhp, vpp)
661 struct mount *mp;
662 struct fid *fhp;
663 struct vnode **vpp;
664 {
665 struct ifid *ifhp = (struct ifid *)fhp;
666 struct iso_node *ip;
667 struct vnode *nvp;
668 int error;
669
670 #ifdef ISOFS_DBG
671 printf("fhtovp: ino %d, start %ld\n",
672 ifhp->ifid_ino, ifhp->ifid_start);
673 #endif
674
675 if ((error = VFS_VGET(mp, ifhp->ifid_ino, &nvp)) != 0) {
676 *vpp = NULLVP;
677 return (error);
678 }
679 ip = VTOI(nvp);
680 if (ip->inode.iso_mode == 0) {
681 vput(nvp);
682 *vpp = NULLVP;
683 return (ESTALE);
684 }
685 *vpp = nvp;
686 return (0);
687 }
688
689 int
690 cd9660_vget(mp, ino, vpp)
691 struct mount *mp;
692 ino_t ino;
693 struct vnode **vpp;
694 {
695
696 /*
697 * XXXX
698 * It would be nice if we didn't always set the `relocated' flag
699 * and force the extra read, but I don't want to think about fixing
700 * that right now.
701 */
702 return (cd9660_vget_internal(mp, ino, vpp,
703 #if 0
704 VFSTOISOFS(mp)->iso_ftype == ISO_FTYPE_RRIP,
705 #else
706 0,
707 #endif
708 NULL));
709 }
710
711 int
712 cd9660_vget_internal(mp, ino, vpp, relocated, isodir)
713 struct mount *mp;
714 ino_t ino;
715 struct vnode **vpp;
716 int relocated;
717 struct iso_directory_record *isodir;
718 {
719 struct iso_mnt *imp;
720 struct iso_node *ip;
721 #ifdef ISODEVMAP
722 struct iso_dnode *dp;
723 #endif
724 struct buf *bp;
725 struct vnode *vp, *nvp;
726 dev_t dev;
727 int error;
728
729 imp = VFSTOISOFS(mp);
730 dev = imp->im_dev;
731 if ((*vpp = cd9660_ihashget(dev, ino)) != NULLVP)
732 return (0);
733
734 /* Allocate a new vnode/iso_node. */
735 if ((error = getnewvnode(VT_ISOFS, mp, cd9660_vnodeop_p, &vp)) != 0) {
736 *vpp = NULLVP;
737 return (error);
738 }
739 ip = pool_get(&cd9660_node_pool, PR_WAITOK);
740 memset(ip, 0, sizeof(struct iso_node));
741 vp->v_data = ip;
742 ip->i_vnode = vp;
743 ip->i_dev = dev;
744 ip->i_number = ino;
745
746 /*
747 * Put it onto its hash chain and lock it so that other requests for
748 * this inode will block if they arrive while we are sleeping waiting
749 * for old data structures to be purged or for the contents of the
750 * disk portion of this inode to be read.
751 */
752 cd9660_ihashins(ip);
753
754 if (isodir == 0) {
755 int lbn, off;
756
757 lbn = lblkno(imp, ino);
758 if (lbn >= imp->volume_space_size) {
759 vput(vp);
760 printf("fhtovp: lbn exceed volume space %d\n", lbn);
761 return (ESTALE);
762 }
763
764 off = blkoff(imp, ino);
765 if (off + ISO_DIRECTORY_RECORD_SIZE > imp->logical_block_size) {
766 vput(vp);
767 printf("fhtovp: crosses block boundary %d\n",
768 off + ISO_DIRECTORY_RECORD_SIZE);
769 return (ESTALE);
770 }
771
772 error = bread(imp->im_devvp,
773 lbn << (imp->im_bshift - DEV_BSHIFT),
774 imp->logical_block_size, NOCRED, &bp);
775 if (error) {
776 vput(vp);
777 brelse(bp);
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 if (bp != 0)
787 brelse(bp);
788 printf("fhtovp: directory crosses block boundary %d[off=%d/len=%d]\n",
789 off +isonum_711(isodir->length), off,
790 isonum_711(isodir->length));
791 return (ESTALE);
792 }
793
794 #if 0
795 if (isonum_733(isodir->extent) +
796 isonum_711(isodir->ext_attr_length) != ifhp->ifid_start) {
797 if (bp != 0)
798 brelse(bp);
799 printf("fhtovp: file start miss %d vs %d\n",
800 isonum_733(isodir->extent) + isonum_711(isodir->ext_attr_length),
801 ifhp->ifid_start);
802 return (ESTALE);
803 }
804 #endif
805 } else
806 bp = 0;
807
808 ip->i_mnt = imp;
809 ip->i_devvp = imp->im_devvp;
810 VREF(ip->i_devvp);
811
812 if (relocated) {
813 /*
814 * On relocated directories we must
815 * read the `.' entry out of a dir.
816 */
817 ip->iso_start = ino >> imp->im_bshift;
818 if (bp != 0)
819 brelse(bp);
820 if ((error = cd9660_blkatoff(vp, (off_t)0, NULL, &bp)) != 0) {
821 vput(vp);
822 return (error);
823 }
824 isodir = (struct iso_directory_record *)bp->b_data;
825 }
826
827 ip->iso_extent = isonum_733(isodir->extent);
828 ip->i_size = isonum_733(isodir->size);
829 ip->iso_start = isonum_711(isodir->ext_attr_length) + ip->iso_extent;
830
831 /*
832 * Setup time stamp, attribute
833 */
834 vp->v_type = VNON;
835 switch (imp->iso_ftype) {
836 default: /* ISO_FTYPE_9660 */
837 {
838 struct buf *bp2;
839 int off;
840 if ((imp->im_flags & ISOFSMNT_EXTATT)
841 && (off = isonum_711(isodir->ext_attr_length)))
842 cd9660_blkatoff(vp, (off_t)-(off << imp->im_bshift),
843 NULL, &bp2);
844 else
845 bp2 = NULL;
846 cd9660_defattr(isodir, ip, bp2);
847 cd9660_deftstamp(isodir, ip, bp2);
848 if (bp2)
849 brelse(bp2);
850 break;
851 }
852 case ISO_FTYPE_RRIP:
853 cd9660_rrip_analyze(isodir, ip, imp);
854 break;
855 }
856
857 if (bp != 0)
858 brelse(bp);
859
860 /*
861 * Initialize the associated vnode
862 */
863 switch (vp->v_type = IFTOVT(ip->inode.iso_mode)) {
864 case VFIFO:
865 vp->v_op = cd9660_fifoop_p;
866 break;
867 case VCHR:
868 case VBLK:
869 /*
870 * if device, look at device number table for translation
871 */
872 #ifdef ISODEVMAP
873 if ((dp = iso_dmap(dev, ino, 0)) != NULL)
874 ip->inode.iso_rdev = dp->d_dev;
875 #endif
876 vp->v_op = cd9660_specop_p;
877 if ((nvp = checkalias(vp, ip->inode.iso_rdev, mp)) != NULL) {
878 /*
879 * Discard unneeded vnode, but save its iso_node.
880 * Note that the lock is carried over in the iso_node
881 * to the replacement vnode.
882 */
883 nvp->v_data = vp->v_data;
884 vp->v_data = NULL;
885 VOP_UNLOCK(vp, 0);
886 vp->v_op = spec_vnodeop_p;
887 vrele(vp);
888 vgone(vp);
889 lockmgr(&nvp->v_lock, LK_EXCLUSIVE, &nvp->v_interlock);
890 /*
891 * Reinitialize aliased inode.
892 */
893 vp = nvp;
894 ip->i_vnode = vp;
895 }
896 break;
897 case VLNK:
898 case VNON:
899 case VSOCK:
900 case VDIR:
901 case VBAD:
902 break;
903 case VREG:
904 uvm_vnp_setsize(vp, ip->i_size);
905 break;
906 }
907
908 if (ip->iso_extent == imp->root_extent)
909 vp->v_flag |= VROOT;
910
911 /*
912 * XXX need generation number?
913 */
914
915 genfs_node_init(vp, &cd9660_genfsops);
916 *vpp = vp;
917 return (0);
918 }
919
920 /*
921 * Vnode pointer to File handle
922 */
923 /* ARGSUSED */
924 int
925 cd9660_vptofh(vp, fhp)
926 struct vnode *vp;
927 struct fid *fhp;
928 {
929 struct iso_node *ip = VTOI(vp);
930 struct ifid *ifhp;
931
932 ifhp = (struct ifid *)fhp;
933 ifhp->ifid_len = sizeof(struct ifid);
934
935 ifhp->ifid_ino = ip->i_number;
936 ifhp->ifid_start = ip->iso_start;
937
938 #ifdef ISOFS_DBG
939 printf("vptofh: ino %d, start %ld\n",
940 ifhp->ifid_ino,ifhp->ifid_start);
941 #endif
942 return 0;
943 }
944
945 SYSCTL_SETUP(sysctl_vfs_cd9660_setup, "sysctl vfs.cd9660 subtree setup")
946 {
947
948 sysctl_createv(clog, 0, NULL, NULL,
949 CTLFLAG_PERMANENT, CTLTYPE_NODE, "vfs", NULL,
950 NULL, 0, NULL, 0,
951 CTL_VFS, CTL_EOL);
952 sysctl_createv(clog, 0, NULL, NULL,
953 CTLFLAG_PERMANENT, CTLTYPE_NODE, "cd9660",
954 SYSCTL_DESCR("ISO-9660 file system"),
955 NULL, 0, NULL, 0,
956 CTL_VFS, 14, CTL_EOL);
957
958 sysctl_createv(clog, 0, NULL, NULL,
959 CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
960 CTLTYPE_INT, "utf8_joliet",
961 SYSCTL_DESCR("Encode Joliet file names to UTF-8"),
962 NULL, 0, &cd9660_utf8_joliet, 0,
963 CTL_VFS, 14, CD9660_UTF8_JOLIET, CTL_EOL);
964
965 }
966