1 /* $OpenBSD: cd9660_vfsops.c,v 1.35 2003/08/14 07:46:39 mickey Exp $ */
2 /* $NetBSD: cd9660_vfsops.c,v 1.26 1997/06/13 15:38:58 pk Exp $ */
3
4 /*-
5 * Copyright (c) 1994
6 * The Regents of the University of California. All rights reserved.
7 *
8 * This code is derived from software contributed to Berkeley
9 * by Pace Willisson (pace@blitz.com). The Rock Ridge Extension
10 * Support code is derived from software contributed to Berkeley
11 * by Atsushi Murai (amurai@spec.co.jp).
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 *
37 * @(#)cd9660_vfsops.c 8.9 (Berkeley) 12/5/94
38 */
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/namei.h>
43 #include <sys/proc.h>
44 #include <sys/kernel.h>
45 #include <sys/vnode.h>
46 #include <miscfs/specfs/specdev.h>
47 #include <sys/mount.h>
48 #include <sys/buf.h>
49 #include <sys/file.h>
50 #include <sys/disklabel.h>
51 #include <sys/ioctl.h>
52 #include <sys/cdio.h>
53 #include <sys/conf.h>
54 #include <sys/errno.h>
55 #include <sys/malloc.h>
56 #include <sys/stat.h>
57
58 #define b_cylin b_resid
59
60 #include <isofs/cd9660/iso.h>
61 #include <isofs/cd9660/cd9660_extern.h>
62 #include <isofs/cd9660/iso_rrip.h>
63 #include <isofs/cd9660/cd9660_node.h>
64
65 const struct vfsops cd9660_vfsops = {
66 cd9660_mount,
67 cd9660_start,
68 cd9660_unmount,
69 cd9660_root,
70 cd9660_quotactl,
71 cd9660_statfs,
72 cd9660_sync,
73 cd9660_vget,
74 cd9660_fhtovp,
75 cd9660_vptofh,
76 cd9660_init,
77 cd9660_sysctl,
78 cd9660_check_export
79 };
80
81 /*
82 * Called by vfs_mountroot when iso is going to be mounted as root.
83 */
84
85 static int iso_mountfs(struct vnode *devvp, struct mount *mp,
86 struct proc *p, struct iso_args *argp);
87 int iso_disklabelspoof(dev_t dev, void (*strat)(struct buf *),
88 struct disklabel *lp);
89
90 int
cd9660_mountroot()91 cd9660_mountroot()
92 {
93 struct mount *mp;
94 extern struct vnode *rootvp;
95 struct proc *p = curproc; /* XXX */
96 int error;
97 struct iso_args args;
98
99 /*
100 * Get vnodes for swapdev and rootdev.
101 */
102 if ((error = bdevvp(swapdev, &swapdev_vp)) ||
103 (error = bdevvp(rootdev, &rootvp))) {
104 printf("cd9660_mountroot: can't setup bdevvp's");
105 return (error);
106 }
107
108 if ((error = vfs_rootmountalloc("cd9660", "root_device", &mp)) != 0)
109 return (error);
110 args.flags = ISOFSMNT_ROOT;
111 if ((error = iso_mountfs(rootvp, mp, p, &args)) != 0) {
112 mp->mnt_vfc->vfc_refcount--;
113 vfs_unbusy(mp, p);
114 free(mp, M_MOUNT);
115 return (error);
116 }
117 simple_lock(&mountlist_slock);
118 CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
119 simple_unlock(&mountlist_slock);
120 (void)cd9660_statfs(mp, &mp->mnt_stat, p);
121 vfs_unbusy(mp, p);
122 inittodr(0);
123 return (0);
124 }
125
126 /*
127 * VFS Operations.
128 *
129 * mount system call
130 */
131 int
cd9660_mount(mp,path,data,ndp,p)132 cd9660_mount(mp, path, data, ndp, p)
133 register struct mount *mp;
134 const char *path;
135 void *data;
136 struct nameidata *ndp;
137 struct proc *p;
138 {
139 struct vnode *devvp;
140 struct iso_args args;
141 size_t size;
142 int error;
143 struct iso_mnt *imp = NULL;
144
145 error = copyin(data, &args, sizeof (struct iso_args));
146 if (error)
147 return (error);
148
149 if ((mp->mnt_flag & MNT_RDONLY) == 0)
150 return (EROFS);
151
152 /*
153 * If updating, check whether changing from read-only to
154 * read/write; if there is no device name, that's all we do.
155 */
156 if (mp->mnt_flag & MNT_UPDATE) {
157 imp = VFSTOISOFS(mp);
158 if (args.fspec == 0)
159 return (vfs_export(mp, &imp->im_export,
160 &args.export_info));
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, UIO_USERSPACE, args.fspec, p);
167 if ((error = namei(ndp)) != 0)
168 return (error);
169 devvp = ndp->ni_vp;
170
171 if (devvp->v_type != VBLK) {
172 vrele(devvp);
173 return (ENOTBLK);
174 }
175 if (major(devvp->v_rdev) >= nblkdev) {
176 vrele(devvp);
177 return (ENXIO);
178 }
179 /*
180 * If mount by non-root, then verify that user has necessary
181 * permissions on the device.
182 */
183 if (p->p_ucred->cr_uid != 0) {
184 vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
185 error = VOP_ACCESS(devvp, VREAD, p->p_ucred, p);
186 if (error) {
187 vput(devvp);
188 return (error);
189 }
190 VOP_UNLOCK(devvp, 0, p);
191 }
192 if ((mp->mnt_flag & MNT_UPDATE) == 0)
193 error = iso_mountfs(devvp, mp, p, &args);
194 else {
195 if (devvp != imp->im_devvp)
196 error = EINVAL; /* needs translation */
197 else
198 vrele(devvp);
199 }
200 if (error) {
201 vrele(devvp);
202 return (error);
203 }
204 imp = VFSTOISOFS(mp);
205 (void)copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
206 bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
207 (void)copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
208 &size);
209 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
210 bcopy(&args, &mp->mnt_stat.mount_info.iso_args, sizeof(args));
211 (void)cd9660_statfs(mp, &mp->mnt_stat, p);
212 return (0);
213 }
214
215 /*
216 * Common code for mount and mountroot
217 */
218 static int
iso_mountfs(devvp,mp,p,argp)219 iso_mountfs(devvp, mp, p, argp)
220 register struct vnode *devvp;
221 struct mount *mp;
222 struct proc *p;
223 struct iso_args *argp;
224 {
225 register struct iso_mnt *isomp = (struct iso_mnt *)0;
226 struct buf *bp = NULL;
227 struct buf *pribp = NULL, *supbp = NULL;
228 dev_t dev = devvp->v_rdev;
229 int error = EINVAL;
230 int needclose = 0;
231 int ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
232 extern struct vnode *rootvp;
233 int iso_bsize;
234 int iso_blknum;
235 int joliet_level;
236 struct iso_volume_descriptor *vdp;
237 struct iso_primary_descriptor *pri = NULL;
238 struct iso_supplementary_descriptor *sup = NULL;
239 struct iso_directory_record *rootp;
240 int logical_block_size;
241 int sess = 0;
242
243 if (!ronly)
244 return (EROFS);
245
246 /*
247 * Disallow multiple mounts of the same device.
248 * Disallow mounting of a device that is currently in use
249 * (except for root, which might share swap device for miniroot).
250 * Flush out any old buffers remaining from a previous use.
251 */
252 if ((error = vfs_mountedon(devvp)) != 0)
253 return (error);
254 if (vcount(devvp) > 1 && devvp != rootvp)
255 return (EBUSY);
256 if ((error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0)) != 0)
257 return (error);
258
259 error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p);
260 if (error)
261 return (error);
262 needclose = 1;
263
264 /* This is the "logical sector size". The standard says this
265 * should be 2048 or the physical sector size on the device,
266 * whichever is greater. For now, we'll just use a constant.
267 */
268 iso_bsize = ISO_DEFAULT_BLOCK_SIZE;
269
270 error = VOP_IOCTL(devvp, CDIOREADMSADDR, (caddr_t)&sess, 0, FSCRED, p);
271 if (error)
272 sess = 0;
273
274 joliet_level = 0;
275 for (iso_blknum = 16; iso_blknum < 100; iso_blknum++) {
276 if ((error = bread(devvp,
277 (iso_blknum + sess) * btodb(iso_bsize),
278 iso_bsize, NOCRED, &bp)) != 0)
279 goto out;
280
281 vdp = (struct iso_volume_descriptor *)bp->b_data;
282 if (bcmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) != 0) {
283 error = EINVAL;
284 goto out;
285 }
286
287 switch (isonum_711 (vdp->type)){
288 case ISO_VD_PRIMARY:
289 if (pribp == NULL) {
290 pribp = bp;
291 bp = NULL;
292 pri = (struct iso_primary_descriptor *)vdp;
293 }
294 break;
295 case ISO_VD_SUPPLEMENTARY:
296 if (supbp == NULL) {
297 supbp = bp;
298 bp = NULL;
299 sup = (struct iso_supplementary_descriptor *)vdp;
300
301 if (!(argp->flags & ISOFSMNT_NOJOLIET)) {
302 if (bcmp(sup->escape, "%/@", 3) == 0)
303 joliet_level = 1;
304 if (bcmp(sup->escape, "%/C", 3) == 0)
305 joliet_level = 2;
306 if (bcmp(sup->escape, "%/E", 3) == 0)
307 joliet_level = 3;
308
309 if (isonum_711 (sup->flags) & 1)
310 joliet_level = 0;
311 }
312 }
313 break;
314
315 case ISO_VD_END:
316 goto vd_end;
317
318 default:
319 break;
320 }
321 if (bp) {
322 brelse(bp);
323 bp = NULL;
324 }
325 }
326 vd_end:
327 if (bp) {
328 brelse(bp);
329 bp = NULL;
330 }
331
332 if (pri == NULL) {
333 error = EINVAL;
334 goto out;
335 }
336
337 logical_block_size = isonum_723 (pri->logical_block_size);
338
339 if (logical_block_size < DEV_BSIZE || logical_block_size > MAXBSIZE
340 || (logical_block_size & (logical_block_size - 1)) != 0) {
341 error = EINVAL;
342 goto out;
343 }
344
345 rootp = (struct iso_directory_record *)pri->root_directory_record;
346
347 isomp = malloc(sizeof *isomp, M_ISOFSMNT, M_WAITOK);
348 bzero((caddr_t)isomp, sizeof *isomp);
349 isomp->logical_block_size = logical_block_size;
350 isomp->volume_space_size = isonum_733 (pri->volume_space_size);
351 bcopy (rootp, isomp->root, sizeof isomp->root);
352 isomp->root_extent = isonum_733 (rootp->extent);
353 isomp->root_size = isonum_733 (rootp->size);
354 isomp->joliet_level = 0;
355
356 isomp->im_bmask = logical_block_size - 1;
357 isomp->im_bshift = ffs(logical_block_size) - 1;
358
359 pribp->b_flags |= B_AGE;
360 brelse(pribp);
361 pribp = NULL;
362
363 mp->mnt_data = (qaddr_t)isomp;
364 mp->mnt_stat.f_fsid.val[0] = (long)dev;
365 mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
366 mp->mnt_maxsymlinklen = 0;
367 mp->mnt_flag |= MNT_LOCAL;
368 isomp->im_mountp = mp;
369 isomp->im_dev = dev;
370 isomp->im_devvp = devvp;
371
372 devvp->v_specmountpoint = mp;
373
374 /* Check the Rock Ridge Extention support */
375 if (!(argp->flags & ISOFSMNT_NORRIP)) {
376 if ((error = bread(isomp->im_devvp, (isomp->root_extent +
377 isonum_711(rootp->ext_attr_length)) <<
378 (isomp->im_bshift - DEV_BSHIFT),
379 isomp->logical_block_size, NOCRED, &bp)) != 0)
380 goto out;
381
382 rootp = (struct iso_directory_record *)bp->b_data;
383
384 if ((isomp->rr_skip = cd9660_rrip_offset(rootp,isomp)) < 0) {
385 argp->flags |= ISOFSMNT_NORRIP;
386 } else {
387 argp->flags &= ~ISOFSMNT_GENS;
388 }
389
390 /*
391 * The contents are valid,
392 * but they will get reread as part of another vnode, so...
393 */
394 bp->b_flags |= B_AGE;
395 brelse(bp);
396 bp = NULL;
397 }
398 isomp->im_flags = argp->flags & (ISOFSMNT_NORRIP | ISOFSMNT_GENS |
399 ISOFSMNT_EXTATT | ISOFSMNT_NOJOLIET);
400 switch (isomp->im_flags & (ISOFSMNT_NORRIP | ISOFSMNT_GENS)) {
401 default:
402 isomp->iso_ftype = ISO_FTYPE_DEFAULT;
403 break;
404 case ISOFSMNT_GENS|ISOFSMNT_NORRIP:
405 isomp->iso_ftype = ISO_FTYPE_9660;
406 break;
407 case 0:
408 isomp->iso_ftype = ISO_FTYPE_RRIP;
409 break;
410 }
411
412 /* Decide whether to use the Joliet descriptor */
413
414 if (isomp->iso_ftype != ISO_FTYPE_RRIP && joliet_level) {
415 rootp = (struct iso_directory_record *)
416 sup->root_directory_record;
417 bcopy(rootp, isomp->root, sizeof isomp->root);
418 isomp->root_extent = isonum_733(rootp->extent);
419 isomp->root_size = isonum_733(rootp->size);
420 isomp->joliet_level = joliet_level;
421 supbp->b_flags |= B_AGE;
422 }
423
424 if (supbp) {
425 brelse(supbp);
426 supbp = NULL;
427 }
428
429 return (0);
430 out:
431 if (bp)
432 brelse(bp);
433 if (supbp)
434 brelse(supbp);
435 if (needclose)
436 (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED,
437 p);
438 if (isomp) {
439 free((caddr_t)isomp, M_ISOFSMNT);
440 mp->mnt_data = (qaddr_t)0;
441 }
442 return (error);
443 }
444
445 /*
446 * Test to see if the device is an ISOFS filesystem.
447 */
448 int
iso_disklabelspoof(dev,strat,lp)449 iso_disklabelspoof(dev, strat, lp)
450 dev_t dev;
451 void (*strat)(struct buf *);
452 register struct disklabel *lp;
453 {
454 struct buf *bp = NULL;
455 struct iso_volume_descriptor *vdp;
456 struct iso_primary_descriptor *pri;
457 int logical_block_size;
458 int error = EINVAL;
459 int iso_blknum;
460 int i;
461
462 bp = geteblk(ISO_DEFAULT_BLOCK_SIZE);
463 bp->b_dev = dev;
464
465 for (iso_blknum = 16; iso_blknum < 100; iso_blknum++) {
466 bp->b_blkno = iso_blknum * btodb(ISO_DEFAULT_BLOCK_SIZE);
467 bp->b_bcount = ISO_DEFAULT_BLOCK_SIZE;
468 bp->b_flags = B_BUSY | B_READ;
469 bp->b_cylin = bp->b_blkno / lp->d_secpercyl;
470
471 /*printf("d_secsize %d iso_blknum %d b_blkno %d bcount %d\n",
472 lp->d_secsize, iso_blknum, bp->b_blkno, bp->b_bcount);*/
473
474 (*strat)(bp);
475
476 if (biowait(bp))
477 goto out;
478
479 vdp = (struct iso_volume_descriptor *)bp->b_data;
480 /*printf("%2x%2x%2x type %2x\n", vdp->id[0], vdp->id[1],
481 vdp->id[2], isonum_711(vdp->type));*/
482 if (bcmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) != 0 ||
483 isonum_711 (vdp->type) == ISO_VD_END)
484 goto out;
485
486 if (isonum_711 (vdp->type) == ISO_VD_PRIMARY)
487 break;
488 }
489
490 if (isonum_711 (vdp->type) != ISO_VD_PRIMARY)
491 goto out;
492
493 pri = (struct iso_primary_descriptor *)vdp;
494 logical_block_size = isonum_723 (pri->logical_block_size);
495 if (logical_block_size < DEV_BSIZE || logical_block_size > MAXBSIZE ||
496 (logical_block_size & (logical_block_size - 1)) != 0)
497 goto out;
498
499 /*
500 * build a disklabel for the CD
501 */
502 strncpy(lp->d_typename, pri->volume_id, sizeof lp->d_typename);
503 strncpy(lp->d_packname, pri->volume_id+16, sizeof lp->d_packname);
504 for (i = 0; i < MAXPARTITIONS; i++) {
505 lp->d_partitions[i].p_size = 0;
506 lp->d_partitions[i].p_offset = 0;
507 }
508 lp->d_partitions[0].p_offset = 0;
509 lp->d_partitions[0].p_size = lp->d_secperunit;
510 lp->d_partitions[0].p_fstype = FS_ISO9660;
511 lp->d_partitions[RAW_PART].p_offset = 0;
512 lp->d_partitions[RAW_PART].p_size = lp->d_secperunit;
513 lp->d_partitions[RAW_PART].p_fstype = FS_ISO9660;
514 lp->d_npartitions = RAW_PART + 1;
515 lp->d_bbsize = 8192; /* fake */
516 lp->d_sbsize = 64*1024; /* fake */
517
518 lp->d_magic = DISKMAGIC;
519 lp->d_magic2 = DISKMAGIC;
520 lp->d_checksum = dkcksum(lp);
521 error = 0;
522 out:
523 bp->b_flags |= B_INVAL;
524 brelse(bp);
525 return (error);
526 }
527
528 /*
529 * Make a filesystem operational.
530 * Nothing to do at the moment.
531 */
532 /* ARGSUSED */
533 int
cd9660_start(mp,flags,p)534 cd9660_start(mp, flags, p)
535 struct mount *mp;
536 int flags;
537 struct proc *p;
538 {
539 return (0);
540 }
541
542 /*
543 * unmount system call
544 */
545 int
cd9660_unmount(mp,mntflags,p)546 cd9660_unmount(mp, mntflags, p)
547 struct mount *mp;
548 int mntflags;
549 struct proc *p;
550 {
551 register struct iso_mnt *isomp;
552 int error, flags = 0;
553
554 if (mntflags & MNT_FORCE)
555 flags |= FORCECLOSE;
556 #if 0
557 mntflushbuf(mp, 0);
558 if (mntinvalbuf(mp))
559 return (EBUSY);
560 #endif
561 if ((error = vflush(mp, NULLVP, flags)) != 0)
562 return (error);
563
564 isomp = VFSTOISOFS(mp);
565
566 #ifdef ISODEVMAP
567 if (isomp->iso_ftype == ISO_FTYPE_RRIP)
568 iso_dunmap(isomp->im_dev);
569 #endif
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 */
583 int
cd9660_root(mp,vpp)584 cd9660_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 */
605 int
cd9660_quotactl(mp,cmd,uid,arg,p)606 cd9660_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 */
620 int
cd9660_statfs(mp,sbp,p)621 cd9660_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 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
639 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname,
640 MNAMELEN);
641 bcopy(&mp->mnt_stat.mount_info.iso_args,
642 &sbp->mount_info.iso_args, sizeof(struct iso_args));
643 }
644 /* Use the first spare for flags: */
645 sbp->f_spare[0] = isomp->im_flags;
646 return (0);
647 }
648
649 /* ARGSUSED */
650 int
cd9660_sync(mp,waitfor,cred,p)651 cd9660_sync(mp, waitfor, cred, p)
652 struct mount *mp;
653 int waitfor;
654 struct ucred *cred;
655 struct proc *p;
656 {
657 return (0);
658 }
659
660 /*
661 * File handle to vnode
662 *
663 * Have to be really careful about stale file handles:
664 * - check that the inode number is in range
665 * - call iget() to get the locked inode
666 * - check for an unallocated inode (i_mode == 0)
667 * - check that the generation number matches
668 */
669
670 struct ifid {
671 ushort ifid_len;
672 ushort ifid_pad;
673 int ifid_ino;
674 long ifid_start;
675 };
676
677 /* ARGSUSED */
678 int
cd9660_fhtovp(mp,fhp,vpp)679 cd9660_fhtovp(mp, fhp, vpp)
680 register struct mount *mp;
681 struct fid *fhp;
682 struct vnode **vpp;
683 {
684 struct ifid *ifhp = (struct ifid *)fhp;
685 register struct iso_node *ip;
686 struct vnode *nvp;
687 int error;
688
689 #ifdef ISOFS_DBG
690 printf("fhtovp: ino %d, start %ld\n", ifhp->ifid_ino,
691 ifhp->ifid_start);
692 #endif
693
694 if ((error = VFS_VGET(mp, ifhp->ifid_ino, &nvp)) != 0) {
695 *vpp = NULLVP;
696 return (error);
697 }
698 ip = VTOI(nvp);
699 if (ip->inode.iso_mode == 0) {
700 vput(nvp);
701 *vpp = NULLVP;
702 return (ESTALE);
703 }
704 *vpp = nvp;
705 return (0);
706 }
707
708 int
cd9660_vget(mp,ino,vpp)709 cd9660_vget(mp, ino, vpp)
710 struct mount *mp;
711 ino_t ino;
712 struct vnode **vpp;
713 {
714
715 /*
716 * XXXX
717 * It would be nice if we didn't always set the `relocated' flag
718 * and force the extra read, but I don't want to think about fixing
719 * that right now.
720 */
721 return (cd9660_vget_internal(mp, ino, vpp,
722 #if 0
723 VFSTOISOFS(mp)->iso_ftype == ISO_FTYPE_RRIP,
724 #else
725 0,
726 #endif
727 NULL));
728 }
729
730 int
cd9660_vget_internal(mp,ino,vpp,relocated,isodir)731 cd9660_vget_internal(mp, ino, vpp, relocated, isodir)
732 struct mount *mp;
733 ino_t ino;
734 struct vnode **vpp;
735 int relocated;
736 struct iso_directory_record *isodir;
737 {
738 register struct iso_mnt *imp;
739 struct iso_node *ip;
740 struct buf *bp;
741 struct vnode *vp, *nvp;
742 dev_t dev;
743 int error;
744
745 retry:
746 imp = VFSTOISOFS(mp);
747 dev = imp->im_dev;
748 if ((*vpp = cd9660_ihashget(dev, ino)) != NULLVP)
749 return (0);
750
751 /* Allocate a new vnode/iso_node. */
752 if ((error = getnewvnode(VT_ISOFS, mp, cd9660_vnodeop_p, &vp)) != 0) {
753 *vpp = NULLVP;
754 return (error);
755 }
756 MALLOC(ip, struct iso_node *, sizeof(struct iso_node), M_ISOFSNODE,
757 M_WAITOK);
758 bzero((caddr_t)ip, sizeof(struct iso_node));
759 lockinit(&ip->i_lock, PINOD, "isoinode", 0, 0);
760 vp->v_data = ip;
761 ip->i_vnode = vp;
762 ip->i_dev = dev;
763 ip->i_number = ino;
764
765 /*
766 * Put it onto its hash chain and lock it so that other requests for
767 * this inode will block if they arrive while we are sleeping waiting
768 * for old data structures to be purged or for the contents of the
769 * disk portion of this inode to be read.
770 */
771 error = cd9660_ihashins(ip);
772
773 if (error) {
774 vrele(vp);
775
776 if (error == EEXIST)
777 goto retry;
778
779 return (error);
780 }
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 {
795 vput(vp);
796 printf("fhtovp: crosses block boundary %d\n",
797 off + ISO_DIRECTORY_RECORD_SIZE);
798 return (ESTALE);
799 }
800
801 error = bread(imp->im_devvp,
802 lbn << (imp->im_bshift - DEV_BSHIFT),
803 imp->logical_block_size, NOCRED, &bp);
804 if (error) {
805 vput(vp);
806 brelse(bp);
807 printf("fhtovp: bread error %d\n",error);
808 return (error);
809 }
810 isodir = (struct iso_directory_record *)(bp->b_data + off);
811
812 if (off + isonum_711(isodir->length) >
813 imp->logical_block_size) {
814 vput(vp);
815 if (bp != 0)
816 brelse(bp);
817 printf("fhtovp: directory crosses block boundary %d[off=%d/len=%d]\n",
818 off +isonum_711(isodir->length), off,
819 isonum_711(isodir->length));
820 return (ESTALE);
821 }
822
823 #if 0
824 if (isonum_733(isodir->extent) +
825 isonum_711(isodir->ext_attr_length) != ifhp->ifid_start) {
826 if (bp != 0)
827 brelse(bp);
828 printf("fhtovp: file start miss %d vs %d\n",
829 isonum_733(isodir->extent) +
830 isonum_711(isodir->ext_attr_length),
831 ifhp->ifid_start);
832 return (ESTALE);
833 }
834 #endif
835 } else
836 bp = 0;
837
838 ip->i_mnt = imp;
839 ip->i_devvp = imp->im_devvp;
840 VREF(ip->i_devvp);
841
842 if (relocated) {
843 /*
844 * On relocated directories we must
845 * read the `.' entry out of a dir.
846 */
847 ip->iso_start = ino >> imp->im_bshift;
848 if (bp != 0)
849 brelse(bp);
850 if ((error = cd9660_bufatoff(ip, (off_t)0, NULL, &bp)) != 0) {
851 vput(vp);
852 return (error);
853 }
854 isodir = (struct iso_directory_record *)bp->b_data;
855 }
856
857 ip->iso_extent = isonum_733(isodir->extent);
858 ip->i_size = isonum_733(isodir->size);
859 ip->iso_start = isonum_711(isodir->ext_attr_length) + ip->iso_extent;
860
861 /*
862 * Setup time stamp, attribute
863 */
864 vp->v_type = VNON;
865 switch (imp->iso_ftype) {
866 default: /* ISO_FTYPE_9660 */
867 {
868 struct buf *bp2;
869 int off;
870 if ((imp->im_flags & ISOFSMNT_EXTATT) &&
871 (off = isonum_711(isodir->ext_attr_length)))
872 cd9660_bufatoff(ip, (off_t)-(off << imp->im_bshift),
873 NULL, &bp2);
874 else
875 bp2 = NULL;
876 cd9660_defattr(isodir, ip, bp2);
877 cd9660_deftstamp(isodir, ip, bp2);
878 if (bp2)
879 brelse(bp2);
880 break;
881 }
882 case ISO_FTYPE_RRIP:
883 cd9660_rrip_analyze(isodir, ip, imp);
884 break;
885 }
886
887 if (bp != 0)
888 brelse(bp);
889
890 /*
891 * Initialize the associated vnode
892 */
893 switch (vp->v_type = IFTOVT(ip->inode.iso_mode)) {
894 case VFIFO:
895 #ifdef FIFO
896 vp->v_op = cd9660_fifoop_p;
897 break;
898 #else
899 vput(vp);
900 return (EOPNOTSUPP);
901 #endif /* FIFO */
902 case VCHR:
903 case VBLK:
904 /*
905 * if device, look at device number table for translation
906 */
907 #ifdef ISODEVMAP
908 if (dp = iso_dmap(dev, ino, 0))
909 ip->inode.iso_rdev = dp->d_dev;
910 #endif
911 vp->v_op = cd9660_specop_p;
912 if ((nvp = checkalias(vp, ip->inode.iso_rdev, mp)) != NULL) {
913 /*
914 * Discard unneeded vnode, but save its iso_node.
915 * Note that the lock is carried over in the iso_node
916 */
917 nvp->v_data = vp->v_data;
918 vp->v_data = NULL;
919 vp->v_op = spec_vnodeop_p;
920 vrele(vp);
921 vgone(vp);
922 /*
923 * Reinitialize aliased inode.
924 */
925 vp = nvp;
926 ip->i_vnode = vp;
927 }
928 break;
929 case VLNK:
930 case VNON:
931 case VSOCK:
932 case VDIR:
933 case VBAD:
934 break;
935 case VREG:
936 uvm_vnp_setsize(vp, ip->i_size);
937 break;
938 }
939
940 if (ip->iso_extent == imp->root_extent)
941 vp->v_flag |= VROOT;
942
943 /*
944 * XXX need generation number?
945 */
946
947 *vpp = vp;
948 return (0);
949 }
950
951 /*
952 * Vnode pointer to File handle
953 */
954 /* ARGSUSED */
955 int
cd9660_vptofh(vp,fhp)956 cd9660_vptofh(vp, fhp)
957 struct vnode *vp;
958 struct fid *fhp;
959 {
960 register struct iso_node *ip = VTOI(vp);
961 register struct ifid *ifhp;
962
963 ifhp = (struct ifid *)fhp;
964 ifhp->ifid_len = sizeof(struct ifid);
965
966 ifhp->ifid_ino = ip->i_number;
967 ifhp->ifid_start = ip->iso_start;
968
969 #ifdef ISOFS_DBG
970 printf("vptofh: ino %d, start %ld\n",
971 ifhp->ifid_ino,ifhp->ifid_start);
972 #endif
973 return (0);
974 }
975
976 /*
977 * Verify a remote client has export rights and return these rights via
978 * exflagsp and credanonp.
979 */
980 int
cd9660_check_export(mp,nam,exflagsp,credanonp)981 cd9660_check_export(mp, nam, exflagsp, credanonp)
982 register struct mount *mp;
983 struct mbuf *nam;
984 int *exflagsp;
985 struct ucred **credanonp;
986 {
987 register struct netcred *np;
988 register struct iso_mnt *imp = VFSTOISOFS(mp);
989
990 /*
991 * Get the export permission structure for this <mp, client> tuple.
992 */
993 np = vfs_export_lookup(mp, &imp->im_export, nam);
994 if (np == NULL)
995 return (EACCES);
996
997 *exflagsp = np->netc_exflags;
998 *credanonp = &np->netc_anon;
999 return (0);
1000 }
1001