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