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