]> git.saurik.com Git - apple/xnu.git/blob - bsd/isofs/cd9660/cd9660_vfsops.c
xnu-517.7.7.tar.gz
[apple/xnu.git] / bsd / isofs / cd9660 / cd9660_vfsops.c
1 /*
2 * Copyright (c) 2000-2003 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 <sys/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 /*
89 * Minutes, Seconds, Frames (M:S:F)
90 */
91 struct CDMSF {
92 u_char minute;
93 u_char second;
94 u_char frame;
95 };
96
97 /*
98 * Table Of Contents
99 */
100 struct CDTOC_Desc {
101 u_char session;
102 u_char ctrl_adr; /* typed to be machine and compiler independent */
103 u_char tno;
104 u_char point;
105 struct CDMSF address;
106 u_char zero;
107 struct CDMSF p;
108 };
109
110 struct CDTOC {
111 u_short length; /* in native cpu endian */
112 u_char first_session;
113 u_char last_session;
114 struct CDTOC_Desc trackdesc[1];
115 };
116
117 #define MSF_TO_LBA(msf) \
118 (((((msf).minute * 60UL) + (msf).second) * 75UL) + (msf).frame - 150)
119
120 u_char isonullname[] = "\0";
121
122 extern int enodev ();
123
124 struct vfsops cd9660_vfsops = {
125 cd9660_mount,
126 cd9660_start,
127 cd9660_unmount,
128 cd9660_root,
129 cd9660_quotactl,
130 cd9660_statfs,
131 cd9660_sync,
132 cd9660_vget,
133 cd9660_fhtovp,
134 cd9660_vptofh,
135 cd9660_init,
136 cd9660_sysctl
137 };
138
139 /*
140 * Called by vfs_mountroot when iso is going to be mounted as root.
141 *
142 * Name is updated by mount(8) after booting.
143 */
144 #define ROOTNAME "root_device"
145
146 static int iso_mountfs __P((struct vnode *devvp, struct mount *mp,
147 struct proc *p, struct iso_args *argp));
148
149 static void DRGetTypeCreatorAndFlags(
150 struct iso_mnt * theMountPointPtr,
151 struct iso_directory_record * theDirRecPtr,
152 u_int32_t * theTypePtr,
153 u_int32_t * theCreatorPtr,
154 u_int16_t * theFlagsPtr);
155
156 int cd9660_vget_internal(
157 struct mount *mp,
158 ino_t ino,
159 struct vnode **vpp,
160 int relocated,
161 struct iso_directory_record *isodir,
162 struct proc *p);
163
164 int
165 cd9660_mountroot()
166 {
167 register struct mount *mp;
168 extern struct vnode *rootvp;
169 struct proc *p = current_proc(); /* XXX */
170 struct iso_mnt *imp;
171 size_t size;
172 int error;
173 struct iso_args args;
174
175 /*
176 * Get vnodes for swapdev and rootdev.
177 */
178 if ( bdevvp(rootdev, &rootvp))
179 panic("cd9660_mountroot: can't setup bdevvp's");
180
181 MALLOC_ZONE(mp, struct mount *,
182 sizeof(struct mount), M_MOUNT, M_WAITOK);
183 bzero((char *)mp, (u_long)sizeof(struct mount));
184
185 /* Initialize the default IO constraints */
186 mp->mnt_maxreadcnt = mp->mnt_maxwritecnt = MAXPHYS;
187 mp->mnt_segreadcnt = mp->mnt_segwritecnt = 32;
188
189 mp->mnt_op = &cd9660_vfsops;
190 mp->mnt_flag = MNT_RDONLY;
191 LIST_INIT(&mp->mnt_vnodelist);
192 args.flags = ISOFSMNT_ROOT;
193 args.ssector = 0;
194 args.fspec = 0;
195 args.toc_length = 0;
196 args.toc = 0;
197 if ((error = iso_mountfs(rootvp, mp, p, &args))) {
198 vrele(rootvp); /* release the reference from bdevvp() */
199
200 if (mp->mnt_kern_flag & MNTK_IO_XINFO)
201 FREE(mp->mnt_xinfo_ptr, M_TEMP);
202 FREE_ZONE(mp, sizeof (struct mount), M_MOUNT);
203 return (error);
204 }
205 simple_lock(&mountlist_slock);
206 CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list);
207 simple_unlock(&mountlist_slock);
208 mp->mnt_vnodecovered = NULLVP;
209 imp = VFSTOISOFS(mp);
210 (void) copystr("/", mp->mnt_stat.f_mntonname, MNAMELEN - 1,
211 &size);
212 bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
213 (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
214 &size);
215 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
216 (void)cd9660_statfs(mp, &mp->mnt_stat, p);
217 return (0);
218 }
219
220 /*
221 * VFS Operations.
222 *
223 * mount system call
224 */
225 int
226 cd9660_mount(mp, path, data, ndp, p)
227 register struct mount *mp;
228 char *path;
229 caddr_t data;
230 struct nameidata *ndp;
231 struct proc *p;
232 {
233 struct vnode *devvp;
234 struct iso_args args;
235 size_t size;
236 int error;
237 struct iso_mnt *imp = NULL;
238
239 if ((error = copyin(data, (caddr_t)&args, sizeof (struct iso_args))))
240 return (error);
241
242 if ((mp->mnt_flag & MNT_RDONLY) == 0)
243 return (EROFS);
244
245 /*
246 * If updating, check whether changing from read-only to
247 * read/write; if there is no device name, that's all we do.
248 */
249 if (mp->mnt_flag & MNT_UPDATE) {
250 imp = VFSTOISOFS(mp);
251 if (args.fspec == 0)
252 return (vfs_export(mp, &imp->im_export, &args.export));
253 }
254 /*
255 * Not an update, or updating the name: look up the name
256 * and verify that it refers to a sensible block device.
257 */
258 NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p);
259 if ((error = namei(ndp)))
260 return (error);
261 devvp = ndp->ni_vp;
262
263 if (devvp->v_type != VBLK) {
264 vrele(devvp);
265 return (ENOTBLK);
266 }
267 if (major(devvp->v_rdev) >= nblkdev) {
268 vrele(devvp);
269 return (ENXIO);
270 }
271 if ((mp->mnt_flag & MNT_UPDATE) == 0)
272 error = iso_mountfs(devvp, mp, p, &args);
273 else {
274 if (devvp != imp->im_devvp)
275 error = EINVAL; /* needs translation */
276 else
277 vrele(devvp);
278 }
279 if (error) {
280 vrele(devvp);
281 return (error);
282 }
283
284 /* Indicate that we don't support volfs */
285 mp->mnt_flag &= ~MNT_DOVOLFS;
286
287 (void) copyinstr(path, mp->mnt_stat.f_mntonname, MNAMELEN - 1, &size);
288 bzero(mp->mnt_stat.f_mntonname + size, MNAMELEN - size);
289 (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
290 &size);
291 bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
292 return (0);
293 }
294
295 /*
296 * Find the BSD device for the physical disk corresponding to the
297 * mount point's device. We use this physical device to read whole
298 * (2352 byte) sectors from the CD to get the content for the video
299 * files (tracks).
300 *
301 * The "path" argument is the path to the block device that the volume
302 * is being mounted on (args.fspec). It should be of the form:
303 * /dev/disk1s0
304 * where the last "s0" part is stripped off to determine the physical
305 * device's path. It is assumed to be in user memory.
306 */
307 static struct vnode *
308 cd9660_phys_device(char *path, struct proc *p)
309 {
310 int err;
311 char *whole_path = NULL; // path to "whole" device
312 char *s, *saved;
313 struct nameidata nd;
314 struct vnode *result;
315 size_t actual_size;
316
317 if (path == NULL)
318 return NULL;
319
320 result = NULL;
321
322 /* Make a copy of the mount from name, then remove trailing "s...". */
323 MALLOC(whole_path, char *, MNAMELEN, M_ISOFSMNT, M_WAITOK);
324 copyinstr(path, whole_path, MNAMELEN-1, &actual_size);
325
326 /*
327 * I would use strrchr or rindex here, but those are declared __private_extern__,
328 * and can't be used across component boundaries at this time.
329 */
330 for (s=whole_path, saved=NULL; *s; ++s)
331 if (*s == 's')
332 saved = s;
333 *saved = '\0';
334
335 /* Lookup the "whole" device. */
336 NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, whole_path, p);
337 err = namei(&nd);
338 if (err) {
339 printf("isofs: Cannot find physical device: %s\n", whole_path);
340 goto done;
341 }
342
343 /* Open the "whole" device. */
344 err = VOP_OPEN(nd.ni_vp, FREAD, FSCRED, p);
345 if (err) {
346 vrele(nd.ni_vp);
347 printf("isofs: Cannot open physical device: %s\n", whole_path);
348 goto done;
349 }
350
351 result = nd.ni_vp;
352
353 done:
354 FREE(whole_path, M_ISOFSMNT);
355 return result;
356 }
357
358
359 /*
360 * See if the given CD-ROM XA disc appears to be a Video CD
361 * (version < 2.0; so, not SVCD). If so, fill in the extent
362 * information for the MPEGAV directory, set the VCD flag,
363 * and return true.
364 */
365 static int
366 cd9660_find_video_dir(struct iso_mnt *isomp)
367 {
368 int result, err;
369 struct vnode *rootvp = NULL;
370 struct vnode *videovp = NULL;
371 struct componentname cn;
372 char dirname[] = "MPEGAV";
373
374 result = 0; /* Assume not a video CD */
375
376 err = cd9660_root(isomp->im_mountp, &rootvp);
377 if (err) {
378 printf("cd9660_find_video_dir: cd9660_root failed (%d)\n", err);
379 return 0; /* couldn't find video dir */
380 }
381
382 cn.cn_nameiop = LOOKUP;
383 cn.cn_flags = LOCKPARENT|ISLASTCN;
384 cn.cn_proc = current_proc();
385 cn.cn_cred = cn.cn_proc->p_ucred;
386 cn.cn_pnbuf = dirname;
387 cn.cn_pnlen = sizeof(dirname)-1;
388 cn.cn_nameptr = cn.cn_pnbuf;
389 cn.cn_namelen = cn.cn_pnlen;
390
391 err = VOP_LOOKUP(rootvp, &videovp, &cn);
392 if (err == 0) {
393 struct iso_node *ip = VTOI(videovp);
394 result = 1; /* Looks like video CD */
395 isomp->video_dir_start = ip->iso_start;
396 isomp->video_dir_end = ip->iso_start + (ip->i_size >> isomp->im_bshift);
397 isomp->im_flags2 |= IMF2_IS_VCD;
398 }
399
400 if (videovp != NULL)
401 vput(videovp);
402 if (rootvp != NULL)
403 vput(rootvp);
404
405 return result;
406 }
407
408 /*
409 * Common code for mount and mountroot
410 */
411 static int
412 iso_mountfs(devvp, mp, p, argp)
413 register struct vnode *devvp;
414 struct mount *mp;
415 struct proc *p;
416 struct iso_args *argp;
417 {
418 register struct iso_mnt *isomp = (struct iso_mnt *)0;
419 struct buf *bp = NULL;
420 struct buf *pribp = NULL, *supbp = NULL;
421 dev_t dev = devvp->v_rdev;
422 int error = EINVAL;
423 int breaderr = 0;
424 int needclose = 0;
425 extern struct vnode *rootvp;
426 u_long iso_bsize;
427 int iso_blknum;
428 int joliet_level;
429 struct iso_volume_descriptor *vdp = NULL;
430 struct iso_primary_descriptor *pri = NULL;
431 struct iso_primary_descriptor *sup = NULL;
432 struct iso_directory_record *rootp;
433 int logical_block_size;
434 u_int8_t vdtype;
435 int blkoff = argp->ssector;
436
437 if (!(mp->mnt_flag & MNT_RDONLY))
438 return (EROFS);
439
440 /*
441 * Disallow multiple mounts of the same device.
442 * Disallow mounting of a device that is currently in use
443 * (except for root, which might share swap device for miniroot).
444 * Flush out any old buffers remaining from a previous use.
445 */
446 if ((error = vfs_mountedon(devvp)))
447 return (error);
448 if (vcount(devvp) > 1 && devvp != rootvp)
449 return (EBUSY);
450 if ((error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0)))
451 return (error);
452
453 if ((error = VOP_OPEN(devvp, FREAD, FSCRED, p)))
454 return (error);
455 needclose = 1;
456
457 /* This is the "logical sector size". The standard says this
458 * should be 2048 or the physical sector size on the device,
459 * whichever is greater. For now, we'll just use a constant.
460 */
461 iso_bsize = ISO_DEFAULT_BLOCK_SIZE;
462
463 /* tell IOKit that we're assuming 2K sectors */
464 if ((error = VOP_IOCTL(devvp, DKIOCSETBLOCKSIZE,
465 (caddr_t)&iso_bsize, FWRITE, p->p_ucred, p)))
466 return (error);
467 devvp->v_specsize = iso_bsize;
468 joliet_level = 0;
469 for (iso_blknum = 16 + blkoff; iso_blknum < (100 + blkoff); iso_blknum++) {
470 if ((error = bread(devvp, iso_blknum, iso_bsize, NOCRED, &bp))) {
471 if (bp) {
472 bp->b_flags |= B_AGE;
473 brelse(bp);
474 bp = NULL;
475 }
476 breaderr = error;
477 printf("iso_mountfs: bread error %d reading block %d\n", error, iso_blknum);
478 continue;
479 }
480
481 vdp = (struct iso_volume_descriptor *)bp->b_data;
482 if (bcmp (vdp->volume_desc_id, ISO_STANDARD_ID, sizeof(vdp->volume_desc_id)) != 0) {
483 #ifdef DEBUG
484 printf("cd9660_vfsops.c: iso_mountfs: "
485 "Invalid ID in volume desciptor.\n");
486 #endif
487 /* There should be a primary volume descriptor followed by any
488 * secondary volume descriptors, then an end volume descriptor.
489 * Some discs are mastered without an end volume descriptor or
490 * they have the type field set and the volume descriptor ID is
491 * not set. If we at least found a primary volume descriptor,
492 * mount the disc.
493 */
494 if (pri != NULL)
495 break;
496
497 error = EINVAL;
498 goto out;
499 }
500
501 vdtype = isonum_711 (vdp->type);
502 if (vdtype == ISO_VD_END)
503 break;
504
505 if (vdtype == ISO_VD_PRIMARY) {
506 if (pribp == NULL) {
507 pribp = bp;
508 bp = NULL;
509 pri = (struct iso_primary_descriptor *)vdp;
510 }
511 } else if(vdtype == ISO_VD_SUPPLEMENTARY) {
512 if (supbp == NULL) {
513 supbp = bp;
514 bp = NULL;
515 sup = (struct iso_primary_descriptor *)vdp;
516
517 if ((argp->flags & ISOFSMNT_NOJOLIET) == 0) {
518 /*
519 * some Joliet CDs are "out-of-spec and don't correctly
520 * set the SVD flags. We ignore the flags and rely soely
521 * on the escape_seq
522 */
523 if (bcmp(sup->escape_seq, ISO_UCS2_Level_1, 3) == 0)
524 joliet_level = 1;
525 else if (bcmp(sup->escape_seq, ISO_UCS2_Level_2, 3) == 0)
526 joliet_level = 2;
527 else if (bcmp(sup->escape_seq, ISO_UCS2_Level_3, 3) == 0)
528 joliet_level = 3;
529 }
530 }
531 }
532
533 if (bp) {
534 bp->b_flags |= B_AGE;
535 brelse(bp);
536 bp = NULL;
537 }
538 }
539
540 if (bp) {
541 bp->b_flags |= B_AGE;
542 brelse(bp);
543 bp = NULL;
544 }
545
546 if (pri == NULL) {
547 if (breaderr)
548 error = breaderr;
549 else
550 error = EINVAL;
551 goto out;
552 }
553
554 logical_block_size = isonum_723 (pri->logical_block_size);
555
556 if (logical_block_size < DEV_BSIZE || logical_block_size > MAXBSIZE
557 || (logical_block_size & (logical_block_size - 1)) != 0) {
558 error = EINVAL;
559 goto out;
560 }
561
562 rootp = (struct iso_directory_record *)pri->root_directory_record;
563
564 MALLOC(isomp, struct iso_mnt *, sizeof *isomp, M_ISOFSMNT, M_WAITOK);
565 bzero((caddr_t)isomp, sizeof *isomp);
566 isomp->im_sector_size = ISO_DEFAULT_BLOCK_SIZE;
567 isomp->logical_block_size = logical_block_size;
568 isomp->volume_space_size = isonum_733 (pri->volume_space_size);
569 /*
570 * Since an ISO9660 multi-session CD can also access previous
571 * sessions, we have to include them into the space consider-
572 * ations. This doesn't yield a very accurate number since
573 * parts of the old sessions might be inaccessible now, but we
574 * can't do much better. This is also important for the NFS
575 * filehandle validation.
576 */
577 isomp->volume_space_size += blkoff;
578 bcopy (rootp, isomp->root, sizeof isomp->root);
579 isomp->root_extent = isonum_733 (rootp->extent);
580 isomp->root_size = isonum_733 (rootp->size);
581
582 /*
583 * getattrlist wants the volume name, create date and modify date
584 */
585
586 /* Remove any trailing white space */
587 if ( strlen(pri->volume_id) ) {
588 char *myPtr;
589
590 myPtr = pri->volume_id + strlen( pri->volume_id ) - 1;
591 while ( *myPtr == ' ' && myPtr >= pri->volume_id ) {
592 *myPtr = 0x00;
593 myPtr--;
594 }
595 }
596
597 if (pri->volume_id[0] == 0)
598 strcpy(isomp->volume_id, ISO_DFLT_VOLUME_ID);
599 else
600 bcopy(pri->volume_id, isomp->volume_id, sizeof(isomp->volume_id));
601 cd9660_tstamp_conv17(pri->creation_date, &isomp->creation_date);
602 cd9660_tstamp_conv17(pri->modification_date, &isomp->modification_date);
603
604 /* See if this is a CD-XA volume */
605 if (bcmp( pri->CDXASignature, ISO_XA_ID,
606 sizeof(pri->CDXASignature) ) == 0 ) {
607 isomp->im_flags2 |= IMF2_IS_CDXA;
608 }
609
610 isomp->im_bmask = logical_block_size - 1;
611 isomp->im_bshift = 0;
612 while ((1 << isomp->im_bshift) < isomp->logical_block_size)
613 isomp->im_bshift++;
614
615 pribp->b_flags |= B_AGE;
616 brelse(pribp);
617 pribp = NULL;
618
619 mp->mnt_data = (qaddr_t)isomp;
620 mp->mnt_stat.f_fsid.val[0] = (long)dev;
621 mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum;
622 mp->mnt_maxsymlinklen = 0;
623 mp->mnt_flag |= MNT_LOCAL;
624
625 isomp->im_mountp = mp;
626 isomp->im_dev = dev;
627 isomp->im_devvp = devvp;
628
629 devvp->v_specflags |= SI_MOUNTEDON;
630
631 /*
632 * If the logical block size is not 2K then we must
633 * set the block device's physical block size to this
634 * disc's logical block size.
635 *
636 */
637 if (logical_block_size != iso_bsize) {
638 iso_bsize = logical_block_size;
639 if ((error = VOP_IOCTL(devvp, DKIOCSETBLOCKSIZE,
640 (caddr_t)&iso_bsize, FWRITE, p->p_ucred, p)))
641 goto out;
642 devvp->v_specsize = iso_bsize;
643 }
644
645 /* Check the Rock Ridge Extention support */
646 if (!(argp->flags & ISOFSMNT_NORRIP)) {
647 if ( (error = bread(isomp->im_devvp,
648 (isomp->root_extent + isonum_711(rootp->ext_attr_length)),
649 isomp->logical_block_size, NOCRED, &bp)) ) {
650
651 printf("iso_mountfs: bread error %d reading block %d\n",
652 error, isomp->root_extent + isonum_711(rootp->ext_attr_length));
653 argp->flags |= ISOFSMNT_NORRIP;
654 goto skipRRIP;
655 }
656 rootp = (struct iso_directory_record *)bp->b_data;
657
658 if ((isomp->rr_skip = cd9660_rrip_offset(rootp,isomp)) < 0) {
659 argp->flags |= ISOFSMNT_NORRIP;
660 } else {
661 argp->flags &= ~ISOFSMNT_GENS;
662 }
663
664 /*
665 * The contents are valid,
666 * but they will get reread as part of another vnode, so...
667 */
668 bp->b_flags |= B_AGE;
669 brelse(bp);
670 bp = NULL;
671 }
672 skipRRIP:
673
674 isomp->im_flags = argp->flags & (ISOFSMNT_NORRIP | ISOFSMNT_GENS |
675 ISOFSMNT_EXTATT | ISOFSMNT_NOJOLIET);
676
677 switch (isomp->im_flags&(ISOFSMNT_NORRIP|ISOFSMNT_GENS)) {
678 default:
679 isomp->iso_ftype = ISO_FTYPE_DEFAULT;
680 break;
681 case ISOFSMNT_GENS|ISOFSMNT_NORRIP:
682 isomp->iso_ftype = ISO_FTYPE_9660;
683 break;
684 case 0:
685 isomp->iso_ftype = ISO_FTYPE_RRIP;
686 break;
687 }
688
689 /* Decide whether to use the Joliet descriptor */
690
691 if (isomp->iso_ftype != ISO_FTYPE_RRIP && joliet_level != 0) {
692 char vol_id[32];
693 int i, convflags;
694 size_t convbytes;
695 u_int16_t *uchp;
696
697 /*
698 * On Joliet CDs use the UCS-2 volume identifier.
699 *
700 * This name can have up to 16 UCS-2 chars.
701 */
702 convflags = UTF_DECOMPOSED;
703 if (BYTE_ORDER != BIG_ENDIAN)
704 convflags |= UTF_REVERSE_ENDIAN;
705 uchp = (u_int16_t *)sup->volume_id;
706 for (i = 0; i < 16 && uchp[i]; ++i);
707 if ((utf8_encodestr((u_int16_t *)sup->volume_id, (i * 2), vol_id,
708 &convbytes, sizeof(vol_id), 0, convflags) == 0)
709 && convbytes && (vol_id[0] != ' ')) {
710 char * strp;
711
712 /* Remove trailing spaces */
713 strp = vol_id + convbytes - 1;
714 while (strp > vol_id && *strp == ' ')
715 *strp-- = '\0';
716 bcopy(vol_id, isomp->volume_id, convbytes + 1);
717 }
718
719 rootp = (struct iso_directory_record *)
720 sup->root_directory_record;
721 bcopy (rootp, isomp->root, sizeof isomp->root);
722 isomp->root_extent = isonum_733 (rootp->extent);
723 isomp->root_size = isonum_733 (rootp->size);
724 supbp->b_flags |= B_AGE;
725 isomp->iso_ftype = ISO_FTYPE_JOLIET;
726 }
727
728 if (supbp) {
729 brelse(supbp);
730 supbp = NULL;
731 }
732
733 /* If there was a TOC in the arguments, copy it in. */
734 if (argp->flags & ISOFSMNT_TOC) {
735 MALLOC(isomp->toc, struct CDTOC *, argp->toc_length, M_ISOFSMNT, M_WAITOK);
736 if ((error = copyin(argp->toc, isomp->toc, argp->toc_length)))
737 goto out;
738 }
739
740 /* See if this could be a Video CD */
741 if ((isomp->im_flags2 & IMF2_IS_CDXA) && cd9660_find_video_dir(isomp)) {
742 /* Get the 2352-bytes-per-block device. */
743 isomp->phys_devvp = cd9660_phys_device(argp->fspec, p);
744 }
745
746 return (0);
747 out:
748 if (bp)
749 brelse(bp);
750 if (pribp)
751 brelse(pribp);
752 if (supbp)
753 brelse(supbp);
754 if (needclose)
755 (void)VOP_CLOSE(devvp, FREAD, NOCRED, p);
756 if (isomp) {
757 if (isomp->toc)
758 FREE((caddr_t)isomp->toc, M_ISOFSMNT);
759 FREE((caddr_t)isomp, M_ISOFSMNT);
760 mp->mnt_data = (qaddr_t)0;
761 }
762
763 /* Clear the mounted on bit in the devvp If it */
764 /* not set, this is a nop and there is no way to */
765 /* get here with it set unless we did it. If you*/
766 /* are making code changes which makes the above */
767 /* assumption not true, change this code. */
768
769 devvp->v_specflags &= ~SI_MOUNTEDON;
770
771 return (error);
772 }
773
774 /*
775 * Make a filesystem operational.
776 * Nothing to do at the moment.
777 */
778 /* ARGSUSED */
779 int
780 cd9660_start(mp, flags, p)
781 struct mount *mp;
782 int flags;
783 struct proc *p;
784 {
785 return (0);
786 }
787
788 /*
789 * unmount system call
790 */
791 int
792 cd9660_unmount(mp, mntflags, p)
793 struct mount *mp;
794 int mntflags;
795 struct proc *p;
796 {
797 register struct iso_mnt *isomp;
798 int error, flags = 0;
799 int force = 0;
800
801 if ( (mntflags & MNT_FORCE) ) {
802 flags |= FORCECLOSE;
803 force = 1;
804 }
805
806 if ( (error = vflush(mp, NULLVP, flags)) && !force )
807 return (error);
808
809 isomp = VFSTOISOFS(mp);
810
811 #ifdef ISODEVMAP
812 if (isomp->iso_ftype == ISO_FTYPE_RRIP)
813 iso_dunmap(isomp->im_dev);
814 #endif
815
816 isomp->im_devvp->v_specflags &= ~SI_MOUNTEDON;
817 error = VOP_CLOSE(isomp->im_devvp, FREAD, NOCRED, p);
818 if (error && !force )
819 return(error);
820
821 vrele(isomp->im_devvp);
822
823 if (isomp->phys_devvp) {
824 error = VOP_CLOSE(isomp->phys_devvp, FREAD, FSCRED, p);
825 if (error && !force)
826 return error;
827 vrele(isomp->phys_devvp);
828 }
829
830 if (isomp->toc)
831 FREE((caddr_t)isomp->toc, M_ISOFSMNT);
832
833 FREE((caddr_t)isomp, M_ISOFSMNT);
834 mp->mnt_data = (qaddr_t)0;
835 mp->mnt_flag &= ~MNT_LOCAL;
836 return (0);
837 }
838
839 /*
840 * Return root of a filesystem
841 */
842 int
843 cd9660_root(mp, vpp)
844 struct mount *mp;
845 struct vnode **vpp;
846 {
847 struct iso_mnt *imp = VFSTOISOFS(mp);
848 struct iso_directory_record *dp =
849 (struct iso_directory_record *)imp->root;
850 ino_t ino = isodirino(dp, imp);
851
852 /*
853 * With RRIP we must use the `.' entry of the root directory.
854 * Simply tell vget, that it's a relocated directory.
855 */
856 return (cd9660_vget_internal(mp, ino, vpp,
857 imp->iso_ftype == ISO_FTYPE_RRIP, dp, current_proc()));
858 }
859
860 /*
861 * Do operations associated with quotas, not supported
862 */
863 /* ARGSUSED */
864 int
865 cd9660_quotactl(mp, cmd, uid, arg, p)
866 struct mount *mp;
867 int cmd;
868 uid_t uid;
869 caddr_t arg;
870 struct proc *p;
871 {
872
873 return (EOPNOTSUPP);
874 }
875
876 /*
877 * Get file system statistics.
878 */
879 int
880 cd9660_statfs(mp, sbp, p)
881 struct mount *mp;
882 register struct statfs *sbp;
883 struct proc *p;
884 {
885 register struct iso_mnt *isomp;
886
887 isomp = VFSTOISOFS(mp);
888
889 #ifdef COMPAT_09
890 sbp->f_type = 5;
891 #else
892 sbp->f_type = 0;
893 #endif
894 sbp->f_bsize = isomp->logical_block_size;
895 sbp->f_iosize = sbp->f_bsize; /* XXX */
896 sbp->f_blocks = isomp->volume_space_size;
897 sbp->f_bfree = 0; /* total free blocks */
898 sbp->f_bavail = 0; /* blocks free for non superuser */
899 sbp->f_files = 0; /* total files */
900 sbp->f_ffree = 0; /* free file nodes */
901 if (sbp != &mp->mnt_stat) {
902 bcopy(mp->mnt_stat.f_mntonname, sbp->f_mntonname, MNAMELEN);
903 bcopy(mp->mnt_stat.f_mntfromname, sbp->f_mntfromname, MNAMELEN);
904 }
905
906 strncpy( sbp->f_fstypename, mp->mnt_vfc->vfc_name, (MFSNAMELEN - 1) );
907 sbp->f_fstypename[(MFSNAMELEN - 1)] = '\0';
908
909 /* DO NOT use the first spare for flags; it's been reassigned for another use: */
910 /* sbp->f_spare[0] = isomp->im_flags; */
911
912 return (0);
913 }
914
915 /* ARGSUSED */
916 int
917 cd9660_sync(mp, waitfor, cred, p)
918 struct mount *mp;
919 int waitfor;
920 struct ucred *cred;
921 struct proc *p;
922 {
923
924 return (0);
925 }
926
927 /*
928 * File handle to vnode
929 *
930 * Have to be really careful about stale file handles:
931 * - check that the inode number is in range
932 * - call iget() to get the locked inode
933 * - check for an unallocated inode (i_mode == 0)
934 * - check that the generation number matches
935 */
936
937 struct ifid {
938 ushort ifid_len;
939 ushort ifid_pad;
940 int ifid_ino;
941 long ifid_start;
942 };
943
944 /* ARGSUSED */
945 int
946 cd9660_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp)
947 register struct mount *mp;
948 struct fid *fhp;
949 struct mbuf *nam;
950 struct vnode **vpp;
951 int *exflagsp;
952 struct ucred **credanonp;
953 {
954 struct ifid *ifhp = (struct ifid *)fhp;
955 register struct iso_node *ip;
956 register struct netcred *np;
957 register struct iso_mnt *imp = VFSTOISOFS(mp);
958 struct vnode *nvp;
959 int error;
960
961 #ifdef ISOFS_DBG
962 printf("fhtovp: ino %d, start %ld\n",
963 ifhp->ifid_ino, ifhp->ifid_start);
964 #endif
965
966 /*
967 * Get the export permission structure for this <mp, client> tuple.
968 */
969 np = vfs_export_lookup(mp, &imp->im_export, nam);
970 if (nam && (np == NULL))
971 return (EACCES);
972
973 if ( (error = VFS_VGET(mp, &ifhp->ifid_ino, &nvp)) ) {
974 *vpp = NULLVP;
975 return (error);
976 }
977 ip = VTOI(nvp);
978 if (ip->inode.iso_mode == 0) {
979 vput(nvp);
980 *vpp = NULLVP;
981 return (ESTALE);
982 }
983 *vpp = nvp;
984 if (np) {
985 *exflagsp = np->netc_exflags;
986 *credanonp = &np->netc_anon;
987 }
988 return (0);
989 }
990
991 /*
992 * Scan the TOC for the track which contains the given sector.
993 *
994 * If there is no matching track, or no TOC, then return -1.
995 */
996 static int
997 cd9660_track_for_sector(struct CDTOC *toc, u_int sector)
998 {
999 int i, tracks, result;
1000
1001 if (toc == NULL)
1002 return -1;
1003
1004 tracks = toc->length / sizeof(struct CDTOC_Desc);
1005
1006 result = -1; /* Sentinel in case we don't find the right track. */
1007 for (i=0; i<tracks; ++i) {
1008 if (toc->trackdesc[i].point < 100 && MSF_TO_LBA(toc->trackdesc[i].p) <= sector) {
1009 result = toc->trackdesc[i].point;
1010 }
1011 }
1012
1013 return result;
1014 }
1015
1016 /*
1017 * Determine whether the given node is really a video CD video
1018 * file. Return non-zero if it appears to be a video file.
1019 */
1020 static int
1021 cd9660_is_video_file(struct iso_node *ip, struct iso_mnt *imp)
1022 {
1023 int lbn;
1024 int track;
1025
1026 /* Check whether this could really be a Video CD at all */
1027 if (((imp->im_flags2 & IMF2_IS_VCD) == 0) ||
1028 imp->phys_devvp == NULL ||
1029 imp->toc == NULL)
1030 {
1031 return 0; /* Doesn't even look like VCD... */
1032 }
1033
1034 /* Make sure it is a file */
1035 if ((ip->inode.iso_mode & S_IFMT) != S_IFREG)
1036 return 0; /* Not even a file... */
1037
1038 /*
1039 * And in the right directory. This assumes the same inode
1040 * number convention that cd9660_vget_internal uses (that
1041 * part of the inode number is the block containing the
1042 * file's directory entry).
1043 */
1044 lbn = lblkno(imp, ip->i_number);
1045 if (lbn < imp->video_dir_start || lbn >= imp->video_dir_end)
1046 return 0; /* Not in the correct directory */
1047
1048 /*
1049 * If we get here, the file should be a video file, but
1050 * do a couple of extra sanity checks just to be sure.
1051 * First, verify the form of the name
1052 */
1053 if (strlen(ip->i_namep) != 11 || /* Wrong length? */
1054 bcmp(ip->i_namep+7, ".DAT", 4) || /* Wrong extension? */
1055 (bcmp(ip->i_namep, "AVSEQ", 5) && /* Wrong beginning? */
1056 bcmp(ip->i_namep, "MUSIC", 5)))
1057 {
1058 return 0; /* Invalid name format */
1059 }
1060
1061 /*
1062 * Verify that AVSEQnn.DAT is in track #(nn+1). This would
1063 * not be appropriate for Super Video CD, which allows
1064 * multiple sessions, so the track numbers might not
1065 * match up like this.
1066 */
1067 track = (ip->i_namep[5] - '0') * 10 + ip->i_namep[6] - '0';
1068 if (track != (cd9660_track_for_sector(imp->toc, ip->iso_start) - 1))
1069 {
1070 return 0; /* Wrong number in name */
1071 }
1072
1073 /* It must be a video file if we got here. */
1074 return 1;
1075 }
1076
1077 int
1078 cd9660_vget(mp, ino, vpp)
1079 struct mount *mp;
1080 void *ino;
1081 struct vnode **vpp;
1082 {
1083 /*
1084 * XXXX
1085 * It would be nice if we didn't always set the `relocated' flag
1086 * and force the extra read, but I don't want to think about fixing
1087 * that right now.
1088 */
1089
1090 return ( cd9660_vget_internal( mp, *(ino_t*)ino, vpp, 0,
1091 (struct iso_directory_record *) 0,
1092 current_proc()) );
1093 }
1094
1095 int
1096 cd9660_vget_internal(mp, ino, vpp, relocated, isodir, p)
1097 struct mount *mp;
1098 ino_t ino;
1099 struct vnode **vpp;
1100 int relocated;
1101 struct iso_directory_record *isodir;
1102 struct proc *p;
1103 {
1104 register struct iso_mnt *imp;
1105 struct iso_node *ip;
1106 struct buf *bp;
1107 struct vnode *vp, *nvp;
1108 dev_t dev;
1109 int error;
1110
1111 imp = VFSTOISOFS(mp);
1112 dev = imp->im_dev;
1113
1114 /* Check for unmount in progress */
1115 if (mp->mnt_kern_flag & MNTK_UNMOUNT) {
1116 *vpp = NULLVP;
1117 return (EPERM);
1118 }
1119
1120 if ((*vpp = cd9660_ihashget(dev, ino, p)) != NULLVP)
1121 return (0);
1122
1123 MALLOC_ZONE(ip, struct iso_node *, sizeof(struct iso_node),
1124 M_ISOFSNODE, M_WAITOK);
1125 /* Allocate a new vnode/iso_node. */
1126 if ( (error = getnewvnode(VT_ISOFS, mp, cd9660_vnodeop_p, &vp)) ) {
1127 FREE_ZONE(ip,sizeof(struct iso_node), M_ISOFSNODE);
1128 *vpp = NULLVP;
1129 return (error);
1130 }
1131 bzero((caddr_t)ip, sizeof(struct iso_node));
1132 lockinit(&ip->i_lock, PINOD,"isonode",0,0);
1133 vp->v_data = ip;
1134 ip->i_vnode = vp;
1135 ip->i_dev = dev;
1136 ip->i_number = ino;
1137 ip->i_namep = &isonullname[0];
1138
1139 /*
1140 * Put it onto its hash chain and lock it so that other requests for
1141 * this inode will block if they arrive while we are sleeping waiting
1142 * for old data structures to be purged or for the contents of the
1143 * disk portion of this inode to be read.
1144 */
1145 cd9660_ihashins(ip);
1146
1147 if (isodir == 0) {
1148 int lbn, off;
1149
1150 lbn = lblkno(imp, ino);
1151 if (lbn >= imp->volume_space_size) {
1152 vput(vp);
1153 printf("fhtovp: lbn exceed volume space %d\n", lbn);
1154 return (ESTALE);
1155 }
1156
1157 off = blkoff(imp, ino);
1158 if (off + ISO_DIRECTORY_RECORD_SIZE > imp->logical_block_size) {
1159 vput(vp);
1160 printf("fhtovp: crosses block boundary %d\n",
1161 off + ISO_DIRECTORY_RECORD_SIZE);
1162 return (ESTALE);
1163 }
1164
1165 error = bread(imp->im_devvp, lbn,
1166 imp->logical_block_size, NOCRED, &bp);
1167 if (error) {
1168 vput(vp);
1169 brelse(bp);
1170 printf("fhtovp: bread error %d\n",error);
1171 return (error);
1172 }
1173 isodir = (struct iso_directory_record *)(bp->b_data + off);
1174
1175 if (off + isonum_711(isodir->length) >
1176 imp->logical_block_size) {
1177 vput(vp);
1178 if (bp != 0)
1179 brelse(bp);
1180 printf("fhtovp: directory crosses block boundary "
1181 "%d[off=%d/len=%d]\n",
1182 off +isonum_711(isodir->length), off,
1183 isonum_711(isodir->length));
1184 return (ESTALE);
1185 }
1186
1187 /*
1188 * for directories we can get parentID from adjacent
1189 * parent directory record
1190 */
1191 if ((isonum_711(isodir->flags) & directoryBit)
1192 && (isodir->name[0] == 0)) {
1193 struct iso_directory_record *pdp;
1194
1195 pdp = (struct iso_directory_record *)
1196 ((char *)bp->b_data + isonum_711(isodir->length));
1197 if ((isonum_711(pdp->flags) & directoryBit)
1198 && (pdp->name[0] == 1))
1199 ip->i_parent = isodirino(pdp, imp);
1200 }
1201 } else
1202 bp = 0;
1203
1204 ip->i_mnt = imp;
1205 ip->i_devvp = imp->im_devvp;
1206 VREF(ip->i_devvp);
1207
1208 if (relocated) {
1209 /*
1210 * On relocated directories we must
1211 * read the `.' entry out of a dir.
1212 */
1213 ip->iso_start = ino >> imp->im_bshift;
1214 if (bp != 0)
1215 brelse(bp);
1216 if ( (error = VOP_BLKATOFF(vp, (off_t)0, NULL, &bp)) ) {
1217 vput(vp);
1218 return (error);
1219 }
1220 isodir = (struct iso_directory_record *)bp->b_data;
1221 }
1222
1223 /*
1224 * go get apple extensions to ISO directory record or use
1225 * defaults when there are no apple extensions.
1226 */
1227 if ( ((isonum_711( isodir->flags ) & directoryBit) == 0) &&
1228 (imp->iso_ftype != ISO_FTYPE_RRIP) ) {
1229 /* This is an ISO directory record for a file */
1230 DRGetTypeCreatorAndFlags(imp, isodir, &ip->i_FileType,
1231 &ip->i_Creator, &ip->i_FinderFlags);
1232
1233 if (isonum_711(isodir->flags) & associatedBit)
1234 ip->i_flag |= ISO_ASSOCIATED;
1235 }
1236
1237 /*
1238 * Shadow the ISO 9660 invisible state to the FinderInfo
1239 */
1240 if (isonum_711(isodir->flags) & existenceBit) {
1241 ip->i_FinderFlags |= fInvisibleBit;
1242 }
1243
1244 ip->iso_extent = isonum_733(isodir->extent);
1245 ip->i_size = isonum_733(isodir->size);
1246 ip->iso_start = isonum_711(isodir->ext_attr_length) + ip->iso_extent;
1247 /*
1248 * account for AppleDouble header
1249 */
1250 if (ip->i_flag & ISO_ASSOCIATED)
1251 ip->i_size += ADH_SIZE;
1252
1253 /*
1254 * if we have a valid name, fill in i_namep with UTF-8 name
1255 */
1256 if (isonum_711(isodir->name_len) != 0) {
1257 u_char *utf8namep;
1258 u_short namelen;
1259 ino_t inump = 0;
1260
1261 MALLOC(utf8namep, u_char *, ISO_RRIP_NAMEMAX + 1, M_TEMP, M_WAITOK);
1262 namelen = isonum_711(isodir->name_len);
1263
1264 switch (imp->iso_ftype) {
1265 case ISO_FTYPE_RRIP:
1266 cd9660_rrip_getname(isodir, utf8namep, &namelen, &inump, imp);
1267 break;
1268
1269 case ISO_FTYPE_JOLIET:
1270 ucsfntrans((u_int16_t *)isodir->name, namelen,
1271 utf8namep, &namelen,
1272 isonum_711(isodir->flags) & directoryBit, ip->i_flag & ISO_ASSOCIATED);
1273 break;
1274
1275 default:
1276 isofntrans (isodir->name, namelen,
1277 utf8namep, &namelen,
1278 imp->iso_ftype == ISO_FTYPE_9660, ip->i_flag & ISO_ASSOCIATED);
1279 }
1280
1281 utf8namep[namelen] = '\0';
1282 MALLOC(ip->i_namep, u_char *, namelen + 1, M_TEMP, M_WAITOK);
1283 bcopy(utf8namep, ip->i_namep, namelen + 1);
1284 FREE(utf8namep, M_TEMP);
1285 }
1286
1287 /*
1288 * Setup time stamp, attribute
1289 */
1290 vp->v_type = VNON;
1291 switch (imp->iso_ftype) {
1292 default: /* ISO_FTYPE_9660 */
1293 {
1294 struct buf *bp2;
1295 int off;
1296 if ((imp->im_flags & ISOFSMNT_EXTATT)
1297 && (off = isonum_711(isodir->ext_attr_length)))
1298 VOP_BLKATOFF(vp, (off_t)-(off << imp->im_bshift), NULL, &bp2);
1299 else
1300 bp2 = NULL;
1301 cd9660_defattr(isodir, ip, bp2);
1302 cd9660_deftstamp(isodir, ip, bp2);
1303 if (bp2)
1304 brelse(bp2);
1305 break;
1306 }
1307 case ISO_FTYPE_RRIP:
1308 cd9660_rrip_analyze(isodir, ip, imp);
1309 break;
1310 }
1311
1312 /*
1313 * See if this is a Video CD file. If so, we must adjust the
1314 * length to account for larger sectors plus the RIFF header.
1315 * We also must substitute the VOP_READ and VOP_PAGEIN functions.
1316 *
1317 * The cd9660_is_video_file routine assumes that the inode has
1318 * been completely set up; it refers to several fields.
1319 *
1320 * This must be done before we release bp, because isodir
1321 * points into bp's data.
1322 */
1323 if (cd9660_is_video_file(ip, imp))
1324 {
1325 cd9660_xa_init(vp, isodir);
1326 }
1327
1328 if (bp != 0)
1329 brelse(bp);
1330
1331 /*
1332 * Initialize the associated vnode
1333 */
1334
1335 if (ip->iso_extent == imp->root_extent) {
1336 vp->v_flag |= VROOT;
1337 ip->i_parent = 1; /* root's parent is always 1 by convention */
1338 /* mode type must be S_IFDIR */
1339 ip->inode.iso_mode = (ip->inode.iso_mode & ~S_IFMT) | S_IFDIR;
1340 }
1341
1342 switch (vp->v_type = IFTOVT(ip->inode.iso_mode)) {
1343 case VFIFO:
1344 #if FIFO
1345 vp->v_op = cd9660_fifoop_p;
1346 break;
1347 #else
1348 vput(vp);
1349 return (EOPNOTSUPP);
1350 #endif /* FIFO */
1351 case VCHR:
1352 case VBLK:
1353 /*
1354 * if device, look at device number table for translation
1355 */
1356 #ifdef ISODEVMAP
1357 if (dp = iso_dmap(dev, ino, 0))
1358 ip->inode.iso_rdev = dp->d_dev;
1359 #endif
1360 vp->v_op = cd9660_specop_p;
1361 if ( (nvp = checkalias(vp, ip->inode.iso_rdev, mp)) ) {
1362 /*
1363 * Discard unneeded vnode, but save its iso_node.
1364 */
1365 cd9660_ihashrem(ip);
1366 VOP_UNLOCK(vp, 0, p);
1367 nvp->v_data = vp->v_data;
1368 vp->v_data = NULL;
1369 vp->v_op = spec_vnodeop_p;
1370 vrele(vp);
1371 vgone(vp);
1372 /*
1373 * Reinitialize aliased inode.
1374 */
1375 vp = nvp;
1376 ip->i_vnode = vp;
1377 cd9660_ihashins(ip);
1378 }
1379 break;
1380 case VREG:
1381 ubc_info_init(vp);
1382 break;
1383 default:
1384 break;
1385 }
1386
1387 /*
1388 * XXX need generation number?
1389 */
1390
1391 *vpp = vp;
1392
1393 return (0);
1394 }
1395
1396
1397 /************************************************************************
1398 *
1399 * Function: DRGetTypeCreatorAndFlags
1400 *
1401 * Purpose: Set up the fileType, fileCreator and fileFlags
1402 *
1403 * Returns: none
1404 *
1405 * Side Effects: sets *theTypePtr, *theCreatorPtr, and *theFlagsPtr
1406 *
1407 * Description:
1408 *
1409 * Revision History:
1410 * 28 Jul 88 BL¡B Added a new extension type of 6, which allows
1411 * the specification of four of the finder flags.
1412 * We let the creator of the disk just copy over
1413 * the finder flags, but we only look at always
1414 * switch launch, system, bundle, and locked bits.
1415 * 15 Aug 88 BL¡B The Apple extensions to ISO 9660 implemented the
1416 * padding field at the end of a directory record
1417 * incorrectly.
1418 * 19 Jul 89 BG Rewrote routine to handle the "new" Apple
1419 * Extensions definition, as well as take into
1420 * account the possibility of "other" definitions.
1421 * 02 Nov 89 BG Corrected the 'AA' SystemUseID processing to
1422 * check for SystemUseID == 2 (HFS). Was incorrectly
1423 * checking for SystemUseID == 1 (ProDOS) before.
1424 * 18 Mar 92 CMP Fixed the check for whether len_fi was odd or even.
1425 * Before it would always assume even for an XA record.
1426 * 26 Dec 97 jwc Swiped from MacOS implementation of ISO 9660 CD-ROM
1427 * support and modified to work in MacOSX file system.
1428 *
1429 *********************************************************************** */
1430
1431 static void
1432 DRGetTypeCreatorAndFlags( struct iso_mnt * theMountPointPtr,
1433 struct iso_directory_record * theDirRecPtr,
1434 u_int32_t * theTypePtr,
1435 u_int32_t * theCreatorPtr,
1436 u_int16_t * theFlagsPtr )
1437 {
1438 int foundStuff;
1439 u_int32_t myType;
1440 u_int32_t myCreator;
1441 AppleExtension *myAppleExtPtr;
1442 NewAppleExtension *myNewAppleExtPtr;
1443 u_int16_t myFinderFlags;
1444 char *myPtr;
1445
1446 foundStuff = 1;
1447 myType = 0x3f3f3f3f;
1448 myCreator = 0x3f3f3f3f;
1449 myFinderFlags = 0;
1450 *theFlagsPtr = 0x0000;
1451
1452 /*
1453 * handle the fact that our original apple extensions didn't take
1454 * into account the padding byte on a file name
1455 */
1456
1457 myPtr = &theDirRecPtr->name[ (isonum_711(theDirRecPtr->name_len)) ];
1458
1459 /* if string length is even, bump myPtr for padding byte */
1460 if ( ((isonum_711(theDirRecPtr->name_len)) & 0x01) == 0 )
1461 myPtr++;
1462 myAppleExtPtr = (AppleExtension *) myPtr;
1463
1464 /*
1465 * checking for whether or not the new 'AA' code is being
1466 * called (and if so, correctly)
1467 */
1468 if ( (isonum_711(theDirRecPtr->length)) <=
1469 ISO_DIRECTORY_RECORD_SIZE + (isonum_711(theDirRecPtr->name_len)) ) {
1470 foundStuff = 0;
1471 goto DoneLooking;
1472 }
1473
1474 foundStuff = 0; /* now we default to *false* until we find a good one */
1475 myPtr = (char *) myAppleExtPtr;
1476
1477 if ( (theMountPointPtr->im_flags2 & IMF2_IS_CDXA) != 0 )
1478 myPtr += 14;/* add in CD-XA fixed record offset (tnx, Phillips) */
1479 myNewAppleExtPtr = (NewAppleExtension *) myPtr;
1480
1481 /*
1482 * Calculate the "real" end of the directory record information.
1483 *
1484 * Note: We always read the first 4 bytes of the System-Use data, so
1485 * adjust myPtr down so we don't read off the end of the directory!
1486 */
1487 myPtr = ((char *) theDirRecPtr) + (isonum_711(theDirRecPtr->length));
1488 myPtr -= sizeof(NewAppleExtension) - 1;
1489 while( (char *) myNewAppleExtPtr < myPtr ) /* end of directory buffer */
1490 {
1491 /*
1492 * If we get here, we can assume that ALL further entries in this
1493 * directory record are of the form:
1494 *
1495 * struct OptionalSystemUse
1496 * {
1497 * byte Signature[2];
1498 * byte OSULength;
1499 * byte systemUseID;
1500 * byte fileType[4]; # only if HFS
1501 * byte fileCreator[4]; # only if HFS
1502 * byte finderFlags[2]; # only if HFS
1503 * };
1504 *
1505 * This means that we can examine the Signature bytes to see
1506 * if they are 'AA' (the NEW Apple extension signature).
1507 * If they are, deal with them. If they aren't,
1508 * the OSULength field will tell us how long this extension
1509 * info is (including the signature and length bytes) and that
1510 * will allow us to walk the OptionalSystemUse records until
1511 * we hit the end of them or run off the end of the
1512 * directory record.
1513 */
1514 u_char *myFromPtr, *myToPtr;
1515 union
1516 {
1517 u_int32_t fourchars;
1518 u_char chars[4];
1519 } myChars;
1520
1521 if ( (myNewAppleExtPtr->signature[0] == 'A') &&
1522 (myNewAppleExtPtr->signature[1] == 'A') ) {
1523 if ( isonum_711(myNewAppleExtPtr->systemUseID) == 2 ) {
1524 /* HFS */
1525 foundStuff = 1; /* we got one! */
1526
1527 myFromPtr = &myNewAppleExtPtr->fileType[0];
1528 myToPtr = &myChars.chars[0];
1529 *myToPtr++ = *myFromPtr++;
1530 *myToPtr++ = *myFromPtr++;
1531 *myToPtr++ = *myFromPtr++;
1532 *myToPtr = *myFromPtr;
1533 myType = myChars.fourchars; /* copy file type to user var */
1534
1535 myFromPtr = &myNewAppleExtPtr->fileCreator[0];
1536 myToPtr = &myChars.chars[0];
1537 *myToPtr++ = *myFromPtr++;
1538 *myToPtr++ = *myFromPtr++;
1539 *myToPtr++ = *myFromPtr++;
1540 *myToPtr = *myFromPtr;
1541 myCreator = myChars.fourchars; /* copy creator to user var */
1542
1543 myFromPtr = &myNewAppleExtPtr->finderFlags[0];
1544 myToPtr = &myChars.chars[2]; /* *flags* is a short */
1545 myChars.fourchars = 0;
1546 *myToPtr++ = *myFromPtr++;
1547 *myToPtr = *myFromPtr;
1548 myFinderFlags = myChars.fourchars;
1549 myFinderFlags &=
1550 ( fAlwaysBit | fSystemBit | fHasBundleBit | fLockedBit );
1551 /* return Finder flags to user var */
1552 *theFlagsPtr = (myFinderFlags | fInitedBit);
1553
1554 break; /* exit the loop */
1555 }
1556 }
1557
1558 /*
1559 * Check to see if we have a reasonable OSULength value.
1560 * ZERO is not an acceptable value. Nor is any value less than 4.
1561 */
1562
1563 if ( (isonum_711(myNewAppleExtPtr->OSULength)) < 4 )
1564 break; /* not acceptable - get out! */
1565
1566 /* otherwise, step past this SystemUse record */
1567 (char *)myNewAppleExtPtr += (isonum_711(myNewAppleExtPtr->OSULength));
1568
1569 } /* end of while loop */
1570
1571 DoneLooking:
1572 if ( foundStuff != 0 ) {
1573 *theTypePtr = myType;
1574 *theCreatorPtr = myCreator;
1575 } else {
1576 *theTypePtr = 0;
1577 *theCreatorPtr = 0;
1578 }
1579
1580 return;
1581
1582 } /* DRGetTypeCreatorAndFlags */
1583
1584
1585 /*
1586 * Vnode pointer to File handle
1587 */
1588 /* ARGSUSED */
1589 int
1590 cd9660_vptofh(vp, fhp)
1591 struct vnode *vp;
1592 struct fid *fhp;
1593 {
1594 register struct iso_node *ip = VTOI(vp);
1595 register struct ifid *ifhp;
1596
1597 ifhp = (struct ifid *)fhp;
1598 ifhp->ifid_len = sizeof(struct ifid);
1599
1600 ifhp->ifid_ino = ip->i_number;
1601 ifhp->ifid_start = ip->iso_start;
1602
1603 #ifdef ISOFS_DBG
1604 printf("vptofh: ino %d, start %ld\n",
1605 ifhp->ifid_ino,ifhp->ifid_start);
1606 #endif
1607 return (0);
1608 }
1609
1610 /*
1611 * Fast-FileSystem only?
1612 */
1613 int
1614 cd9660_sysctl(name, namelen, oldp, oldlenp, newp, newlen, p)
1615 int * name;
1616 u_int namelen;
1617 void* oldp;
1618 size_t * oldlenp;
1619 void * newp;
1620 size_t newlen;
1621 struct proc * p;
1622 {
1623 return (EOPNOTSUPP);
1624 }
1625