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