]> git.saurik.com Git - apple/xnu.git/blob - bsd/isofs/cd9660/cd9660_vfsops.c
xnu-201.19.tar.gz
[apple/xnu.git] / bsd / isofs / cd9660 / cd9660_vfsops.c
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22 /* $NetBSD: cd9660_vfsops.c,v 1.18 1995/03/09 12:05:36 mycroft Exp $ */
23
24 /*-
25 * Copyright (c) 1994
26 * The Regents of the University of California. All rights reserved.
27 *
28 * This code is derived from software contributed to Berkeley
29 * by Pace Willisson (pace@blitz.com). The Rock Ridge Extension
30 * Support code is derived from software contributed to Berkeley
31 * by Atsushi Murai (amurai@spec.co.jp).
32 *
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
35 * are met:
36 * 1. Redistributions of source code must retain the above copyright
37 * notice, this list of conditions and the following disclaimer.
38 * 2. Redistributions in binary form must reproduce the above copyright
39 * notice, this list of conditions and the following disclaimer in the
40 * documentation and/or other materials provided with the distribution.
41 * 3. All advertising materials mentioning features or use of this software
42 * must display the following acknowledgement:
43 * This product includes software developed by the University of
44 * California, Berkeley and its contributors.
45 * 4. Neither the name of the University nor the names of its contributors
46 * may be used to endorse or promote products derived from this software
47 * without specific prior written permission.
48 *
49 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
50 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
52 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
53 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
54 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
55 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
56 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
57 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
58 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
59 * SUCH DAMAGE.
60 *
61 * @(#)cd9660_vfsops.c 8.9 (Berkeley) 12/5/94
62 */
63
64 #include <sys/param.h>
65 #include <sys/systm.h>
66 #include <sys/vnode.h>
67 #include <sys/mount.h>
68 #include <sys/namei.h>
69 #include <sys/proc.h>
70 #include <sys/kernel.h>
71 #include <miscfs/specfs/specdev.h>
72 #include <sys/buf.h>
73 #include <sys/file.h>
74 #include <sys/ioctl.h>
75 #include <dev/disk.h>
76 #include <sys/errno.h>
77 #include <sys/malloc.h>
78 #include <sys/stat.h>
79 #include <sys/ubc.h>
80 #include <sys/utfconv.h>
81 #include <architecture/byte_order.h>
82
83 #include <isofs/cd9660/iso.h>
84 #include <isofs/cd9660/iso_rrip.h>
85 #include <isofs/cd9660/cd9660_node.h>
86 #include <isofs/cd9660/cd9660_mount.h>
87
88 u_char isonullname[] = "\0";
89
90 extern int enodev ();
91
92 struct vfsops cd9660_vfsops = {
93 cd9660_mount,
94 cd9660_start,
95 cd9660_unmount,
96 cd9660_root,
97 cd9660_quotactl,
98 cd9660_statfs,
99 cd9660_sync,
100 cd9660_vget,
101 cd9660_fhtovp,
102 cd9660_vptofh,
103 cd9660_init,
104 cd9660_sysctl
105 };
106
107 /*
108 * Called by vfs_mountroot when iso is going to be mounted as root.
109 *
110 * Name is updated by mount(8) after booting.
111 */
112 #define ROOTNAME "root_device"
113
114 static int iso_mountfs __P((struct vnode *devvp, struct mount *mp,
115 struct proc *p, struct iso_args *argp));
116
117 static void DRGetTypeCreatorAndFlags(
118 struct iso_mnt * theMountPointPtr,
119 struct iso_directory_record * theDirRecPtr,
120 u_int32_t * theTypePtr,
121 u_int32_t * theCreatorPtr,
122 u_int16_t * theFlagsPtr);
123
124 int cd9660_vget_internal(
125 struct mount *mp,
126 ino_t ino,
127 struct vnode **vpp,
128 int relocated,
129 struct iso_directory_record *isodir,
130 struct proc *p);
131
132 int
133 cd9660_mountroot()
134 {
135 register struct mount *mp;
136 extern struct vnode *rootvp;
137 struct proc *p = current_proc(); /* XXX */
138 struct iso_mnt *imp;
139 size_t size;
140 int error;
141 struct iso_args args;
142
143 /*
144 * Get vnodes for swapdev and rootdev.
145 */
146 if ( bdevvp(rootdev, &rootvp))
147 panic("cd9660_mountroot: can't setup bdevvp's");
148
149 MALLOC_ZONE(mp, struct mount *,
150 sizeof(struct mount), M_MOUNT, M_WAITOK);
151 bzero((char *)mp, (u_long)sizeof(struct mount));
152
153 /* Initialize the default IO constraints */
154 mp->mnt_maxreadcnt = mp->mnt_maxwritecnt = MAXPHYS;
155 mp->mnt_segreadcnt = mp->mnt_segwritecnt = 32;
156
157 mp->mnt_op = &cd9660_vfsops;
158 mp->mnt_flag = MNT_RDONLY;
159 LIST_INIT(&mp->mnt_vnodelist);
160 args.flags = ISOFSMNT_ROOT;
161 args.ssector = 0;
162 if ((error = iso_mountfs(rootvp, mp, p, &args))) {
163 FREE_ZONE(mp, sizeof (struct mount), M_MOUNT);
164 return (error);
165 }
166 simple_lock(&mountlist_slock);
167 CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
168 simple_unlock(&mountlist_slock);
169 mp->mnt_vnodecovered = NULLVP;
170 imp = VFSTOISOFS(mp);
171 (void) copystr("/", mp->mnt_stat.f_mntonname, MNAMELEN - 1,
172 &size);
173 bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
174 (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
175 &size);
176 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
177 (void)cd9660_statfs(mp, &mp->mnt_stat, p);
178 return (0);
179 }
180
181 /*
182 * VFS Operations.
183 *
184 * mount system call
185 */
186 int
187 cd9660_mount(mp, path, data, ndp, p)
188 register struct mount *mp;
189 char *path;
190 caddr_t data;
191 struct nameidata *ndp;
192 struct proc *p;
193 {
194 struct vnode *devvp;
195 struct iso_args args;
196 size_t size;
197 int error;
198 struct iso_mnt *imp = NULL;
199
200 if ((error = copyin(data, (caddr_t)&args, sizeof (struct iso_args))))
201 return (error);
202
203 if ((mp->mnt_flag & MNT_RDONLY) == 0)
204 return (EROFS);
205
206 /*
207 * If updating, check whether changing from read-only to
208 * read/write; if there is no device name, that's all we do.
209 */
210 if (mp->mnt_flag & MNT_UPDATE) {
211 imp = VFSTOISOFS(mp);
212 if (args.fspec == 0)
213 return (vfs_export(mp, &imp->im_export, &args.export));
214 }
215 /*
216 * Not an update, or updating the name: look up the name
217 * and verify that it refers to a sensible block device.
218 */
219 NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
220 if ((error = namei(ndp)))
221 return (error);
222 devvp = ndp->ni_vp;
223
224 if (devvp->v_type != VBLK) {
225 vrele(devvp);
226 return (ENOTBLK);
227 }
228 if (major(devvp->v_rdev) >= nblkdev) {
229 vrele(devvp);
230 return (ENXIO);
231 }
232 if ((mp->mnt_flag & MNT_UPDATE) == 0)
233 error = iso_mountfs(devvp, mp, p, &args);
234 else {
235 if (devvp != imp->im_devvp)
236 error = EINVAL; /* needs translation */
237 else
238 vrele(devvp);
239 }
240 if (error) {
241 vrele(devvp);
242 return (error);
243 }
244
245 /* Set the mount flag to indicate that we support volfs */
246 mp->mnt_flag |= MNT_DOVOLFS;
247
248 (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
249 bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
250 (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
251 &size);
252 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
253 return (0);
254 }
255
256 /*
257 * Common code for mount and mountroot
258 */
259 static int
260 iso_mountfs(devvp, mp, p, argp)
261 register struct vnode *devvp;
262 struct mount *mp;
263 struct proc *p;
264 struct iso_args *argp;
265 {
266 register struct iso_mnt *isomp = (struct iso_mnt *)0;
267 struct buf *bp = NULL;
268 struct buf *pribp = NULL, *supbp = NULL;
269 dev_t dev = devvp->v_rdev;
270 int error = EINVAL;
271 int breaderr = 0;
272 int needclose = 0;
273 extern struct vnode *rootvp;
274 u_long iso_bsize;
275 int iso_blknum;
276 int joliet_level;
277 struct iso_volume_descriptor *vdp = NULL;
278 struct iso_primary_descriptor *pri = NULL;
279 struct iso_primary_descriptor *sup = NULL;
280 struct iso_directory_record *rootp;
281 int logical_block_size;
282 u_int8_t vdtype;
283 int blkoff = argp->ssector;
284
285 if (!(mp->mnt_flag & MNT_RDONLY))
286 return (EROFS);
287
288 /*
289 * Disallow multiple mounts of the same device.
290 * Disallow mounting of a device that is currently in use
291 * (except for root, which might share swap device for miniroot).
292 * Flush out any old buffers remaining from a previous use.
293 */
294 if ((error = vfs_mountedon(devvp)))
295 return (error);
296 if (vcount(devvp) > 1 && devvp != rootvp)
297 return (EBUSY);
298 if ((error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0)))
299 return (error);
300
301 if ((error = VOP_OPEN(devvp, FREAD, FSCRED, p)))
302 return (error);
303 needclose = 1;
304
305 /* This is the "logical sector size". The standard says this
306 * should be 2048 or the physical sector size on the device,
307 * whichever is greater. For now, we'll just use a constant.
308 */
309 iso_bsize = ISO_DEFAULT_BLOCK_SIZE;
310
311 /* tell IOKit that we're assuming 2K sectors */
312 if ((error = VOP_IOCTL(devvp, DKIOCSETBLOCKSIZE,
313 (caddr_t)&iso_bsize, FWRITE, p->p_ucred, p)))
314 return (error);
315 devvp->v_specsize = iso_bsize;
316 joliet_level = 0;
317 for (iso_blknum = 16 + blkoff; iso_blknum < (100 + blkoff); iso_blknum++) {
318 if ((error = bread(devvp, iso_blknum, iso_bsize, NOCRED, &bp))) {
319 if (bp) {
320 bp->b_flags |= B_AGE;
321 brelse(bp);
322 bp = NULL;
323 }
324 breaderr = error;
325 printf("iso_mountfs: bread error %d reading block %d\n", error, iso_blknum);
326 continue;
327 }
328
329 vdp = (struct iso_volume_descriptor *)bp->b_data;
330 if (bcmp (vdp->volume_desc_id, ISO_STANDARD_ID, sizeof(vdp->volume_desc_id)) != 0) {
331 #ifdef DEBUG
332 printf("cd9660_vfsops.c: iso_mountfs: "
333 "Invalid ID in volume desciptor.\n");
334 #endif
335 error = EINVAL;
336 goto out;
337 }
338
339 vdtype = isonum_711 (vdp->type);
340 if (vdtype == ISO_VD_END)
341 break;
342
343 if (vdtype == ISO_VD_PRIMARY) {
344 if (pribp == NULL) {
345 pribp = bp;
346 bp = NULL;
347 pri = (struct iso_primary_descriptor *)vdp;
348 }
349 } else if(vdtype == ISO_VD_SUPPLEMENTARY) {
350 if (supbp == NULL) {
351 supbp = bp;
352 bp = NULL;
353 sup = (struct iso_primary_descriptor *)vdp;
354
355 if ((argp->flags & ISOFSMNT_NOJOLIET) == 0) {
356 /*
357 * some Joliet CDs are "out-of-spec and don't correctly
358 * set the SVD flags. We ignore the flags and rely soely
359 * on the escape_seq
360 */
361 if (bcmp(sup->escape_seq, ISO_UCS2_Level_1, 3) == 0)
362 joliet_level = 1;
363 else if (bcmp(sup->escape_seq, ISO_UCS2_Level_2, 3) == 0)
364 joliet_level = 2;
365 else if (bcmp(sup->escape_seq, ISO_UCS2_Level_3, 3) == 0)
366 joliet_level = 3;
367 }
368 }
369 }
370
371 if (bp) {
372 bp->b_flags |= B_AGE;
373 brelse(bp);
374 bp = NULL;
375 }
376 }
377
378 if (bp) {
379 bp->b_flags |= B_AGE;
380 brelse(bp);
381 bp = NULL;
382 }
383
384 if (pri == NULL) {
385 if (breaderr)
386 error = breaderr;
387 else
388 error = EINVAL;
389 goto out;
390 }
391
392 logical_block_size = isonum_723 (pri->logical_block_size);
393
394 if (logical_block_size < DEV_BSIZE || logical_block_size > MAXBSIZE
395 || (logical_block_size & (logical_block_size - 1)) != 0) {
396 error = EINVAL;
397 goto out;
398 }
399
400 rootp = (struct iso_directory_record *)pri->root_directory_record;
401
402 MALLOC(isomp, struct iso_mnt *, sizeof *isomp, M_ISOFSMNT, M_WAITOK);
403 bzero((caddr_t)isomp, sizeof *isomp);
404 isomp->logical_block_size = logical_block_size;
405 isomp->volume_space_size = isonum_733 (pri->volume_space_size);
406 /*
407 * Since an ISO9660 multi-session CD can also access previous
408 * sessions, we have to include them into the space consider-
409 * ations. This doesn't yield a very accurate number since
410 * parts of the old sessions might be inaccessible now, but we
411 * can't do much better. This is also important for the NFS
412 * filehandle validation.
413 */
414 isomp->volume_space_size += blkoff;
415 bcopy (rootp, isomp->root, sizeof isomp->root);
416 isomp->root_extent = isonum_733 (rootp->extent);
417 isomp->root_size = isonum_733 (rootp->size);
418
419 /*
420 * getattrlist wants the volume name, create date and modify date
421 */
422
423 /* Remove any trailing white space */
424 if ( strlen(pri->volume_id) ) {
425 char *myPtr;
426
427 myPtr = pri->volume_id + strlen( pri->volume_id ) - 1;
428 while ( *myPtr == ' ' && myPtr >= pri->volume_id ) {
429 *myPtr = 0x00;
430 myPtr--;
431 }
432 }
433
434 if (pri->volume_id[0] == 0)
435 strcpy(isomp->volume_id, ISO_DFLT_VOLUME_ID);
436 else
437 bcopy(pri->volume_id, isomp->volume_id, sizeof(isomp->volume_id));
438 cd9660_tstamp_conv17(pri->creation_date, &isomp->creation_date);
439 cd9660_tstamp_conv17(pri->modification_date, &isomp->modification_date);
440
441 /* See if this is a CD-XA volume */
442 if (bcmp( pri->CDXASignature, ISO_XA_ID,
443 sizeof(pri->CDXASignature) ) == 0 )
444 isomp->im_flags2 |= IMF2_IS_CDXA;
445
446 isomp->im_bmask = logical_block_size - 1;
447 isomp->im_bshift = 0;
448 while ((1 << isomp->im_bshift) < isomp->logical_block_size)
449 isomp->im_bshift++;
450
451 pribp->b_flags |= B_AGE;
452 brelse(pribp);
453 pribp = NULL;
454
455 mp->mnt_data = (qaddr_t)isomp;
456 mp->mnt_stat.f_fsid.val[0] = (long)dev;
457 mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
458 mp->mnt_maxsymlinklen = 0;
459 mp->mnt_flag |= MNT_LOCAL;
460
461 isomp->im_mountp = mp;
462 isomp->im_dev = dev;
463 isomp->im_devvp = devvp;
464
465 devvp->v_specflags |= SI_MOUNTEDON;
466
467 /* Check the Rock Ridge Extention support */
468 if (!(argp->flags & ISOFSMNT_NORRIP)) {
469 if ( (error = bread(isomp->im_devvp,
470 (isomp->root_extent + isonum_711(rootp->ext_attr_length)),
471 isomp->logical_block_size, NOCRED, &bp)) ) {
472
473 printf("iso_mountfs: bread error %d reading block %d\n",
474 error, isomp->root_extent + isonum_711(rootp->ext_attr_length));
475 argp->flags |= ISOFSMNT_NORRIP;
476 goto skipRRIP;
477 }
478 rootp = (struct iso_directory_record *)bp->b_data;
479
480 if ((isomp->rr_skip = cd9660_rrip_offset(rootp,isomp)) < 0) {
481 argp->flags |= ISOFSMNT_NORRIP;
482 } else {
483 argp->flags &= ~ISOFSMNT_GENS;
484 }
485
486 /*
487 * The contents are valid,
488 * but they will get reread as part of another vnode, so...
489 */
490 bp->b_flags |= B_AGE;
491 brelse(bp);
492 bp = NULL;
493 }
494 skipRRIP:
495
496 isomp->im_flags = argp->flags & (ISOFSMNT_NORRIP | ISOFSMNT_GENS |
497 ISOFSMNT_EXTATT | ISOFSMNT_NOJOLIET);
498
499 switch (isomp->im_flags&(ISOFSMNT_NORRIP|ISOFSMNT_GENS)) {
500 default:
501 isomp->iso_ftype = ISO_FTYPE_DEFAULT;
502 break;
503 case ISOFSMNT_GENS|ISOFSMNT_NORRIP:
504 isomp->iso_ftype = ISO_FTYPE_9660;
505 break;
506 case 0:
507 isomp->iso_ftype = ISO_FTYPE_RRIP;
508 break;
509 }
510
511 /* Decide whether to use the Joliet descriptor */
512
513 if (isomp->iso_ftype != ISO_FTYPE_RRIP && joliet_level != 0) {
514 char vol_id[32];
515 int i, convflags;
516 size_t convbytes;
517 u_int16_t *uchp;
518
519 /*
520 * On Joliet CDs use the UCS-2 volume identifier.
521 *
522 * This name can have up to 15 UCS-2 chars and is
523 * terminated with 0x0000 or padded with 0x0020.
524 */
525 convflags = UTF_DECOMPOSED;
526 if (BYTE_ORDER != BIG_ENDIAN)
527 convflags |= UTF_REVERSE_ENDIAN;
528 for (i = 0, uchp = (u_int16_t *)sup->volume_id; i < 15 && uchp[i]; ++i);
529 if ((utf8_encodestr((u_int16_t *)sup->volume_id, (i * 2), vol_id,
530 &convbytes, sizeof(vol_id), 0, convflags) == 0)
531 && convbytes && (vol_id[0] != ' ')) {
532 char * strp;
533
534 /* Remove trailing spaces */
535 strp = vol_id + convbytes - 1;
536 while (strp > vol_id && *strp == ' ')
537 *strp-- = '\0';
538 bcopy(vol_id, isomp->volume_id, convbytes);
539 }
540
541 rootp = (struct iso_directory_record *)
542 sup->root_directory_record;
543 bcopy (rootp, isomp->root, sizeof isomp->root);
544 isomp->root_extent = isonum_733 (rootp->extent);
545 isomp->root_size = isonum_733 (rootp->size);
546 supbp->b_flags |= B_AGE;
547 isomp->iso_ftype = ISO_FTYPE_JOLIET;
548 }
549
550 if (supbp) {
551 brelse(supbp);
552 supbp = NULL;
553 }
554
555 return (0);
556 out:
557 if (bp)
558 brelse(bp);
559 if (pribp)
560 brelse(pribp);
561 if (supbp)
562 brelse(supbp);
563 if (needclose)
564 (void)VOP_CLOSE(devvp, FREAD, NOCRED, p);
565 if (isomp) {
566 FREE((caddr_t)isomp, M_ISOFSMNT);
567 mp->mnt_data = (qaddr_t)0;
568 }
569
570 /* Clear the mounted on bit in the devvp If it */
571 /* not set, this is a nop and there is no way to */
572 /* get here with it set unless we did it. If you*/
573 /* are making code changes which makes the above */
574 /* assumption not true, change this code. */
575
576 devvp->v_specflags &= ~SI_MOUNTEDON;
577
578 return (error);
579 }
580
581 /*
582 * Make a filesystem operational.
583 * Nothing to do at the moment.
584 */
585 /* ARGSUSED */
586 int
587 cd9660_start(mp, flags, p)
588 struct mount *mp;
589 int flags;
590 struct proc *p;
591 {
592 return (0);
593 }
594
595 /*
596 * unmount system call
597 */
598 int
599 cd9660_unmount(mp, mntflags, p)
600 struct mount *mp;
601 int mntflags;
602 struct proc *p;
603 {
604 register struct iso_mnt *isomp;
605 int error, flags = 0;
606
607 if ( (mntflags & MNT_FORCE) )
608 flags |= FORCECLOSE;
609
610 if ( (error = vflush(mp, NULLVP, flags)) )
611 return (error);
612
613 isomp = VFSTOISOFS(mp);
614
615 #ifdef ISODEVMAP
616 if (isomp->iso_ftype == ISO_FTYPE_RRIP)
617 iso_dunmap(isomp->im_dev);
618 #endif
619
620 isomp->im_devvp->v_specflags &= ~SI_MOUNTEDON;
621 error = VOP_CLOSE(isomp->im_devvp, FREAD, NOCRED, p);
622 vrele(isomp->im_devvp);
623 FREE((caddr_t)isomp, M_ISOFSMNT);
624 mp->mnt_data = (qaddr_t)0;
625 mp->mnt_flag &= ~MNT_LOCAL;
626
627 return (error);
628 }
629
630 /*
631 * Return root of a filesystem
632 */
633 int
634 cd9660_root(mp, vpp)
635 struct mount *mp;
636 struct vnode **vpp;
637 {
638 struct iso_mnt *imp = VFSTOISOFS(mp);
639 struct iso_directory_record *dp =
640 (struct iso_directory_record *)imp->root;
641 ino_t ino = isodirino(dp, imp);
642
643 /*
644 * With RRIP we must use the `.' entry of the root directory.
645 * Simply tell vget, that it's a relocated directory.
646 */
647 return (cd9660_vget_internal(mp, ino, vpp,
648 imp->iso_ftype == ISO_FTYPE_RRIP, dp, current_proc()));
649 }
650
651 /*
652 * Do operations associated with quotas, not supported
653 */
654 /* ARGSUSED */
655 int
656 cd9660_quotactl(mp, cmd, uid, arg, p)
657 struct mount *mp;
658 int cmd;
659 uid_t uid;
660 caddr_t arg;
661 struct proc *p;
662 {
663
664 return (EOPNOTSUPP);
665 }
666
667 /*
668 * Get file system statistics.
669 */
670 int
671 cd9660_statfs(mp, sbp, p)
672 struct mount *mp;
673 register struct statfs *sbp;
674 struct proc *p;
675 {
676 register struct iso_mnt *isomp;
677
678 isomp = VFSTOISOFS(mp);
679
680 #ifdef COMPAT_09
681 sbp->f_type = 5;
682 #else
683 sbp->f_type = 0;
684 #endif
685 sbp->f_bsize = isomp->logical_block_size;
686 sbp->f_iosize = sbp->f_bsize; /* XXX */
687 sbp->f_blocks = isomp->volume_space_size;
688 sbp->f_bfree = 0; /* total free blocks */
689 sbp->f_bavail = 0; /* blocks free for non superuser */
690 sbp->f_files = 0; /* total files */
691 sbp->f_ffree = 0; /* free file nodes */
692 if (sbp != &mp->mnt_stat) {
693 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
694 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
695 }
696
697 strncpy( sbp->f_fstypename, mp->mnt_vfc->vfc_name, (MFSNAMELEN - 1) );
698 sbp->f_fstypename[(MFSNAMELEN - 1)] = '\0';
699
700 /* DO NOT use the first spare for flags; it's been reassigned for another use: */
701 /* sbp->f_spare[0] = isomp->im_flags; */
702
703 return (0);
704 }
705
706 /* ARGSUSED */
707 int
708 cd9660_sync(mp, waitfor, cred, p)
709 struct mount *mp;
710 int waitfor;
711 struct ucred *cred;
712 struct proc *p;
713 {
714
715 return (0);
716 }
717
718 /*
719 * File handle to vnode
720 *
721 * Have to be really careful about stale file handles:
722 * - check that the inode number is in range
723 * - call iget() to get the locked inode
724 * - check for an unallocated inode (i_mode == 0)
725 * - check that the generation number matches
726 */
727
728 struct ifid {
729 ushort ifid_len;
730 ushort ifid_pad;
731 int ifid_ino;
732 long ifid_start;
733 };
734
735 /* ARGSUSED */
736 int
737 cd9660_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
738 register struct mount *mp;
739 struct fid *fhp;
740 struct mbuf *nam;
741 struct vnode **vpp;
742 int *exflagsp;
743 struct ucred **credanonp;
744 {
745 struct ifid *ifhp = (struct ifid *)fhp;
746 register struct iso_node *ip;
747 register struct netcred *np;
748 register struct iso_mnt *imp = VFSTOISOFS(mp);
749 struct vnode *nvp;
750 int error;
751
752 #ifdef ISOFS_DBG
753 printf("fhtovp: ino %d, start %ld\n",
754 ifhp->ifid_ino, ifhp->ifid_start);
755 #endif
756
757 /*
758 * Get the export permission structure for this <mp, client> tuple.
759 */
760 np = vfs_export_lookup(mp, &imp->im_export, nam);
761 if (np == NULL)
762 return (EACCES);
763
764 if ( (error = VFS_VGET(mp, &ifhp->ifid_ino, &nvp)) ) {
765 *vpp = NULLVP;
766 return (error);
767 }
768 ip = VTOI(nvp);
769 if (ip->inode.iso_mode == 0) {
770 vput(nvp);
771 *vpp = NULLVP;
772 return (ESTALE);
773 }
774 *vpp = nvp;
775 *exflagsp = np->netc_exflags;
776 *credanonp = &np->netc_anon;
777 return (0);
778 }
779
780 int
781 cd9660_vget(mp, ino, vpp)
782 struct mount *mp;
783 void *ino;
784 struct vnode **vpp;
785 {
786 /*
787 * XXXX
788 * It would be nice if we didn't always set the `relocated' flag
789 * and force the extra read, but I don't want to think about fixing
790 * that right now.
791 */
792
793 return ( cd9660_vget_internal( mp, *(ino_t*)ino, vpp, 0,
794 (struct iso_directory_record *) 0,
795 current_proc()) );
796 }
797
798 int
799 cd9660_vget_internal(mp, ino, vpp, relocated, isodir, p)
800 struct mount *mp;
801 ino_t ino;
802 struct vnode **vpp;
803 int relocated;
804 struct iso_directory_record *isodir;
805 struct proc *p;
806 {
807 register struct iso_mnt *imp;
808 struct iso_node *ip;
809 struct buf *bp;
810 struct vnode *vp, *nvp;
811 dev_t dev;
812 int error;
813
814 imp = VFSTOISOFS(mp);
815 dev = imp->im_dev;
816
817 /* Check for unmount in progress */
818 if (mp->mnt_kern_flag & MNTK_UNMOUNT) {
819 *vpp = NULLVP;
820 return (EPERM);
821 }
822
823 if ((*vpp = cd9660_ihashget(dev, ino, p)) != NULLVP)
824 return (0);
825
826 MALLOC_ZONE(ip, struct iso_node *, sizeof(struct iso_node),
827 M_ISOFSNODE, M_WAITOK);
828 /* Allocate a new vnode/iso_node. */
829 if ( (error = getnewvnode(VT_ISOFS, mp, cd9660_vnodeop_p, &vp)) ) {
830 FREE_ZONE(ip,sizeof(struct iso_node), M_ISOFSNODE);
831 *vpp = NULLVP;
832 return (error);
833 }
834 bzero((caddr_t)ip, sizeof(struct iso_node));
835 lockinit(&ip->i_lock, PINOD,"isonode",0,0);
836 vp->v_data = ip;
837 ip->i_vnode = vp;
838 ip->i_dev = dev;
839 ip->i_number = ino;
840 ip->i_namep = &isonullname[0];
841
842 /*
843 * Put it onto its hash chain and lock it so that other requests for
844 * this inode will block if they arrive while we are sleeping waiting
845 * for old data structures to be purged or for the contents of the
846 * disk portion of this inode to be read.
847 */
848 cd9660_ihashins(ip);
849
850 if (isodir == 0) {
851 int lbn, off;
852
853 lbn = lblkno(imp, ino);
854 if (lbn >= imp->volume_space_size) {
855 vput(vp);
856 printf("fhtovp: lbn exceed volume space %d\n", lbn);
857 return (ESTALE);
858 }
859
860 off = blkoff(imp, ino);
861 if (off + ISO_DIRECTORY_RECORD_SIZE > imp->logical_block_size) {
862 vput(vp);
863 printf("fhtovp: crosses block boundary %d\n",
864 off + ISO_DIRECTORY_RECORD_SIZE);
865 return (ESTALE);
866 }
867
868 error = bread(imp->im_devvp, lbn,
869 imp->logical_block_size, NOCRED, &bp);
870 if (error) {
871 vput(vp);
872 brelse(bp);
873 printf("fhtovp: bread error %d\n",error);
874 return (error);
875 }
876 isodir = (struct iso_directory_record *)(bp->b_data + off);
877
878 if (off + isonum_711(isodir->length) >
879 imp->logical_block_size) {
880 vput(vp);
881 if (bp != 0)
882 brelse(bp);
883 printf("fhtovp: directory crosses block boundary "
884 "%d[off=%d/len=%d]\n",
885 off +isonum_711(isodir->length), off,
886 isonum_711(isodir->length));
887 return (ESTALE);
888 }
889
890 /*
891 * for directories we can get parentID from adjacent
892 * parent directory record
893 */
894 if ((isonum_711(isodir->flags) & directoryBit)
895 && (isodir->name[0] == 0)) {
896 struct iso_directory_record *pdp;
897
898 pdp = (struct iso_directory_record *)
899 ((char *)bp->b_data + isonum_711(isodir->length));
900 if ((isonum_711(pdp->flags) & directoryBit)
901 && (pdp->name[0] == 1))
902 ip->i_parent = isodirino(pdp, imp);
903 }
904 } else
905 bp = 0;
906
907 ip->i_mnt = imp;
908 ip->i_devvp = imp->im_devvp;
909 VREF(ip->i_devvp);
910
911 if (relocated) {
912 /*
913 * On relocated directories we must
914 * read the `.' entry out of a dir.
915 */
916 ip->iso_start = ino >> imp->im_bshift;
917 if (bp != 0)
918 brelse(bp);
919 if ( (error = VOP_BLKATOFF(vp, (off_t)0, NULL, &bp)) ) {
920 vput(vp);
921 return (error);
922 }
923 isodir = (struct iso_directory_record *)bp->b_data;
924 }
925
926 /*
927 * go get apple extensions to ISO directory record or use
928 * defaults when there are no apple extensions.
929 */
930 if ( (isonum_711( isodir->flags ) & directoryBit) == 0 ) {
931 /* This is an ISO directory record for a file */
932 DRGetTypeCreatorAndFlags( imp, isodir, &ip->i_FileType,
933 &ip->i_Creator, &ip->i_FinderFlags );
934 }
935
936 ip->iso_extent = isonum_733(isodir->extent);
937 ip->i_size = isonum_733(isodir->size);
938 ip->iso_start = isonum_711(isodir->ext_attr_length) + ip->iso_extent;
939
940 /*
941 * if we have a valid name, fill in i_namep with UTF-8 name
942 */
943 if (isonum_711(isodir->name_len) != 0) {
944 u_char *utf8namep;
945 u_short namelen;
946 ino_t inump = 0;
947
948 MALLOC(utf8namep, u_char *, ISO_RRIP_NAMEMAX + 1, M_TEMP, M_WAITOK);
949 namelen = isonum_711(isodir->name_len);
950
951 switch (imp->iso_ftype) {
952 case ISO_FTYPE_RRIP:
953 cd9660_rrip_getname(isodir, utf8namep, &namelen, &inump, imp);
954 break;
955
956 case ISO_FTYPE_JOLIET:
957 ucsfntrans((u_int16_t *)isodir->name, namelen,
958 utf8namep, &namelen,
959 isonum_711(isodir->flags) & directoryBit);
960 break;
961
962 default:
963 isofntrans (isodir->name, namelen,
964 utf8namep, &namelen,
965 imp->iso_ftype == ISO_FTYPE_9660);
966 }
967
968 utf8namep[namelen] = '\0';
969 MALLOC(ip->i_namep, u_char *, namelen + 1, M_TEMP, M_WAITOK);
970 bcopy(utf8namep, ip->i_namep, namelen + 1);
971 FREE(utf8namep, M_TEMP);
972 }
973
974 /*
975 * Setup time stamp, attribute
976 */
977 vp->v_type = VNON;
978 switch (imp->iso_ftype) {
979 default: /* ISO_FTYPE_9660 */
980 {
981 struct buf *bp2;
982 int off;
983 if ((imp->im_flags & ISOFSMNT_EXTATT)
984 && (off = isonum_711(isodir->ext_attr_length)))
985 VOP_BLKATOFF(vp, (off_t)-(off << imp->im_bshift), NULL, &bp2);
986 else
987 bp2 = NULL;
988 cd9660_defattr(isodir, ip, bp2);
989 cd9660_deftstamp(isodir, ip, bp2);
990 if (bp2)
991 brelse(bp2);
992 break;
993 }
994 case ISO_FTYPE_RRIP:
995 cd9660_rrip_analyze(isodir, ip, imp);
996 break;
997 }
998
999 if (bp != 0)
1000 brelse(bp);
1001
1002 /*
1003 * Initialize the associated vnode
1004 */
1005
1006 if (ip->iso_extent == imp->root_extent) {
1007 vp->v_flag |= VROOT;
1008 ip->i_parent = 1; /* root's parent is always 1 by convention */
1009 /* mode type must be S_IFDIR */
1010 ip->inode.iso_mode = (ip->inode.iso_mode & ~S_IFMT) | S_IFDIR;
1011 }
1012
1013 switch (vp->v_type = IFTOVT(ip->inode.iso_mode)) {
1014 case VFIFO:
1015 #if FIFO
1016 vp->v_op = cd9660_fifoop_p;
1017 break;
1018 #else
1019 vput(vp);
1020 return (EOPNOTSUPP);
1021 #endif /* FIFO */
1022 case VCHR:
1023 case VBLK:
1024 /*
1025 * if device, look at device number table for translation
1026 */
1027 #ifdef ISODEVMAP
1028 if (dp = iso_dmap(dev, ino, 0))
1029 ip->inode.iso_rdev = dp->d_dev;
1030 #endif
1031 vp->v_op = cd9660_specop_p;
1032 if ( (nvp = checkalias(vp, ip->inode.iso_rdev, mp)) ) {
1033 /*
1034 * Discard unneeded vnode, but save its iso_node.
1035 */
1036 cd9660_ihashrem(ip);
1037 VOP_UNLOCK(vp, 0, p);
1038 nvp->v_data = vp->v_data;
1039 vp->v_data = NULL;
1040 vp->v_op = spec_vnodeop_p;
1041 vrele(vp);
1042 vgone(vp);
1043 /*
1044 * Reinitialize aliased inode.
1045 */
1046 vp = nvp;
1047 ip->i_vnode = vp;
1048 cd9660_ihashins(ip);
1049 }
1050 break;
1051 case VREG:
1052 ubc_info_init(vp);
1053 break;
1054 default:
1055 break;
1056 }
1057
1058 /*
1059 * XXX need generation number?
1060 */
1061
1062 *vpp = vp;
1063
1064 return (0);
1065 }
1066
1067
1068 /************************************************************************
1069 *
1070 * Function: DRGetTypeCreatorAndFlags
1071 *
1072 * Purpose: Set up the fileType, fileCreator and fileFlags
1073 *
1074 * Returns: none
1075 *
1076 * Side Effects: sets *theTypePtr, *theCreatorPtr, and *theFlagsPtr
1077 *
1078 * Description:
1079 *
1080 * Revision History:
1081 * 28 Jul 88 BL¡B Added a new extension type of 6, which allows
1082 * the specification of four of the finder flags.
1083 * We let the creator of the disk just copy over
1084 * the finder flags, but we only look at always
1085 * switch launch, system, bundle, and locked bits.
1086 * 15 Aug 88 BL¡B The Apple extensions to ISO 9660 implemented the
1087 * padding field at the end of a directory record
1088 * incorrectly.
1089 * 19 Jul 89 BG Rewrote routine to handle the "new" Apple
1090 * Extensions definition, as well as take into
1091 * account the possibility of "other" definitions.
1092 * 02 Nov 89 BG Corrected the 'AA' SystemUseID processing to
1093 * check for SystemUseID == 2 (HFS). Was incorrectly
1094 * checking for SystemUseID == 1 (ProDOS) before.
1095 * 18 Mar 92 CMP Fixed the check for whether len_fi was odd or even.
1096 * Before it would always assume even for an XA record.
1097 * 26 Dec 97 jwc Swiped from MacOS implementation of ISO 9660 CD-ROM
1098 * support and modified to work in MacOSX file system.
1099 *
1100 *********************************************************************** */
1101
1102 static void
1103 DRGetTypeCreatorAndFlags( struct iso_mnt * theMountPointPtr,
1104 struct iso_directory_record * theDirRecPtr,
1105 u_int32_t * theTypePtr,
1106 u_int32_t * theCreatorPtr,
1107 u_int16_t * theFlagsPtr )
1108 {
1109 int foundStuff;
1110 u_int32_t myType;
1111 u_int32_t myCreator;
1112 AppleExtension *myAppleExtPtr;
1113 NewAppleExtension *myNewAppleExtPtr;
1114 u_int16_t myFinderFlags;
1115 char *myPtr;
1116
1117 foundStuff = 1;
1118 myType = 0x3f3f3f3f;
1119 myCreator = 0x3f3f3f3f;
1120 myFinderFlags = 0;
1121 *theFlagsPtr = 0x0000;
1122
1123 /*
1124 * handle the fact that our original apple extensions didn't take
1125 * into account the padding byte on a file name
1126 */
1127
1128 myPtr = &theDirRecPtr->name[ (isonum_711(theDirRecPtr->name_len)) ];
1129
1130 /* if string length is even, bump myPtr for padding byte */
1131 if ( ((isonum_711(theDirRecPtr->name_len)) & 0x01) == 0 )
1132 myPtr++;
1133 myAppleExtPtr = (AppleExtension *) myPtr;
1134
1135 /*
1136 * checking for whether or not the new 'AA' code is being
1137 * called (and if so, correctly)
1138 */
1139 if ( (isonum_711(theDirRecPtr->length)) <=
1140 ISO_DIRECTORY_RECORD_SIZE + (isonum_711(theDirRecPtr->name_len)) ) {
1141 foundStuff = 0;
1142 goto DoneLooking;
1143 }
1144
1145 foundStuff = 0; /* now we default to *false* until we find a good one */
1146 myPtr = (char *) myAppleExtPtr;
1147
1148 if ( (theMountPointPtr->im_flags2 & IMF2_IS_CDXA) != 0 )
1149 myPtr += 14;/* add in CD-XA fixed record offset (tnx, Phillips) */
1150 myNewAppleExtPtr = (NewAppleExtension *) myPtr;
1151
1152 /* calculate the "real" end of the directory record information */
1153 myPtr = ((char *) theDirRecPtr) + (isonum_711(theDirRecPtr->length));
1154 while( (char *) myNewAppleExtPtr < myPtr ) /* end of directory buffer */
1155 {
1156 /*
1157 * If we get here, we can assume that ALL further entries in this
1158 * directory record are of the form:
1159 *
1160 * struct OptionalSystemUse
1161 * {
1162 * byte Signature[2];
1163 * byte systemUseID;
1164 * byte OSULength;
1165 * byte fileType[4]; # only if HFS
1166 * byte fileCreator[4]; # only if HFS
1167 * byte finderFlags[2]; # only if HFS
1168 * };
1169 *
1170 * This means that we can examine the Signature bytes to see
1171 * if they are 'AA' (the NEW Apple extension signature).
1172 * If they are, deal with them. If they aren't,
1173 * the OSULength field will tell us how long this extension
1174 * info is (including the signature and length bytes) and that
1175 * will allow us to walk the OptionalSystemUse records until
1176 * we hit the end of them or run off the end of the
1177 * directory record.
1178 */
1179 u_char *myFromPtr, *myToPtr;
1180 union
1181 {
1182 u_int32_t fourchars;
1183 u_char chars[4];
1184 } myChars;
1185
1186 if ( (myNewAppleExtPtr->signature[0] == 'A') &&
1187 (myNewAppleExtPtr->signature[1] == 'A') ) {
1188 if ( isonum_711(myNewAppleExtPtr->systemUseID) == 2 ) {
1189 /* HFS */
1190 foundStuff = 1; /* we got one! */
1191
1192 myFromPtr = &myNewAppleExtPtr->fileType[0];
1193 myToPtr = &myChars.chars[0];
1194 *myToPtr++ = *myFromPtr++;
1195 *myToPtr++ = *myFromPtr++;
1196 *myToPtr++ = *myFromPtr++;
1197 *myToPtr = *myFromPtr;
1198 myType = myChars.fourchars; /* copy file type to user var */
1199
1200 myFromPtr = &myNewAppleExtPtr->fileCreator[0];
1201 myToPtr = &myChars.chars[0];
1202 *myToPtr++ = *myFromPtr++;
1203 *myToPtr++ = *myFromPtr++;
1204 *myToPtr++ = *myFromPtr++;
1205 *myToPtr = *myFromPtr;
1206 myCreator = myChars.fourchars; /* copy creator to user var */
1207
1208 myFromPtr = &myNewAppleExtPtr->finderFlags[0];
1209 myToPtr = &myChars.chars[2]; /* *flags* is a short */
1210 myChars.fourchars = 0;
1211 *myToPtr++ = *myFromPtr++;
1212 *myToPtr = *myFromPtr;
1213 myFinderFlags = myChars.fourchars;
1214 myFinderFlags &=
1215 ( fAlwaysBit | fSystemBit | fHasBundleBit | fLockedBit );
1216 /* return Finder flags to user var */
1217 *theFlagsPtr = (myFinderFlags | fInitedBit);
1218
1219 break; /* exit the loop */
1220 }
1221 }
1222
1223 /*
1224 * Check to see if we have a reasonable OSULength value.
1225 * ZERO is not an acceptable value. Nor is any value less than 4.
1226 */
1227
1228 if ( (isonum_711(myNewAppleExtPtr->OSULength)) < 4 )
1229 break; /* not acceptable - get out! */
1230
1231 /* otherwise, step past this SystemUse record */
1232 (char *)myNewAppleExtPtr += (isonum_711(myNewAppleExtPtr->OSULength));
1233
1234 } /* end of while loop */
1235
1236 DoneLooking:
1237 if ( foundStuff != 0 ) {
1238 *theTypePtr = myType;
1239 *theCreatorPtr = myCreator;
1240 } else {
1241 *theTypePtr = 0;
1242 *theCreatorPtr = 0;
1243 }
1244
1245 return;
1246
1247 } /* DRGetTypeCreatorAndFlags */
1248
1249
1250 /*
1251 * Vnode pointer to File handle
1252 */
1253 /* ARGSUSED */
1254 int
1255 cd9660_vptofh(vp, fhp)
1256 struct vnode *vp;
1257 struct fid *fhp;
1258 {
1259 register struct iso_node *ip = VTOI(vp);
1260 register struct ifid *ifhp;
1261
1262 ifhp = (struct ifid *)fhp;
1263 ifhp->ifid_len = sizeof(struct ifid);
1264
1265 ifhp->ifid_ino = ip->i_number;
1266 ifhp->ifid_start = ip->iso_start;
1267
1268 #ifdef ISOFS_DBG
1269 printf("vptofh: ino %d, start %ld\n",
1270 ifhp->ifid_ino,ifhp->ifid_start);
1271 #endif
1272 return (0);
1273 }
1274
1275 /*
1276 * Fast-FileSystem only?
1277 */
1278 int
1279 cd9660_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
1280 int * name;
1281 u_int namelen;
1282 void* oldp;
1283 size_t * oldlenp;
1284 void * newp;
1285 size_t newlen;
1286 struct proc * p;
1287 {
1288 return (EOPNOTSUPP);
1289 }
1290