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