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