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