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